template-toolkit-0.1.0.1: Text/TemplateToolkitLang.hs
{-|
Module : Text.TemplateToolkitLang
Description : Template Toolkit language manual for Haskell
Copyright : (c) Dzianis Kabanau, 2017
Maintainer : kobargh@gmail.com
Template Toolkit is a template processing system originally written in Perl by Andy Wardley.
Below is the complete documentation of features implemented in Haskell version of the system. Original documentation is available <http://www.template-toolkit.org/docs/index.html here>, but be warned that not all features are realized in Haskell version.
-}
module Text.TemplateToolkitLang (
-- * Tags
-- $tags
-- * Variables
-- $variables
-- * Operators
-- $operators
-- * Directives
-- $directives
-- * Virtual methods
-- $vmethods
-- * Filters
-- $filters
) where
{-$tags
Character sequences @__[% %]__@ are used to enclose directive tags within a template.
@
Hello __[% user.name %]__!
@
If directive tag starts by @__[%-__@ then all spaces before the tag are stripped. With @__-%]__@ all spaces after the tag are removed.
Multiple directives may be enclosed within one tag. In this case they must be separated by @__;__@
Comments are started by @__#__@
@
__[%__
__FOREACH__ __x__ = [0,15,100];
__x__; /# Comments here/
__END__;
__%]__
@
-}
{- $variables
There are three types of variables implemented: SCALARS, ARRAYS and HASHES.
Dots are used to traverse hashes and arrays: @__[% my_hash.key1 %]__@, @__[% my_array.0 %]__@.
Arrays may be represented in range form: @__[% xs = [1..10] %]__@
Actually arrays and hashes are kind-of Perl's arrayrefs and hashrefs.
So, for example, if two variables refer to one hash, modifying one variable affects another too.
Assignment to undefined hashes and arrays __autovivificates__ needed structures.
@
__[%__
/# scalar/
__int__ = 100;
__flt__ = 0.2;
__str__ = \"Hello \\\"guest\\\"\"; /# backslash is used to escape characters \" \' \\ $ and to type newlines \\n and tabs \\t./
/# array/
__arr__ = [1,2,\"three\"];
__rng__ = [1..10]; /# [1,2,3,4,5,6,7,8,9,10]/
/# hash/
__foo__ = {
k1 => 1,
k2 => \"value 2\",
k3 => [1,2,3],
k4 => {
subk1 => 10,
subk2 => 20,
}
};
__bar__ = __foo.k4;__
__bar.subk1__ = \"this is ten\";
__foo.k4.subk1;__ /# \'this is ten\'/
__bazarray.10.k1__ = 1; /# autovivification of array \'bazarray\' and hash \'bazarray.10\'/
__%]__
@
Variables may be __interpolated__ in double-quoted strings and in complex dotted variables (hashes or arrays).
__$__ character is used to precede interpolated variable: @"__$var__"@. Complex variables may be enclosed in curly braces: @"__${myhash.k1.0}__"@.
Single-qouted strings do not interpolate variables.
@
__[%__
__i__ = 2;
__kbar__ = \'bar\';
__arr__ = [\'one\',\'two\',\'three\',\'four\',\'five\'];
__hsh__ = {foo => 10, bar => 20};
__arr.$i__; /# \'three\'/
\"Foo is __${hsh.foo}__.0\"; /# \'Foo is 10.0\'/
__hsh.$kbar__; /# 20/
__%]__
@
-}
{-$operators
=== Arithmetic operators
@
__[%__
15 + 3.14; /# 18.14/
12 - 10; /# 2/
2 * 2; /# 4/
10 \/ 4; /# 2.5/
5 % 2; /# 1 modulus (remainder) of division/
/# \'mod\' - synonym of \'%\'/
13 mod 5; /# 3/
+7; /# 7 unary positive/
-7; /# -7 unary negative/
__%]__
@
=== Logical operators
__0__ and empty strings are /false/ values. Everything else is /true/. Internal representation of /true\/false/ is __1__\/__0__ respectively.
If both operands of comparison are strings, then they are compared as strings. Otherwise string operand is parsed as number.
@
__[%__
100 __>__ 99; /# 1 true/
100 __>=__ 101; /# 0 false/
100 __<__ 100; /# 0 false/
100 __<=__ 100; /# 1 true/
100 __==__ 100; /# 1 true/
100 __!=__ 100; /# 0 false/
__!__0; /# 1 unary negation/
\"100\" > 2; /# 1 true - numeric comparison/
\"100\" > \"2\"; /# 0 false - string comparison/
0 __||__ 100; /# 100/
/# \'or\' - synonym of \'||\'/
30 __or__ \'\'; /# 30/
\'fox\' __&&__ \'dog\'; /# \'dog\'/
/# \'and\' - synonym of \'&&\'/
\'fox\' __and__ \"\"; /# 0 evaluates to false value/
/# operations group with ( )/
(\"string\" && 0) __?__ \"snow\" __:__ \"rain\"; /# \'rain\'/
/# cond ? val_true : val_false ternary condition operator/
/# complex operands of ternary condition operator must be enclosed in parentheses:/
(!loop.last) ? \'not last\' : \'last\' /# \'not last\' or \'last\'/
!loop.last ? \'not last\' : \'last\' /# always evals to 0 - same as !(loop.last ? \'not last\' : \'last\')/
__%]__
@
=== String concatenation
Underscore @__\___@ separated by spaces is used to concatenate strings.
@
__[%__
__name__ = \"Zork\";
\"Hello,\" _ __name__; /# \'Hello, Zork\'/
__%]__
@
-}
{-$directives
=== Conditionals
__IF__ ... [ELSIF...] [ELSE...] __END__
@
__[% IF user.name__ == \'root\' __%]__
Hello, Admin!
__[% ELSIF user.status__ > 1 __%]__
Welcome, master __[% user.name %]__!
__[% ELSE %]__
Hi, __[% user.name %]__!
__[% END %]__
@
=== Loops
__FOREACH__ x = ... __END__
Special variable @__loop__@ is used to save information about foreach loop and current iteration.
@
__[%__ __FOREACH__ __i__ = [10..15] __%]__
I is __[% i %]__
__[%__
__IF__ __i__ == 12;
__loop.index;__ /# 2 current index/
__loop.count;__ /# 3 iteration count - index+1/
__loop.first;__ /# 10 first loop element/
__loop.last;__ /# 15 last loop element/
__loop.prev;__ /# 11 previous loop element/
__loop.next;__ /# 13 next loop element/
__loop.odd;__ /# 1 true if iteration count is odd/
__loop.even;__ /# 0 true if iteration count is even/
__END;__
__%]__
__[% END %]__
@
__WHILE__ ... __END__
@
__[%__
x = 1;
__WHILE__ x <= 20;
"| X$x ";
x = x + 1; __IF__ x > 3; __LAST__; __END__;
__FOREACH__ y = [1..10];
__IF__ y > 2 && y < 9; __NEXT__; __END__;
"y$y ";
__END__;
__END__;
/# Output: | X1 y1 y2 y9 y10 | X2 y1 y2 y9 y10 | X3 y1 y2 y9 y10/
__%]__
@
__LAST__ is used to immediately break current loop. __NEXT__ - to skip to the next iteration.
=== Processing template files and blocks
__PROCESS__ /blockname_or_filename/ [var1 = ... var2 = ... varN = ...]
__BLOCK__ /blockname/ ... __END__
@
\<html>
__[%__ __PROCESS__ header.tt __title__ = \'Homepage\' __descr__ = \'Homepage description\' __keyw__ = \'homepage,home,firstpage\' __%]__
\<p>Hello, __[% user.name %]__!
__[% BLOCK__ foobarbazzer __%]__
\<p>Foo__[% word %]__barbaz
__[% END %]__
__[%__
__FOREACH w__ = [\'fox\', \'dog\', \'cat\'];
__PROCESS__ foobarbazzer __word__ = __w__; /# \<p>Foofoxbarbaz \<p>Foodogbarbaz \<p>Foocatbarbaz/
__END__;
__%]__
__[%__ __PROCESS__ footer.tt __%]__
\</html>
@
Variable may be passed to __PROCESS__ or __WRAPPER__ directive as a name using __$__: @__[% PROCESS $template %]__@
=== Wrapper
__WRAPPER__ /wrapper_block_or_filename/ [var1 = ... var2 = ... varN = ...] ... __END__
The @__WRAPPER__@ block evaluates its content and passes the result in the variable @__content__@ to /wrapper_block_or_filename/. This is very useful for web templates with the same skeleton.
@
/FILE index.tt/
__[% WRAPPER html_wrap.tt title = \'Barbaz homepage!\' %]__
\<p>Welcome to Barbaz home!
__[% END %]__
/FILE html_wrap.tt/
\<html>
\<head>
\<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">
\<title>__[% title %]__\</title>
\</head>
\<body>
__[% content %]__
\</body>
\</html>
@
-}
{-$vmethods
Virtual methods are applied to the variables to get new values or to modify array or hash variable.
@__[% my_array.size %]__@ - Get the number of elements in @__my_array__@.
@__[% karr = my_hash.keys %]__@ - Create array @__karr__@. The elements are the keys of @__my_hash__@.
@__[% my_array.push(\"Baz\") %]__@ - Modify array @__my_array__@ appending scalar @__\"Baz\"__@ to the end of the array.
Methods that use regular expressions are based on __pcre__ patterns, e.g. @__[% bar.match(\'(?i)^baz\\\\d$\') %]__@.
Below is the list of implemented virtual methods. You can also take a look at the original documentation: <http://www.template-toolkit.org/docs/manual/VMethods.html Template Toolkit VMethods>.
===Scalar vmethods
[@.collapse@] Returns the string with trailing and leading spaces removed and internal multiple spaces converted to single space.
[@.defined@] Returns true if the value is defined.
[@.lcfirst@] Returns the string with first character converted to lower case.
[@.length@] Returns the length of the string.
[@.lower@] Returns the string converted to lower case.
[@.match(/pattern/, /global/)@] Returns the array of captured substrings from regexing target string with @/pattern/@. If pattern-match fails, returns @/false/@. Optional @/global/@ is used for global pattern-match to return all captured substrings.
[@.replace(/old/, /new/)@] Returns the string with all occurrences of @/old/@ replaced by @/new/@.
[@.split(/pattern/)@] Returns the array produced by splitting the string by @/pattern/@.
[@.trim@] Returns the string with leading and trailing spaces removed.
[@.ucfirst@] Returns the string with first character converted to upper case.
[@.upper@] Returns the string converted to upper case.
===Array vmethods
[@.first@] Returns the first element of the array.
[@.grep(/pattern/)@] Returns the array of elements that match @/pattern/@.
[@.import(/arr1/, /arr2/, /arrN/)@] Imports to the target array elements of all passed arrays. Target array is modified.
[@.join(/separator/)@] Returns the string created by joining all elements of the array separated by @/separator/@.
[@.last@] Returns the last element of the array.
[@.nsort@] Returns the array sorted numerically.
[@.pop@] Removes the last element from the array. Target array is modified.
[@.push(/el1/, /el2/, /elN/)@] Appends element(s) to the end of the array. Target array is modified.
[@.reverse@] Returns reversed version of the array.
[@.shift@] Removes the first element from the array. Target array is modified.
[@.size@] Returns the number of elements in the array.
[@.slice(/from/, /to/)@] Returns the array of elements idexing in the range @/from/../to/@ of the original array. If @/to/@ is omitted, then to the last element.
[@.sort@] Returns the array sorted alphabetically.
[@.splice(/offset/,/length/,/insertarray/)@] Powerful array-modification method that behaves just like <https://perldoc.perl.org/functions/splice.html Perl's splice>. Removes from the array @/length/@ elements starting from @/offset/@ index, replacing them with @/insertarray/@. If @/insertarray/@ is omitted - just removes elements. If @/length/@ is omitted removes everything up to the end of the array. @/length/@ may be @0@ - no elements are removed. @/offset/@ may be negative - counts index from the end of the array, e.g. @-2@ - penultimate element's index. Target array is modified.
[@.unique@] Returns the array of only unique elements.
[@.unshift(/el1/, /el2/, /elN/)@] Prepends element(s) to the beginning of the array. Target array is modified.
===Hash vmethods
[@.delete(/key1/, /key2/, /keyN/)@] Deletes items identified by the keys from the hash. Target hash is modified.
[@.each@] Returns keys and values of the hash in one array - @[key1, val1, key2, val2, ... keyN, valN]@.
[@.keys@] Returns the array of the hash keys.
[@.import(/hash1/, /hash2/, /hashN/)@] Imports to the target hash items of all passed hashes. Existing items get new values, new items are added. Target hash is modified.
[@.item(/key/)@] Returns the value of hash item identified by /key/. This is useful to get values with keys that contain any characters. E.g. @__[% hash.item('complex $ key.') %]__@ or @__[% hash.item('12') %]__@.
[@.pairs@] Returns the array of key-value pairs of the hash. The pairs are hashes each with two keys: @__key__@ and @__value__@.
[@.size@] Returns the number of items in the hash.
[@.values@] Returns the array of the hash values.
Sometimes a hash may have items whith keys that conflict with the above method names. In this situation parentheses may be used to force method call.
@
__[%__
__my_car__ = {
\'keys\' => \'lost\',
\'mileage\' => 150000,
};
__my_car.keys__; /# \'lost\'/
__my_car.keys()__; /# [\'keys\', \'mileage\']/
__%]__
@
-}
{-$filters
Filters transform text of a block. Filter may be applied as a directive:
__FILTER__ /filter_name/ ... __END__
Or in piped form (multiple filters may be chained):
/expr/ __|__ /filter_name [| /filter_name]/
@
__[% FILTER collapse %]__
__[% PROCESS body.tt %]__
__[% END %]__
The same:
__[% PROCESS body.tt | collapse %]__
@
Below is the list of implemented filters.
[@collapse@] Removes leading and trailing spaces. Internal multiple spaces are converted to single space.
[@html@] Replaces all @__\<__@, @__>__@, @__&__@, @__\"__@ with @__<__@, @__>__@, @__&__@, @__"__@ respectively.
[@lcfirst@] Converts the first character to lower case.
[@lcfirst@] Converts all characters to lower case.
[@null@] Discards the text of block
[@replace(/old/, /new/)@] Replaces all occurrences of @/old/@ with @/new/@.
[@trim@] Removes leading and trailing spaces.
[@ucfirst@] Converts the first character to upper case.
[@upper@] Converts all characters to upper case.
[@uri@] URI-encodes text.
-}