Artemus 5 Templating Language Overview
Artemus is a template toolkit. It filters text files, parsing, compiling and executing code surrounded by special marks (leaving the rest untouched) and concatenating everything as output. Its main purpose is to filter HTML files, but it can be used for any scripting need related to text filtering and substitution.
Basic Syntax
The Artemus 5 parser expects its code to be between the <{ and }> markers, passing the rest of its input as is.
This will be output with no modification:
This is a text. It includes no Art5 markup, so it will pass through unmodified.
Artemus 5 tokens must be separated by freely distributed blanks (spaces, tabs or newlines). If a single token is found, it's accepted to be a template to be called. Templates can be found on disk as regular files (where they will be recursively compiled), in memory as builtin operators or functions (that will be discussed later), or as variables defined inside the Art5 program flow.
Direct template file inclusion:
This is a text. If the current directory is in the template search path and a README file exists there, it will be directly included.
README file: <{README}>
Builting functions:
This is another example. The sum of 2 plus 3 is <{add 2 3}>, that will output "The sum of 2 plus 3 is 5".
Assignation and variable usage:
This is another example. The TEST variable is assigned. <{= 'TEST' 'This is a test' }> (Note that the above code do not generate any output). And now it's printed: <{TEST}>
Please take note that, on assignation, the name of the variable to be assigned must be enclosed by quotes, as if it was a string literal.
Any text from a # symbol to the end of the line is assumed to be a comment and is ignored.
<{ # This won't appear in the output and will be ignored }>
A block of code, or a template invocation with arguments, must be enclosed in curly brackets. The <{ and }> markers also work as code block enclosers.
Look how a mul
(multiply) operation must be set in a code stream:
V and A are variables. <{"Voltage: " V "Current: " A "Power: " {mul V A}}>
In a code block, the first argument must always be an opcode, being it a
builtin operator or a template name. But, if a literal is found, the
default opcode ?
(concatenate) is assumed. So, the following example
is exactly the same as the previous one:
<{? "Voltage: " V "Current: " A "Power: " {mul V A}}>
Variables and data types
Assignation to variables can be done by using the =
operator:
<{= 'email' 'angel@triptico.com' # assign }> Artemus author's email is <{email}>.
From that moment on, the email
variable can be used as a template.
Strings
Strings can be specified in two ways: by enclosing them in double quotes, where backslash-prefixed codes are accepted (like \n, as in C or Perl), or by enclosing in single quotes, where they are parsed verbatim.
<{ "This is\na test" # Output is two lines }> <{ 'This is\na test' # Output is one line, \n is printed }>
Translateable strings
A translateable string is one that will be internally translated just
before output. They are like double quoted strings, but prefixed by
the @
symbol.
<{ @"Monday" }>
The special T
operator can be used to define sets of translateable
strings. For example, this code snippets translate weekday names from
english to spanish:
<{T "Monday" "lunes" "Tuesday" "martes" "Wednesday" "miercoles" "Thursday" "jueves" "Friday" "viernes" "Saturday" "sabado" "Sunday" "domingo" }>
So the <{ @"Monday" }> code above will output lunes
.
The art5
command line tool includes an option to generate translate
code files from a set of templates on disk. Any file matching lang_*
will be refreshed to include all translateable strings ready to be
edited. To start with new language file, just create an empty one.
Arrays
Arrays can be defined by using the &
opcode.
<{= 'weekdays' {& "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday" } }>
Arrays can be later used in foreach
loops and such. Each element of an
array can be a scalar (as in the example) or another array itself. These
structures can be as complicated as desired.
Arguments
Any included template can be called with arguments. For example:
<{ link 'http://triptico.com/software/artemus.html' 'Artemus Home Page' }>
The link
template will access its arguments as numbers prefixed by the $
sign, as in the example:
<{ # generate an link '<a href = "' $0 '">' $1 '</a>' }>
External hash elements
When Artemus 5 is used as a library inside an application, an external hash
can be provided at startup. The values for this hash can be accessed by
prefixing them with the %
sign. For example, in the Gruta Content
Management System, the external hash is filled with the CGI arguments.
The topic is <{%topic}>.
In the art5
command line tool, though, the external hash only has a
key/value pair, arch
, containing the system architecture (most probably
the "Unix" string).
The current architecture on this system is <{%arch}>.
Conditional and looping constructs
if
The if
opcode can be used for conditional output. It has two mandatory
arguments, the condition and the output if true:
<{if accepted "Operation was accepted" # accepted should return 1 or 0 }>
It also accepts an optional third argument, to be output if the condition is false:
Operation <{if accepted "was accepted" "was NOT accepted"}>.
As discussed above, if any of the three code blocks contain more than one opcode or one with arguments, they must be enclosed by curly brackets:
Error msg: <{if {eq msg "OK"} "All OK" "Something bad happened"}>
<{if {eq %user "anonymous"} "No user logged" {"User " %user " logged in"} }>
foreach
The foreach
opcode can be used for looping through arrays. It accepts
up to 4 arguments, being mandatory just the first one, the array:
Concatenates the full array without separation <{foreach weekdays}>
The second argument is a code block that will be called on each iteration
with the arguments filled with each element of the array. For arrays
with scalar elements, only the first ($0
) element is filled.
Prints each array element with a heading in its own line <{foreach weekdays {"Week day: " $0 "\n"}}>
If an element of the array is itself an array, arguments from $0
up to $9
will be filled with the elements of the array.
<{= 'dataset' {& {& 'a' 1} {& 'b' 2} {& 'c' 3}}}> <{foreach dataset { "Value for element " $0 " is " $1 "\n" }}>
The array can be defined inline:
The multiplying table of 2 <{foreach {& 1 2 3 4 5 6 7 8 9 10} { $0 " by 2 is " {mul $0 2}}}>
Though, for loops like this, the seq
opcode is more useful, as it
generates a sequence of numbers:
<{foreach {seq 1 10} { $0 " by 2 is " {mul $0 2}}}>
The third argument to foreach
is a separator, that will be emitted as
output between each call to the main code block:
<{foreach {seq 1 10} $0 ", " }>
And the fourth one is a header; it will be emitted everytime the output generated by it is different that the previous one. This can be useful to generate subheaders everytime a field changes:
Output will be: a 1 2 b 3 <{foreach {& {& 'a' 1} {& 'a' 2} {& 'b' 3}} { " " $1 "\n" } "" { $0 "\n" } }>
It can also be used to generate a header only if the array is not empty:
Output will be: Dataset 1 2 3 4 <{foreach {& 1 2 3 4} $0 "\n" "Dataset\n" }>
Output will be nothing <{foreach {&} $0 "\n" "Dataset\n" }>
case
The case
opcode can be used as a multiple choice code generator. The
first argument is the value to be compared, followed by pairs of
value-output code block.
<{case %arch "Unix" { "Some Unix system (Linux, etc)" } "win32" { "Some version of MS Windows" } }>
The first argument is compared sequentially until one is found, and then the associated code block is emitted. If none is found, nothing is output.
If the number of arguments is odd, the last one is not compared, but
accepted as the otherwise
clause and used as output in case no value
is found.
<{case %arch "Unix" { "Some Unix system (Linux, etc)" } "win32" { "Some version of MS Windows" } { "Some other strange architecture I didn't envisioned" } }>
Builtin operators and functions
String comparisons
The eq
and ne
operators can be used to test for equality or inequality
of text strings.
Numerical comparisons
The gt
and lt
operators can be used to test greater-than and lower-than
numerical comparisons.
Boolean operators
The and
, or
and not
can be used as boolean operators. Both and
and
or
do not return some true or false values, but the value tested itself,
so they can be used as simple conditionals. For example:
Stores in the user variable the content of %user or, if it's empty, the "anonymous" string <{= user {or %user "anonymous"}}>
Array manipulation
Array definitions and the seq
operator has been seen above; other array
manipulation opcodes are reverse
, that does the obvious or size
, that
returns the number of elements in the array.
The split
opcode can be used to split an array by using a separator:
<{foreach {split "," "1,2,3,4,5"} {$0 "\n"}}>
The sort
opcode can be used to sort an array. The 1 argument version
is straightforward:
Print in proper order: <{foreach {sort {& 3 4 2 5 6 4 3 2 4 5 6 4}} $0 ', ' }>
If a second argument is used, it's assumed to be a code block to be executed on each pair of arguments as a sort order criteria:
<{foreach {sort {& 3 4 2 5 6 4 3 2 4 5 6 4} {sub 1000 $0}} $0 ', ' }>
Math operators
The add
, sub
, mul
and div
exist as their corresponding math
operators.
Miscellaneous
The env
opcode returns the value of an environment variable; if no
argument is given, the full set of existing environment variables will
be returned as an array.
The random
opcode accepts an arbitrary number of arguments and returns
one of them, at random.
Angel Ortega <angel@triptico.com>