Note: This page is based on Go's text/template, adapted to suit the Ra environment.
Templates are executed by applying them to a tuple. Annotations in the template refer to attributes of the tuple to control execution and derive values to be displayed. Execution of the template walks the tuple and sets the cursor, represented by a period '.' and called "dot", to the value at the current location in the tuple as execution proceeds.
Ra assumes that template authors are trusted. It does not auto-escape output, so injecting code into a template can lead to arbitrary code execution if the template is executed by an untrusted source.
"Actions" - data evaluations or control structures - are delimited by « and »; all text outside actions is copied to the output unchanged.
Here is a trivial example that prints "17 items are made of wool".
import("http")
template_register("b1", dee(
template_name:="eg1",
template_content:="«.Count» items are made of «.Material»"
))
print(template_execute("b1", "eg1", tuple{Count:=17, Material:="wool"}))
More intricate examples appear below.
Text and spaces
By default, all text between actions is copied verbatim when the template is executed. For example, the string " items are made of " in the example above appears on standard output when the program is run.
However, to aid in formatting template source code, if an action's left delimiter («) is followed immediately by a minus sign and white space, all trailing white space is trimmed from the immediately preceding text. Similarly, if the right delimiter (») is preceded by white space and a minus sign, all leading white space is trimmed from the immediately following text. In these trim markers, the white space must be present: "«- 3»" is like "«3»" but trims the immediately preceding text, while "«-3»" parses as an action containing the number -3.
For instance, when executing the template whose source is
"«23 -» < «- 45»"
the generated output would be
"23<45"
For this trimming, the definition of white space characters is space, horizontal tab, carriage return, and newline.
Actions
Here is the list of actions. "Arguments" and "pipelines" are evaluations of data, defined in detail in the corresponding sections that follow.
«/* a comment */»
«- /* a comment with white space trimmed from preceding and following text */ -»
A comment; discarded. May contain newlines.
Comments do not nest and must start and end at the
delimiters, as shown here.
«pipeline»
The default textual representation (the same as would be
printed by print) of the value of the pipeline is copied
to the output.
«if pipeline» T1 «end»
If the value of the pipeline is empty, no output is generated;
otherwise, T1 is executed. The empty values are false, 0, and any
string of length zero.
Dot is unaffected.
«if pipeline» T1 «else» T0 «end»
If the value of the pipeline is empty, T0 is executed;
otherwise, T1 is executed. Dot is unaffected.
«if pipeline» T1 «else if pipeline» T0 «end»
To simplify the appearance of if-else chains, the else action
of an if may include another if directly; the effect is exactly
the same as writing
«if pipeline» T1 «else»«if pipeline» T0 «end»«end»
«range pipeline» T1 «end»
The value of the pipeline must be a table/array, set or integer.
If the value of the pipeline has length zero, nothing is output;
otherwise, dot is set to the successive elements of the table
and T1 is executed.
«range pipeline» T1 «else» T0 «end»
The value of the pipeline must be a table/array, set or integer.
If the value of the pipeline has length zero, dot is unaffected and
T0 is executed; otherwise, dot is set to the successive elements
of the table and T1 is executed.
«break»
The innermost «range pipeline» loop is ended early, stopping the
current iteration and bypassing all remaining iterations.
«continue»
The current iteration of the innermost «range pipeline» loop is
stopped, and the loop starts the next iteration.
«template "name"»
The template with the specified name is executed with nil data.
«template "name" pipeline»
The template with the specified name is executed with dot set
to the value of the pipeline.
«block "name" pipeline» T1 «end»
A block is shorthand for defining a template
«define "name"» T1 «end»
and then executing it in place
«template "name" pipeline»
The typical use is to define a set of root templates that are
then customised by redefining the block templates within.
«with pipeline» T1 «end»
If the value of the pipeline is empty, no output is generated;
otherwise, dot is set to the value of the pipeline and T1 is
executed.
«with pipeline» T1 «else» T0 «end»
If the value of the pipeline is empty, dot is unaffected and T0
is executed; otherwise, dot is set to the value of the pipeline
and T1 is executed.
«with pipeline» T1 «else with pipeline» T0 «end»
To simplify the appearance of with-else chains, the else action
of a with may include another with directly; the effect is exactly
the same as writing
«with pipeline» T1 «else»«with pipeline» T0 «end»«end»
Arguments
An argument is a simple value, denoted by one of the following.
- A bool, string, int or float constant in Ra syntax.
-
The character '.' (period):
.The result is the value of dot. -
A template variable name, which is a (possibly empty) alphanumeric string preceded by a dollar sign, such as
$piOver2or$The result is the value of the template variable. Template variables are distinct from Ra variables and are described below. -
The name of an attribute of the data, if it is a tuple, preceded by a period, such as
.AttrThe result is the value of the attribute. Attribute invocations may be chained:.Attr1.Attr2Attributes can also be evaluated on variables, including chaining:$x.Attr1.Attr2 -
.Heada set of heading attributes for a table (i.e. a tuple array), each having a.Name -
.Tuplesan array of tuples for a table (i.e. a tuple array) -
The name of a niladic function, such as
funThe result is the value of invoking the function,fun(). Functions and function names are described below. -
A parenthesised instance of one the above, for grouping actions. The result may be accessed by an attribute invocation.
print(.F1 arg1) (.F2 arg2).Attr
Arguments may evaluate to any type. If an evaluation yields a function value, the function is not invoked automatically, but it can be used as a truth value for an if action and the like. To invoke it, use the call function, defined below.
Pipelines
A pipeline is a possibly chained sequence of "commands". A command is a simple value (argument) or a function call, possibly with multiple arguments:
Argument
The result is the value of evaluating the argument.
functionName [Argument...]
The result is the value of calling the function associated
with the name:
function(Argument1, etc.)
Functions and function names are described below.
A pipeline may be "chained" by separating a sequence of commands with pipeline characters '|'. In a chained pipeline, the result of each command is passed as the last argument of the following command. The output of the final command in the pipeline is the value of the pipeline.
The output of a command will be either one value or two values, the second of which has type error. If that second value is present and evaluates to non-nil, execution terminates and the error is returned to the caller of template_execute.
Variables
A pipeline inside an action may initialise a template variable to capture the result. The initialisation has syntax
$variable := pipeline
where $variable is the name of the template variable. An action that declares a variable produces no output.
Variables previously declared can also be assigned, using the syntax
$variable = pipeline
If a "range" action initializes a variable, the variable is set to the successive elements of the iteration. Also, a "range" may declare two variables, separated by a comma:
range $index, $element := pipeline
in which case $index and $element are set to the successive values of the index and element, respectively. Note that if there is only one variable, it is assigned the element.
A template variable's scope extends to the "end" action of the control structure ("if", "with", or "range") in which it is declared, or to the end of the template if there is no such control structure. A template invocation does not inherit template variables from the point of its invocation.
When execution begins, $ is set to the tuple argument passed to template_execute, that is, to the starting value of dot.
Examples
Here are some example one-line templates demonstrating pipelines and variables. All produce the quoted word "output":
«"output"»
A string constant.
«print "output"»
A function call.
«"output" | print »
A function call whose final argument comes from the previous
command.
«print (print "out" "put")»
A parenthesised argument.
«"put" | print "out" | print »
A more elaborate call.
«"output" | print | print »
A longer chain.
«with "output"»«print .»«end»
A with action using dot.
«with $x := "output" | print »«$x»«end»
A with action that creates and uses a template variable.
«with $x := "output"»«print $x»«end»
A with action that uses the template variable in another action.
«with $x := "output"»«$x | print »«end»
The same, but pipelined.
Functions
During execution functions are found in two function maps: first in the template, then in the global function map. By default, no functions are defined in the template but the Funcs method can be used to add them.
Predefined global functions are named as follows.
and
Returns the boolean AND of its arguments by returning the
first empty argument or the last argument. That is,
"and x y" behaves as "if x then y else x."
Evaluation proceeds through the arguments left to right
and returns when the result is determined.
call
Returns the result of calling the first argument, which
must be a function, with the remaining arguments as parameters.
Thus "call X 1 2" is, in Ra notation, X(1, 2).
The first argument must be a function. The function must
return either one or two result values, the second of which
is of type error. If the arguments don't match the function
or the returned error value is non-nil, execution stops.
index
Returns the result of indexing its first argument by the
following arguments. Thus "index x 3" is, in Ra syntax,
x[3] for tables, and "index t attr1" is, in Ra syntax,
t.attr1. Each indexed item must be a table or a tuple.
js
Returns the escaped JavaScript equivalent of the textual
representation of its arguments.
len
Returns the integer length of its argument.
not
Returns the boolean negation of its single argument.
or
Returns the boolean OR of its arguments by returning the
first non-empty argument or the last argument, that is,
"or x y" behaves as "if x then x else y".
Evaluation proceeds through the arguments left to right
and returns when the result is determined.
print
Ra print
The boolean functions take any zero value to be false and a non-zero value to be true.
There is also a set of binary comparison operators defined as functions:
eq
Returns the boolean truth of arg1 = arg2
ne
Returns the boolean truth of arg1 != arg2
lt
Returns the boolean truth of arg1 < arg2
le
Returns the boolean truth of arg1 <= arg2
gt
Returns the boolean truth of arg1 > arg2
ge
Returns the boolean truth of arg1 >= arg2
For simpler multi-way equality tests, eq (only) accepts two or more arguments and compares the second and subsequent to the first, returning in effect
arg1=arg2 or arg1=arg3 or arg1=arg4 ...
(Unlike with or in Ra, however, eq is a function call and all the arguments will be evaluated.)
The comparison functions work on comparable values so, as usual, one may not compare an int with a float and so on.
Associated templates
Each template is named by a string specified when it is created. Also, each template is associated with zero or more other templates that it may invoke by name; such associations are transitive and form a name space of templates.
A template may use a template invocation to instantiate another associated template; see the explanation of the "template" action above. The name must be that of a template associated with the template that contains the invocation.
Nested template definitions
When parsing a template, another template may be defined and associated with the template being parsed. Template definitions must appear at the top level of the template, much like global variables in a Ra program.
The syntax of such definitions is to surround each template declaration with a "define" and "end" action.
The define action names the template being created by providing a string constant. Here is a simple example:
«define "T1"»ONE«end»
«define "T2"»TWO«end»
«define "T3"»«template "T1"» «template "T2"»«end»
«template "T3"»
This defines two templates, T1 and T2, and a third T3 that invokes the other two when it is executed. Finally it invokes T3. If executed this template will produce the text
ONE TWO
By construction, a template may reside in only one group. If it's necessary to have a template addressable from multiple groups, the template definition must be registered multiple times to create distinct fragment values.
Register may be called multiple times to assemble the various associated templates; see template_register.
A template may be executed through template_execute, which executes an associated template identified by name. To invoke a particular template explicitly by name,
template_execute("g1", "T2", tuple{}) // no data needed
Portions of this page are modifications based on Go's text/template created and shared by Google and used according to terms described in the Creative Commons Attribution 4.0 License.