LtdTemplate Manual
Version 0.1.0; July 12, 2013
Author(s)
- Brian Katzung <[email protected]>, Kappa Computer Solutions, LLC (original author)
Contents
Introduction
LtdTemplate is a Ruby Gem implementing resource-limitable templating. With proper configuration, it can be used to allow sophisticated users to edit their own templates, e.g. for message localization, with limited risk of infinite execution loops or other uncontrolled resource utilization.
This document describes the template syntax. See the Gem documentation for information about the programming interface.
[Contents]
Template Syntax
A template consists of inter-mixed sections of literal text and
template code. The shortest sequences between "<<
"
and ">>
" that don't contain "<<
"
or ">>
" are template code; the rest is literal
text. Given a sequence of the form:
A<<B<<C>>D<<E>>F>>G<<<H>>>I
template code cannot begin at "<<B" because it is not allowed
to contain "<<
" or ">>
", so the
first template code is "<<C>>
", the second is
"<<E>>
", and the last is
"<<H>>
". Everything else ("A<<B
",
"D
", "F>>G<
", and ">I
")
is treated as literal text.
If template code begins with "<<.
" (with a period
immediately after the second "<
"), it strips any trailing
white space from immediately preceding literal text. Likewise, if template
code ends with ".>>
", it strips any leading white space
from immediately following literal text. Template code consisting of
only "<<.>>
" is considered to meet both
conditions and is equivalent to "<<..>>
".
There need not be any literal text before, after, or between template
code sequences. Template code sequences between delimiters may also be empty
(<<>>
).
Unless otherwise stated, the remainder of this document will refer to
template code as the code between the "<<
"
(or "<<.
") and ">>
" (or
".>>
") without reference to the delimiters
themselves.
[Contents]
Template Code Syntax
- Comments
- String Literals
- Numeric Literals
- Variables
- Method Calls
- Assignments
- Pre-Defined Variables
- Code Sequences
- Code Blocks
- Subscripts And Code-Block Bindings
Comments
Comments begin with "/*
" and end at the nearest
"*/
".
/* this is a comment */
/* and so is /* this */
[Contents] [Template Code Syntax]
String Literals
String literals are used to generate string values. LtdTemplate supports two forms: "short" and "regular".
Short string literals begin with a single quote ('
) and
terminate before a period (.
), comma (,
), opening
or closing brackets, parentheses, or braces ([](){}
), or white
space. However, any normally terminating character may be included by
preceding it with a backslash (\
).
Regular string literals begin with a double quote ("
) and
terminate at the next double quote. A double quote may be included by
preceding it with a backslash.
String literals may also contain other "escape sequences" like those in Ruby double-quoted strings. Here is the full list:
Sequence | Meaning |
---|---|
\M-\C-x | meta-control-x |
\M-x | meta-x |
\C-x, \Cx | control-x |
\udddd | Unicode four-digit, 16-bit hexadecimal code point dddd |
\xdd | two-digit, 8-bit hexadecimal dd |
\ddd | one, two, or three-digit, 8-bit octal ddd |
\a | alert (ASCII BEL) |
\b | backspace (ASCII BS) |
\e | escape (ASCII ESC) |
\f | formfeed (ASCII FF) |
\n | new-line/line-feed (ASCII LF) |
\r | carriage return (ASCII ESC) |
\s | space (ASCII SP) |
\t | horizontal tab (ASCII HT) |
\v | vertical tab (ASCII VT) |
\c | any other character c is just itself |
Examples, with some comments added for annotation:
' /* empty */ 'short '<\< '>\>
/* escaped code delimiters */ "\"regular\" string"
[Contents] [Template Code Syntax]
Numeric Literals
Numeric literals are used to generate typical integer or real (decimal)
numeric values and consist of an optional
minus sign (-
) followed by one or more digits, and optionally
followed by a decimal point (.
) and one or more additional
digits.
0.125 1 -2 3.0 -4.5
LtdTemplate does not support numeric literals in scientific notation or bases other than ten.
[Contents] [Template Code Syntax]
Variables
Variables hold references to values, and can hold references to (be
bound to) different values at different times. They exist within the stack
of namespaces. Referencing a variable
normally searches for it beginning in the most recent or "nearest"
namespace and works back to the first or "root" namespace until a
variable with that name is found. If the name begins with circumflex
(^
), the search begins in the parent namespace (if there is
one) instead of the current namespace. If the name begins with at-sign
(@
), only the root namespace is searched. If the variable
has not been assigned, the
nil value is used.
Variable names must be in one of the following formats (unless accessed as an element of a specific namespace—see last example) and are case-sensitive:
- A letter or an underscore (
_
), followed by zero or more letters, numbers, or underscores - An at-sign or circumflex followed by one or more letters, numbers, or underscores
- An at-sign, circumflex, or dollar-sign (
$
) by itself
name item1 _2 ^parent @root $
@['<\<weird>\>]
[Contents] [Template Code Syntax]
Method Calls
A method call performs an action on, or returns information about,
a value. A method call consists of a value expression followed by a
period (.
) followed by the desired method name, optionally
followed by an open parenthesis "(
", zero or more method
call parameters separated by commas (,
), and a closing
parenthesis ")
". Parameters may be positional (also called
sequential) or named (also called random-access). Use the "dot dot"
symbol (..
) to terminate the positional parameters and begin
the named parameters.
value_expression.method_name(positional_1,
..., positional_N .. name_1, value_1,
..., name_N, value_N)
Method names are case-sensitive and must be in one of the following formats:
- A letter or underscore (
_
) followed by zero or more letters, numbers, or underscores - One or more punctuation characters that don't have any other meaning (these are often referred to as "operators" in other syntax definitions), such as:
+ - * / % & | ! < <= = == != >= >
The parentheses are optional if no parameters are to be supplied to the method call. The period is optional for "operator-style" method calls if not immediately preceded by punctuation.
3.type /* => number */
3.type.length /* "chained" method calls; => 6 */
1+(2,3,4) /* short for */ 1.+(2,3,4) /* => 10 */
[Contents] [Template Code Syntax]
Assignments
Variables support two assignment method calls: unconditional
(=
) and conditional (?=
). A conditional
assignment does nothing if the variable is already bound to (holds a
reference to) a value (including the nil value). Assignments do not
render in the template output.
If called with a single parameter and no "dot dot" symbol, the value of the single parameter is assigned. Otherwise, all the parameters are assigned as an array. See also array values.
num=(5) num?=(6) /* num is still 5 */
empty1= empty2=() /* empty arrays */
single=(10 ..) /* one element */ double=(5, 10) /* two */
matrix=($.*(1, 0), $.*(0, 1) .. 'type, 'identity)
matrix[0, 0] /* => 1 */ matrix['type] /* => identity */
Variables beginning with circumflex (^
) will be created in
the parent namespace (if they do not already exist) and variables beginning
with at-sign (@
) will be created in the root namespace. All
others will be created in the current namespace.
See also the var method for namespaces.
[Contents] [Template Code Syntax]
Pre-Defined Variables
The following variables are pre-defined by LtdTemplate:
Name | Description |
---|---|
$ |
This is the current namespace. A new namespace is automatically created each time a code block is executed and is subsequently destroyed when the code block completes. |
^ |
This variable refers to the previous namespace if there is one, or nil if there isn't. |
@ |
This variable refers to the first (also known as "root" or "top-level") namespace. |
_ |
This variable contains the parameters passed into the template or current code block. |
[Contents] [Template Code Syntax]
Code Sequences
A code sequence refers to a sequence of zero or more template code expressions. Templates, method call parameters, and code block bodies are all code sequences.
If a code sequence consists of a single, non-string value and does not constitute the entire template code, it is retained as-is. Otherwise, the string value of each element in the sequence, if any, is combined to produce the result of the code sequence.
'Hello $.true ", " num=(5) num-(4) " world!"
/* 5 and 4 are single, non-string values in their code sequences */
/* $.true and num=(5) render nothing */
/* num-(4) returns the number 1 but it's string value gets used */
/* => Hello, 1 world! */
[Contents] [Template Code Syntax]
Code Blocks
If you surround a code sequence
by braces ({
and }
), you create a code
block. A code block is a value which does not render directly, but
can be called as a method call, executing
the code sequence within the code block.
render_method=({ $.method })
render_method.hi " " render_method.there
/* => hi there */
[Contents] [Template Code Syntax]
Subscripts And Code-Block Bindings
Any expression that evaluates to an array (or tree of nested arrays)
may be subscripted to select a particular value or nested array from the
array. A subscript consists of an open bracket ([
) followed
by one or more selector expressions separated by commas followed by a
closing bracket (]
). Consecutive selector expressions are
used to traverse progressively more deeply nested arrays.
array_var['items, 5] /* fetches item "5" (which
might also be an array) from array "items" in the array referenced by
array_var */
array_var['items][5] /* as above - alternate syntax */
If the requested item does not exist, the special value "nil" is used instead.
LtdTemplate also uses subscript syntax to bind code blocks to non-array values. These can subsequently be called like methods. They never override standard methods.
x['greeting]=({'hello}) /* where x is not an array
value */
x.greeting /* => hello */
You can also bind code blocks to proxy objects to be used by all array, boolean, number, or string values.
@Array?=(') /* bind the array proxy to a unique object */
@Array['list]=({ $.target.join(", ") }) /* bind the list method */
$.*(1, 2, 3).list /* => 1, 2, 3 */
[Contents] [Template Code Syntax]
Values And Methods
Arrays
LtdTemplate does not have array literals, but you can construct arrays using the variable assignment method (see variable syntax) or via the namespace anonymous array method:
empty=() /* empty array */ single=(10 ..) /* one element */
double=(5, 10) /* two */
matrix=($.*(1, 0), $.*(0, 1) .. 'type, 'identity)
matrix[0, 0] /* => 1 */ matrix['type] /* => identity */
Arrays render to the concatenation of the renderings of their sequential (positional) elements; random-access (named) elements are ignored.
Standard methods:
Method | Description |
---|---|
call | Same as the array itself |
class | Returns the string "Array" |
join | Joins sequential (positional) elements |
join( separator) | Join with separator between elements |
join( two, first,
middle, last) |
Joins two elements with two as the separator or more than two elements with first as the first separator, last as the last separator, and middle for all other separators |
pop , -> | Pop the last sequential element |
push( list) ,
+>( list) |
Adds zero or more elements in the list to the end of the array |
rnd_size | The number of random-access (named) elements |
seq_size | The number of sequential (positional) elements |
shift , <- | Shift the first sequential element |
size | The total number of elements in the array |
type | Returns the string "array" |
unshift( list) ,
<+( list) |
Adds zero or more elements in the list to the beginning of the array |
Code blocks may be bound as methods for all array values as follows:
@Array?=(') @Array['
method_name]=({
code sequence})
[Contents] [Values And Methods]
Booleans (True And False)
LtdTemplate supports boolean values (true and false). They can be
accessed via the namespace method calls $.true
and
$.false
. There is only one true value and one false value,
although other values can be interpreted in boolean context (the nil
value is treated as false; all others, including the number 0 and
empty strings, are treated as true).
Standard methods:
Method | Description |
---|---|
call | Same as the boolean itself |
class | Returns the string "Boolean" |
string , str |
Returns the string "true" for true and "false" for false |
type | Returns the string "boolean" |
+ , | , or |
Returns the "logical or" of the value and any supplied call parameters (if any are true, the result is true, otherwise the result is false) |
* , & , and |
Returns the "logical and" of the value and any supplied call parameters (if all are true, the result is true, otherwise the result is false) |
! , not |
Returns the "logical not and" of the value and any supplied call parameters (if all are false, the result is true, otherwise the result is false) |
Code blocks may be bound as methods for true, false, or both boolean values as follows:
$.true['
method_name]=({
code sequence})
method_name
$.false[']=({
code sequence})
method_name
@Boolean?=(') @Boolean[']=({
code sequence})
[Contents] [Values And Methods]
Code Blocks
Standard methods:
Method | Description |
---|---|
type | Returns the string "code" |
All other methods execute the code block in a new namespace.
[Contents] [Values And Methods]
Namespaces
A namespace is a storage area for variables. A new namespace is created
each time the template is rendered or a code
block is executed. In the case of code blocks, the previously active
namespace becomes the parent (^
) of the new namespace
($
).
Namespaces provide a number of pre-defined variables, as well as method calls for loops and conditionals that are traditionally statements in other programming environments.
Standard methods:
Method | Description |
---|---|
array( elements) ,
*( elements) |
Returns an anonymous array (see array values) |
false | Returns the boolean false value |
if( condition_1,
return_1, ...,
condition_N, return_N,
default) |
Processes each condition in turn. The return value corresponding to the first condition that evaluates to true is returned. If none of the conditions evaluate to true, the optional default value (or the nil value, in the case of an even number of parameters) is returned. Parameters can be supplied as code blocks to avoid execution unless and until needed. |
loop( before,
body, after) |
If the before condition evaluates to true, the body is executed and the optional after condition is evaluated. If the after condition is absent or evaluates to true, the loop starts over with the before condition. The body and non-constant conditions should be supplied as code blocks. Returns an array of body results (one element per loop iteration). |
method | Returns the method name used to call a code block, or "render" for top-level template code |
nil | Returns the nil value |
target | Returns the target object in a code block being called as part of an object binding |
true | Returns the boolean true value |
use( name) |
Calls the template loader to load resource name |
var( name_1, ...,
name_N .. set_1,
value_1, ..., set_N,
value_N) |
Creates and (re-)sets variables named by the supplied strings. The variables in the sequential parameters section, name_1 through name_N, are assigned the nil value. The variables in the random-access section, set_1 through set_N, are assigned the corresponding values from value_1 through value_N. |
[Contents] [Values And Methods]
Nil
LtdTemplate supports a "nil" value to represent the lack of another
value. It can be accessed via the namespace method call
$.nil
. There is only one nil value.
Standard methods:
Method | Description |
---|---|
type | Returns the string "nil" |
Code blocks may be bound as methods for the nil value as follows:
$.nil['
method_name]=({
code sequence})
[Contents] [Values And Methods]
Numbers
Standard methods:
Method | Description |
---|---|
abs |
Returns the absolute value of the number |
call | Returns the number itself |
ceil | Returns the closest greater or equal integer |
class | Returns the string "Number" |
floor | Returns the closest lesser or equal integer |
flt, float | Returns the number as a floating-point number |
int | Returns the number as an integer |
str , string |
Returns the number as a string |
type | Returns the string "number" |
+( list) |
Returns the sum of the number and numeric items in list |
- |
With no parameters, returns the negative of the number |
-( list) |
Returns the difference of the number and the sum of numeric items in the non-empty list |
*( list) |
Returns the product of the number and the numeric items in list |
/( list) |
Returns the quotient of the number and the numeric items in list |
%( list) |
Returns the progressive remainder of the number and the numeric items in list |
&( list) |
Returns the bit-wise "AND" of the number and the numeric items in list |
|( list) |
Returns the bit-wise "OR" of the number and the numeric items in list |
^( list) |
Returns the bit-wise "exclusive OR" of the number and the numeric items in list |
op or op( value) for
op in <= , < , == ,
!= , > , >= |
Returns whether the number is less than or equal to, less than, equal to, not equal to, greater than, or greater than or equal to, value. If value is not supplied or is not numeric, zero is used. |
[Contents] [Values And Methods]
Strings
Standard methods:
Method | Description |
---|---|
call | Returns the string itself |
class | Returns the string "String" |
flt , float |
Returns the floating-point value of the string |
idx( target,
offset) ,
index( target,
offset) |
Search for target left-to-right in the string beginning at position offset (default 0) and return the offset from the start of the string at which found (or -1 if not found) |
int |
Returns the integer value of the string |
len , length |
Returns the length of the string |
ridx( string,
offset) ,
rindex( string,
offset) |
Search for target right-to-left in the string beginning at position offset (the end of the string by default) and return the offset from the start of the string at which found (or -1 if not found) |
rng( begin,
end) ,
range( begin,
end) |
Returns characters begin through end of the string, inclusive, counting from zero. Either may be negative, in which case counting is backwards from the end of the string. |
slc( begin,
length) ,
slice( begin,
length) |
Returns length characters beginning at begin, counting from zero. Begin may be negative, in which case counting is backwards from the end of the string. |
str , string |
Returns the string itself |
type | Returns the string "string" |
+( list) |
Returns the concatenation of the string and the items in list |
*( value) |
Returns the concatenation of the string repeated value times. If value is negative, the reverse of the string repeated -value times is returned. If value is omitted or not numeric, an empty string is returned. |
op or op( value) for
op in <= , < , == ,
!= , > , >= |
Returns whether the string is less than or equal to, less than, equal to, not equal to, greater than, or greater than or equal to, value. If value is not supplied, the empty string is used. |
[Contents] [Values And Methods]
(Some More) Examples
This example binds a list method to arrays to include commas and "and" between elements:
@Array?=(') @Array['list]=({
$.target.join(" and ", ", ", ", ", ", and ") })
$.*('Ruby).list /* => Ruby */
$.*('Perl, 'Ruby).list /* => Perl and Ruby */
$.*('Perl, 'PHP, 'Python, 'Ruby).list /* => Perl, PHP, Python, and Ruby */
This example binds a method called "en_nth" on number values to return the English "nth" for the number (e.g. 1st for 1, 2nd for 2, 3rd for 3, etc.) and then generates them from -11 to 24:
@Number?=(') @Number['en_nth]=({
$.var(.. 'n, $.target) $.var(.. 'n10, n.abs%(10), 'n100, n.abs%(100))
n $.if({ n100>=(11)&(n100<=(20)) }, 'th, { n10==(1) }, 'st,
{ n10==(2) }, 'nd, { n10==(3) }, 'rd, 'th) })
n=(-11) $.loop({ n<=(24) }, { n.en_nth n=(n+(1)) }).join(", ")
[Contents]