The Templator foramt is a format for generating source code files from a set of structured data. It's relatively flexible making it applicable for a large amount of different input data.
render_template_file( f, values, outfile=None )
Takes a path to a template source file (f), the input data that should be applied to the template
(values) and if specified will write the rendered template to outfile, otherwise to the original
template file itself.
Returns 0 on success and 1 on error. If an error occurs it will be printed to stdout.
render_template( src, values, keep_original=True )
Renders the given template source src with the given values. If keep_original is true the template part of the template file will be returned concatenated with the rendered template.
Returns 0 on success and 1 on error. If an error occurs it will be printed to stdout.
The Templator file consists of two segments, the definition segment, and the body segment. Both are enclosed with two lines only containing /* amd */ respectively.
The syntax is defined in EBNF as:
SPACING := TAB | " "
WHITESPACE := ( NEWLINE | SPACING )+ ;
NAME := -( WHITESPACE | ESCAPE | "${" | "%{" | "?{" | "}" | "." ) + ;
COMMENT := "#", (-NEWLINE)+, NEWLINE ;
ESCAPE = "$$" | "$/" |"$." | "$n" | "$%" ;
SUBTEMP_TAG := "%{", SPACEING*, NAME, ( "with" | "for", SPACING+, NAME )?, SPACING*, "}" ;
BODY_SEGMENT := ( SUBTEMP_TAG | ESCAPE | -"*/" )* ;
IF_TAG := "?{", SPACEING*, "if", SPACING+, "not"?, SPACING+, "first"|"last", ":", ( ESCAPE | (-NEWLINE) + ) ;
VAR_TAG := "${", SPACING*, NAME, SPACING*, "}" ;
TAG := VAR_TAG | IF_TAG | SUBTEMP_TAG ;
SUBTEMPLATE := NAME, NEWLINE, ( TAG | ESCAPE | -NEWLINE, NEWLINE )+, "." ;
DEFINITION_SEGMENT := ( WHITESPACE | SUBTEMPLATE | COMMENT )*, "@BODY" ;
TEMPLATE := "/*", NEWLINE, DEFINITION_SEGMENT, BODY_SEGMENT, "*/", ANYTHING ;*Note that ANYTHING is not greedy, else this the syntax would be broken.
In the defition segment subtemplates are defined. Subtemplates consists of thier name, then their body and a . to terminate them. The body is raw text as-is except for the tags inside.
Tags come in 3 flavours:
-
Variable tag:
${ variable_name }or${}, which replaces itself with the giving variable if present in the current value. If the variable is empty (${}) then the current topvalue is inserted instead of a subvalue of it. -
If tag:
?{ if not last:raw text here}or?{ if first:also raw text}, which if the condition is met, replaces itself with the text directly following the:and trailing the}. Current a condition can be eitherif firstorif last, these can also be negated withif not lastandif not first. Note that any condition with usesfirstorlastis always false if it's note a part of an iterable. -
Subtemplate tag:
%{ foo },%{ foo with var_bar }or%{ foo for var_bar }, which replaces itself with the result of the specified subtemplate being rendered. Passing the values that the subtemplate will be rendered can be done in 3 different ways:%{ subtemp }, which just passes the current value along (on top-level that is always the data structure passed to therender_templatefunction) to the given subtemplate.%{ subtemp with val }, which passesval(which belongs the current value) on to the specified subtemplate.%{ subtemp for vals }, which iterates overlists andtuples calling the specified subtemplate with each element. If the specified iterable value is adict, the subtemplate will be called with a key value structure:{ "key": ..., "value": ... }. If the specified value isn't iterable the program will fail with an error.
After the definition of subtemplates comes the body of the template. The body may contain subtemplate tags which are then resolved. This is done multiple time until the rendered body can't be resolved any further. This enables all kinds of weird recursion, though the recursion limit is a 100.
In order to avoid plain-text source code to clash with the syntax of Templator a set of escape codes are available:
$$ → $
$/ → */
$. → .
$n → \n(newline)
$% → %
These examples are here to demonstrate the semantics of Templator.
/*
# This takes the top-value given, and resovle to the value displayed with
# indentation and a trailing comma and newline, but only if it's not the
# last element in the list.
list_stuff
${}?{ if not last:,$n}
.
@BODY
My list of stuff:
%{list_stuff}
*/
Given [ 1, 2, 3, 4 ] as it's data, it would resolve to:
My list of stuff:
1,
2,
3,
4
/*
# Here, we are going to list some more complex data.
list_developer
${name}:
Job: ${job}
Previous projects: %{list_projects for projects}
?{ if not last:$n}
.
# Here we basically do the same as in #1
list_projects
${}?{ if not last:, }
.
header
${studio}'s is working on their game ${game}.
The devlopment team is:
%{list_developer for developers}
.
@BODY
%{header}
They are hiring QAs though.
*/
Given the following data:
{ "studio": "Lioncloth Intertainment"
, "game": "Mogworld"
, "developers": [ { "name": "Simon Northbridge"
, "job": "Programmer"
, "projects": [ "Interstellar Bum Pirates" ] }
, { "name": "Sasha Caldwell"
, "job": "Lead artist"
, "projects": [ "Skywards", "Call of Duty 39" ] }
, { "name": "Don Sonderland"
, "job": "Lead programmer"
, "projects": [ "Interstellar Bum Pirates"
, "Project 11"
, "Bullet Madness 3"
, "Magizalius" ] } ] }
Resolves to:
Lioncloth Intertainment's is working on their game Mogworld.
The devlopment team is:
Simon Northbridge:
Job: Programmer
Previous projects: Interstellar Bum Pirates
Sasha Caldwell:
Job: Lead artist
Previous projects: Skywards, Call of Duty 39
Don Sonderland:
Job: Lead programmer
Previous projects: Interstellar Bum Pirates, Project 11, Bullet Madness 3, Magizalius
They are hiring QAs though.