Welcome to Lina¶
Lina is a minimal template system for Python, modelled after Google’s CTemplate library. It is designed to provide fast, safe template evaluation to generate code or other text documents.
enum DataTypes {
{{#types:list-separator=,NEWLINE}} {{name}}={{value:hex}}{{/types}}
}
evaluated with:
types = [{'name':'Vector3i', 'value': 0x301}, {'name':'Vector3f', 'value': 0x302}]
will produce:
enum DataTypes {
Vector3i = 0x301,
Vector3f = 0x302
}
Overview¶
The base class in Lina is lina.Template
which must be initialized with the template contents. It can be then evaluated to a string using lina.Template.Render()
and lina.Template.RenderSimple()
.
Lina has two main directives, values and blocks. A value is something which is replaced directly by the provided value, while a block is used to iterate over collections. Both blocks and values can be optionally formatted using a formatter
, which allows for example to turn a string into uppercase inside the template.
Values are escaped using double curly braces:
Hello {{name}}!
Blocks have an additional prefix before the variable, #
for the block start and /
for the block end:
{{#users}}Hello {{name}}!{{/users}}
This requires to pass an array of named objects:
template.Render ({'users':[{'name':'Alice'}, {'name':'Bob'}]})
Element access¶
In some cases, accessing members by names is unnecessary complicated. Lina provides a special syntax to access the current element, using a single dot. Using a self-reference, the template above can be simplified to:
{{#users}}Hello {{.}}!{{/users}}
and rendered with:
template.Render ({'users': ['Alice', 'Bob']})
or even simpler using lina.Template.RenderSimple()
:
template.RenderSimple (users = ['Alice', 'Bob'])
Both self-references as well as values can also access fields of an object. Assuming the User
class has fields name
, age
, the following template will print the user name and age:
{{#users}}Hello {{.name}}, you are {{.age}} years old!{{/users}}
For an object, use {{item.field}}
. The field accessor syntax works for both fields as well as associative containers, that is, for Lina, the following two objects are equivalent:
u = {'name':'Alice'}
and:
class User:
def __init__(self, name):
self.name = name
u = User ('Alice')
It is also possible to directly reference indexed items using [0]
, [1]
, etc. For instance, the following template:
{{#vectors}}X: {{.[0]}}, Y: {{.[1]}}, Z: {{.[2]}}\n{{/vectors}}
rendered with:
template.RenderSimple (vectors = [[0, 1, 2], [3, 4, 5]])
will produce:
X: 0, Y: 1, Z: 2
X: 3, Y: 4, Z: 5
Blocks¶
For blocks, Lina provides additional modifiers to check whether the current block execution is the first, an intermediate or the last one:
{{#block}}{{variable}}{{#block#Separator}},{{/block#Separator}}{{/block}}
#First
will be only expanded for the first iteration, #Separator
will be expanded for every expansion which is neither first nor last and #Last
will be expanded for the last iteration only. If there is only one element, it will considered both first and last item of the sequence.
If a block variable is not found, or the block is None
, the block will be not expanded. It is possible to capture this case using !
blocks, which are only expanded if the variable is not present:
{{!users}}No users :({{/users}}
Rendered with template.Render ()
, this will yield No users :(
. This can be used to emulate conditional statements.
Formatters¶
Lina comes with a few formatters which can be used to modify values or block elements. The value formatters are:
width
,w
: This aligns a value to a specific width. Negative values align to the left. For example:{{name:w=-8}}
usingname='Ton'
will yield `` Ton``.prefix
adds a prefix to a value. For example:{{method:prefix=api_}}
withmethod='Copy'
yieldsapi_Copy
suffix
adds a suffix to a value. For example:{{method:suffix=_internal}}
withmethod='Copy'
yieldsCopy_internal
default
provides a default value in case the provided value isNone
.{{name:default=Unknown}}
withname=None
yieldsUnknown
.upper-case
,uc
converts the provided value to upper case.{{func:upper-case}}
withfunc=Copy
yieldsCOPY
.escape-newlines
escapes embedded newlines.{{s:escape-newlines}}
withs='foo\nbar'
yieldsfoo\\nbar
.escape-string
escapes newlines, tabs, and quotes.{{s:escape-string}}
withs=a "string"
yieldsa \"string\"
.wrap-string
wraps the provided string with quotes.{{s:wrap-string}}
withs=string
yields"string"
. If the value is not a string, it will not be wrapped.cbool
converts booleans totrue
orfalse
.{{enabled:cbool}}
withenabled=True
yieldstrue
. If the value is not a boolean, it will be returned as-is.hex
prints numbers in hexadecimal notation.{{i:hex}}
withi=127
yields0x7F
.
Lina provides the following block formatters:
indent
indents every line with a specified number of tabs.{{#block:indent=2}}{{.}}{{/block}}
withblock=[1,2]
yields\t\t1\t\t2
list-separator
,l-s
separates block repetitions using the provided value.{{#block:l-s=,}}{{.}}{{/block}}
withblock=[1,2]
yields1,2
.NEWLINE
is replaced with a new line, andSPACE
with a space.
Whitespace & special characters¶
Whitespace in Lina is preserved. If you want to explicitly insert whitespace, you can use {{_NEWLINE}}
to get a new line character inserted into the stream, and {{_SPACE}}
to get a blank space. To produce a left brace or right brace, use {{_LEFT_BRACE}}
and {{_RIGHT_BRACE}}
.