Templates are simple hierarchical pieces of text used for efficient stream writing.

Efficient stream writing

Templates are more efficient than ever-growing buffers with useless concatenation and more usable and maintainable than manual arrays of strings.

The add method (and its variations) is used to append new content (like string or other templates) to a template object.

Eventually, the write_to method (and its variations) is used to write the complete content of a template in streams (and files, and strings).

var tmpl = new Template
tmpl.add("A")
tmpl.add("B")
tmpl.add("C")
assert tmpl.write_to_string == "ABC"

Non-linear system with sub-templates.

A template is made of a mix of string, sub-templates and other Writable objects. A sub-template can be constructed independently of its usages, thus simplifying the high-level logic. A single sub-template can be used more than once.

var main = new Template
var sub = new Template
sub.add("1")
main.add("A")
main.add(sub)
main.add("B")
main.add(sub)
main.add("C")
sub.add("2")
assert main.write_to_string == "A12B12C"

See also the new_sub method.

Specific high-level templates

The advanced, and recommended way, is to subclass Template and provide an autonomous structural template with its specific attributes and templating logic.

In such a subclass, the full logic is provided by the rendering method that will be automatically and lazily invoked.

class LnkTmpl
    super Template
    var text: Writable
    var title: nullable String
    var href: String
    redef fun rendering do
        add """<a href="{{{href.html_escape}}}""""
        if title != null then add """ title="{{{title.html_escape}}}""""
        add ">"
        add text
        add "</a>"
    end
    # ...
end
var l = new LnkTmpl("hello world", null, "hello.png")
assert l.write_to_string == """<a href="hello.png">hello world</a>"""

Introduced properties

fun add(element: Writable)

template :: Template :: add

Append an element (String, other Template, etc.) at the end of the template.
fun add_all(elements: Collection[Writable])

template :: Template :: add_all

Append a bunch of elements at the end of the template.
fun add_list(elements: Collection[Writable], sep: Writable, last_sep: Writable)

template :: Template :: add_list

Append a bunch of elements at the end of the template with separations.
fun addn(element: Writable)

template :: Template :: addn

Append element and the end of the template then append a "\n".
fun force_render

template :: Template :: force_render

Call rendering, if not already done
fun freeze

template :: Template :: freeze

Disable further modification: no more add is allowed
fun is_frozen: Bool

template :: Template :: is_frozen

Is the template allowing more modification (add)
protected fun is_frozen=(is_frozen: Bool)

template :: Template :: is_frozen=

Is the template allowing more modification (add)
fun new_sub: Template

template :: Template :: new_sub

Return a new basic template that is automatically added in self (using add)
protected fun rendering

template :: Template :: rendering

Service used to render the content of the template.

Redefined properties

redef type SELF: Template

template $ Template :: SELF

Type of this instance, automatically specialized in every class
redef fun write_to(stream: Writer)

template $ Template :: write_to

Do the full rendering and write the final content to a stream

All properties

fun !=(other: nullable Object): Bool

core :: Object :: !=

Have self and other different values?
fun ==(other: nullable Object): Bool

core :: Object :: ==

Have self and other the same value?
type CLASS: Class[SELF]

core :: Object :: CLASS

The type of the class of self.
type SELF: Object

core :: Object :: SELF

Type of this instance, automatically specialized in every class
fun add(element: Writable)

template :: Template :: add

Append an element (String, other Template, etc.) at the end of the template.
fun add_all(elements: Collection[Writable])

template :: Template :: add_all

Append a bunch of elements at the end of the template.
fun add_list(elements: Collection[Writable], sep: Writable, last_sep: Writable)

template :: Template :: add_list

Append a bunch of elements at the end of the template with separations.
fun addn(element: Writable)

template :: Template :: addn

Append element and the end of the template then append a "\n".
protected fun class_factory(name: String): CLASS

core :: Object :: class_factory

Implementation used by get_class to create the specific class.
fun class_name: String

core :: Object :: class_name

The class name of the object.
fun force_render

template :: Template :: force_render

Call rendering, if not already done
fun freeze

template :: Template :: freeze

Disable further modification: no more add is allowed
fun get_class: CLASS

core :: Object :: get_class

The meta-object representing the dynamic type of self.
fun hash: Int

core :: Object :: hash

The hash code of the object.
init init

core :: Object :: init

fun inspect: String

core :: Object :: inspect

Developer readable representation of self.
protected fun inspect_head: String

core :: Object :: inspect_head

Return "CLASSNAME:#OBJECTID".
fun is_frozen: Bool

template :: Template :: is_frozen

Is the template allowing more modification (add)
protected fun is_frozen=(is_frozen: Bool)

template :: Template :: is_frozen=

Is the template allowing more modification (add)
intern fun is_same_instance(other: nullable Object): Bool

core :: Object :: is_same_instance

Return true if self and other are the same instance (i.e. same identity).
fun is_same_serialized(other: nullable Object): Bool

core :: Object :: is_same_serialized

Is self the same as other in a serialization context?
intern fun is_same_type(other: Object): Bool

core :: Object :: is_same_type

Return true if self and other have the same dynamic type.
fun new_sub: Template

template :: Template :: new_sub

Return a new basic template that is automatically added in self (using add)
intern fun object_id: Int

core :: Object :: object_id

An internal hash code for the object based on its identity.
fun output

core :: Object :: output

Display self on stdout (debug only).
intern fun output_class_name

core :: Object :: output_class_name

Display class name on stdout (debug only).
protected fun rendering

template :: Template :: rendering

Service used to render the content of the template.
fun serialization_hash: Int

core :: Object :: serialization_hash

Hash value use for serialization
intern fun sys: Sys

core :: Object :: sys

Return the global sys object, the only instance of the Sys class.
abstract fun to_jvalue(env: JniEnv): JValue

core :: Object :: to_jvalue

fun to_s: String

core :: Object :: to_s

User readable representation of self.
abstract fun write_to(stream: Writer)

core :: Writable :: write_to

Write itself to a stream
fun write_to_bytes: Bytes

core :: Writable :: write_to_bytes

Like write_to but return a new Bytes (may be quite large)
fun write_to_file(filepath: String)

core :: Writable :: write_to_file

Like write_to but take care of creating the file
fun write_to_string: String

core :: Writable :: write_to_string

Like write_to but return a new String (may be quite large).
package_diagram template::Template Template core::Writable Writable template::Template->core::Writable core::Object Object core::Writable->core::Object ...core::Object ... ...core::Object->core::Object gen_nit::NitModule NitModule gen_nit::NitModule->template::Template nitcorn::ErrorTemplate ErrorTemplate nitcorn::ErrorTemplate->template::Template html::BSComponent BSComponent html::BSComponent->template::Template template::TemplateString TemplateString template::TemplateString->template::Template popcorn::ErrorTpl ErrorTpl popcorn::ErrorTpl->template::Template popcorn::HtmlErrorTemplate HtmlErrorTemplate popcorn::HtmlErrorTemplate->template::Template template::TmplComposers TmplComposers template::TmplComposers->template::Template template::TmplComposer TmplComposer template::TmplComposer->template::Template template::TmplComposerDetail TmplComposerDetail template::TmplComposerDetail->template::Template html::Link Link html::Link->html::BSComponent html::Header Header html::Header->html::BSComponent html::HTMLList HTMLList html::HTMLList->html::BSComponent html::ListItem ListItem html::ListItem->html::BSComponent html::BSIcon BSIcon html::BSIcon->html::BSComponent html::BSLabel BSLabel html::BSLabel->html::BSComponent html::BSBadge BSBadge html::BSBadge->html::BSComponent html::BSPageHeader BSPageHeader html::BSPageHeader->html::BSComponent html::BSAlert BSAlert html::BSAlert->html::BSComponent html::BSPanel BSPanel html::BSPanel->html::BSComponent html::Link... ... html::Link...->html::Link html::Header... ... html::Header...->html::Header html::HTMLList... ... html::HTMLList...->html::HTMLList html::ListItem... ... html::ListItem...->html::ListItem html::BSIcon... ... html::BSIcon...->html::BSIcon html::BSLabel... ... html::BSLabel...->html::BSLabel html::BSBadge... ... html::BSBadge...->html::BSBadge html::BSPageHeader... ... html::BSPageHeader...->html::BSPageHeader html::BSAlert... ... html::BSAlert...->html::BSAlert html::BSPanel... ... html::BSPanel...->html::BSPanel

Ancestors

interface Object

core :: Object

The root of the class hierarchy.

Parents

interface Writable

core :: Writable

Things that can be efficienlty written to a Writer

Children

abstract class BSComponent

html :: BSComponent

Bootstrap component abstraction.
class ErrorTemplate

nitcorn :: ErrorTemplate

A basic error page for the HTTP error code
class NitModule

gen_nit :: NitModule

Template of a Nit module to generate Nit code
class TemplateString

template :: TemplateString

Template with macros replacement.
class TmplComposer

template :: TmplComposer

A composer in the short list of composers
class TmplComposerDetail

template :: TmplComposerDetail

A composer in the detailled list of composers
class TmplComposers

template :: TmplComposers

The root template for composers

Descendants

class BSAlert

html :: BSAlert

A Bootstrap alert component.
class BSBadge

html :: BSBadge

A Bootstrap badge component.
class BSBreadCrumbs

html :: BSBreadCrumbs

A Bootstrap breadcrumbs component.
class BSIcon

html :: BSIcon

A Boostrap icon.
class BSLabel

html :: BSLabel

A Bootstrap label component.
class BSPageHeader

html :: BSPageHeader

A Bootstrap page header component.
class BSPanel

html :: BSPanel

A Bootstrap panel component.
abstract class HTMLList

html :: HTMLList

An abstract HTML list.
class Header

html :: Header

A <h1> to <h6> tag.
class ListItem

html :: ListItem

A <li> tag.
class OrderedList

html :: OrderedList

A <ol> list tag.
class UnorderedList

html :: UnorderedList

A <ul> list tag.

Class definitions

template $ Template
# Templates are simple hierarchical pieces of text used for efficient stream writing.
#
# # Efficient stream writing
#
# Templates are more efficient than ever-growing buffers with useless concatenation
# and more usable and maintainable than manual arrays of strings.
#
# The `add` method (and its variations) is used to append new content (like string or
# other templates) to a template object.
#
# Eventually, the `write_to` method (and its variations) is used to write the complete
# content of a template in streams (and files, and strings).
#
#     var tmpl = new Template
#     tmpl.add("A")
#     tmpl.add("B")
#     tmpl.add("C")
#     assert tmpl.write_to_string == "ABC"
#
# # Non-linear system with sub-templates.
#
# A template is made of a mix of string, sub-templates and other `Writable` objects.
# A sub-template can be constructed independently of its usages, thus simplifying
# the high-level logic.
# A single sub-template can be used more than once.
#
#     var main = new Template
#     var sub = new Template
#     sub.add("1")
#     main.add("A")
#     main.add(sub)
#     main.add("B")
#     main.add(sub)
#     main.add("C")
#     sub.add("2")
#     assert main.write_to_string == "A12B12C"
#
# See also the `new_sub` method.
#
# # Specific high-level templates
#
# The advanced, and recommended way, is to subclass Template and provide an autonomous
# structural template with its specific attributes and templating logic.
#
# In such a subclass, the full logic is provided by the `rendering` method that will
# be automatically and lazily invoked.
#
#     class LnkTmpl
#         super Template
#         var text: Writable
#         var title: nullable String
#         var href: String
#         redef fun rendering do
#             add """<a href="{{{href.html_escape}}}""""
#             if title != null then add """ title="{{{title.html_escape}}}""""
#             add ">"
#             add text
#             add "</a>"
#         end
#         # ...
#     end
#     var l = new LnkTmpl("hello world", null, "hello.png")
#     assert l.write_to_string == """<a href="hello.png">hello world</a>"""
#
class Template
	super Writable

	# Service used to render the content of the template.
	#
	# Do nothing by default but subclasses should put all their specific
	# templating code in this method to regroup and simplify their logic
	#
	# Note: to avoid inconsistencies, the template is automatically frozen
	# (see `freeze`) after the invocation of `rendering`.
	protected fun rendering do end

	# Append an element (`String`, other `Template`, etc.) at the end of the template.
	#
	# Should be either used externally to act on basic templates,
	# or internally in the `rendering` method of specific templates.
	#
	# Mixing the internal and external uses should be avoided because
	# the final behavior will depend on the lazy invocation of `rendering`.
	#
	#     var t = new Template
	#     t.add("1")
	#     t.add("2")
	#     assert t.write_to_string == "12"
	fun add(element: Writable) do
		assert not is_frozen
		content.add element
	end

	# Append `element` and the end of the template then append a "\n".
	#
	#     var t = new Template
	#     t.addn("1")
	#     t.addn("2")
	#     assert t.write_to_string == "1\n2\n"
	fun addn(element: Writable) do
		add element
		add "\n"
	end

	# Append a bunch of elements at the end of the template.
	# See `add`.
	#
	#     var t = new Template
	#     t.add_all(["1", "2"])
	#     assert t.write_to_string == "12"
	fun add_all(elements: Collection[Writable]) do content.add_all elements

	# Append a bunch of elements at the end of the template with separations.
	# see `add`.
	#
	#     var t = new Template
	#     t.add_list(["1", "2", "3"], ", ", " and ")
	#     assert t.write_to_string == "1, 2 and 3"
	fun add_list(elements: Collection[Writable], sep, last_sep: Writable) do
		var last = elements.length - 2
		var i = 0
		for e in elements do
			content.add e
			if i < last then
				content.add sep
			else if i == last then
				content.add last_sep
			end
			i += 1
		end
	end

	# Is the template allowing more modification (`add`)
	var is_frozen = false

	# Disable further modification: no more `add` is allowed
	fun freeze
	do
		if is_frozen then return
		is_frozen = true
	end

	# Return a new basic template that is automatically added in `self` (using `add`)
	#
	# This is an easy way to provide a free insertion point in an existing template.
	#
	#     var t = new Template
	#     t.add("""void main(void) {""")
	#     var tdecl = t.new_sub # used to group declarations
	#     tdecl.add("int i; ")
	#     t.add("i = 1; ")
	#     tdecl.add("int j; ")
	#     t.add("j = i + 1; ")
	#     t.add("\}")
	#     assert t.write_to_string == """void main(void) {int i; int j; i = 1; j = i + 1; }"""
	fun new_sub: Template
	do
		var res = new Template
		add res
		return res
	end

	# Each sub-elements
	private var content = new Array[Writable]

	# Flag to avoid multiple rendering
	private var render_done = false

	# Call rendering, if not already done
	# Then freeze the template
	#
	# This method is only required in corner-cases since
	# `rendering` is automatically called when needed.
	fun force_render
	do
		if render_done then return
		render_done = true
		rendering
		freeze
	end

	# Do the full rendering and write the final content to a stream
	redef fun write_to(stream)
	do
		assert not is_writing
		is_writing = true
		force_render
		for e in content do
			e.write_to(stream)
		end
		is_writing = false
	end

	# Flag to avoid infinite recursivity if a template contains itself
	private var is_writing = false
end
lib/template/template.nit:21,1--216,3