Safe Haskell | Trustworthy |
---|
A simple templating system with variable substitution, function invokation, for
loops and conditionals. Most callers should use compileTemplate
and invoke
the template with renderTemplate
. E.g.:
let myTemplate = compileTemplate "Hello, $@$!" print $ renderTemplate myTemplate mempty "World"
- compileTemplate :: Text -> Either String Template
- evaluate :: AST -> Template
- evaluateAST :: FunctionMap -> Value -> AST -> Value
- valueToText :: Value -> Text
- replaceVar :: Value -> Identifier -> Value -> Value
- module Web.Simple.Templates.Types
Language Description
A template may contain plain-text, which is reproduced as is, as well as blocks of code, escaped by surrounding with dollar-signs ($), for variable expansion, function invokation, conditionals and loops. For example, given a global variable "answer" with the value 42,
The answer to the universe is $answer$.
would expand to
The answer to the universe is 42.
Since the dollar-sign is used to denote code sections, it must be escaped in plaintext sections by typing two dollar-signs. For example, to reproduce the lyrics for Bonzo Goes to Bitburg, by The Ramones:
Shouldn't wish you happiness, wish her the very best. $$50,000 dress Shaking hands with your highness
Literals
Bool
s, Number
s, String
s, Array
s and Null
can be typed
as literals.
Pi is approximately $3.14159$
-
String
s are surrounded by double-quotes ("). Double-quotes inside a string can be escaped by proceeding it with a backslash (\"), however backslashes themselves do not need to be escaped:
And then, Dr. Evil said: $"Mini Me, stop humping the \"laser\"."$
-
Array
s are surrounded by square-brackets ([ ]) and elements are comma separated. Elements can be literals, variables or function invokations, and do not have to be the same type:
$["Foo", 42, ["bar", "baz"], length([1, 2, 3, 6])]$
-
Null
is type as the literal null (in lower case):
$null$
Variable substitution
Templates are evaluated with a single global variable called @. For example, you can refernce the global in your template like so:
The value in my global is $@$.
If the global is an Object
, it can be indexed using dot-notation:
The Sex Pistols' bassist was $@.bassist.name.first$
In this case, you may also discard the @ global reference and simply name the field in the global object, for example:
Field 'foo' is $foo$. Field 'bar.baz' is $bar.baz$.
String
s, Number
s and Bool
s are meaningful when evaluated to
text in a template, while Object
s, Array
s and Null
s simply render as
strings representing their types (e.g. "[object]"). However, all types can
be used as arguments to functions, or in conditionals and loops.
Function Invokation
Functions are invoked with similar syntax to imperative languages:
$myfunc(arg1, arg2, arg3)$
where arguments can be literals, variables or other function calls -- basically anything that can be evaluated can be an argument to a function. Function names are in a separate namespace than variables, so there can be a function and variable both named foo and they are differentiated by their use. For example:
$mysymbol$
is a variable expansion, whereas
$mysymbol()$
is a function invokation.
Conditionals
Branching is supported through the common if statement with an optional else branch. Conditions can be any expression. false and null are evaluated as false, while everything else is evaluated as true.
if blocks are surround by an if-statement and and endif, each surrounded separately by dollar signs. Optionally, the else branch is declared by with "$else$". The blocks themselves are templates and may contain regular text as well as evaluable expressions.
Should I stay or should I go? $if(go)$ Trouble will be $trouble$. $else$ Trouble will be $double(trouble)$ $endif$
For Loops
For loops iterate over collections, setting a variable name to one element
in the collection for each iteration of the loop. Collections are usually
Array
s, however non-false expressions (e.g., String
s and Number
s) are
treated as collections with one element. A loop starts with a
for-statement surrounded by dollar-signs and end with an "$endfor$":
<h1>The Clash</h1> <ul> $for(member in band)$ <li>$member.name$ played the $member.instrument$</li> $endfor$ </ul>
There is also an optional "$sep$" (for separator) clause, which is rendered between iterations. So if I have a collection with three items, the sep clause will be rendered after the first and second, but not third elements:
<h1>Grocery list</h1> <p> $for(item in groceries)$ $item.quantity$ $item.name$(s). $sep$ <br/> $endfor$ </p>
Will render something like:
<h1>Grocery list</h1> <p> 2 MC(s). <br/> 1 DJ(s) <br/> </p>
Compilation
Helpers
valueToText :: Value -> TextSource
replaceVar :: Value -> Identifier -> Value -> ValueSource
module Web.Simple.Templates.Types