util.interpolation
util.interpolation
implements a string template
language, primarily meant for interpolation of variables into HTML.
An example:
local st = require"util.stanza"
local render = require"util.interpolation".new("%b{}", st.xml_escape);
local template = [[
<title>{title}</title>
<h1>{title}</h1>
<p>Hello, {name}! Welcome to {here}.</p>
]]
print(render(template, { title = "Welome", name = "Alice", here = "wonderland" })
new
The module exposes a single new()
function, which takes
2 or 3 arguments and returns a renderer function.
The first argument is the pattern that signifies variables. The first
capture must have exactly one character before and after the variable
name. It is recommended to use the
%bxy
pattern construct. To allow a longer pre- or
suffix, a capture can be used around the inner two characters, so a
longer pattern may be "\\var(%b{})"
for
\var(variable)
.
The second argument must be an escaping function for the target text
format. For HTML or XML the xml_escape
function from util.stanza is suitable. To
disable escaping, simply pass function(x) return x end
.
The third argument is an optional table of filter functions. See the Filters section below.
The returned function takes two arguments, a template string and a table of variables.
Modifiers
No escaping
To pass a variable through raw, without escaping, put an exclamation
mark as last character: {foo!}
.
Optional variables
Normally, if a variable used in the template is left out, the
original template text is passed through unchanged. This can be changed
by including a question mark: {foo?}
, then the entire
expression will be removed in the output.
This fallback text can contain nested template expressions, like
{foo?empty, but {bar}}
.
template | input | output |
---|---|---|
{foo?bar} |
{foo="hi"} |
"hi" |
{foo?bar} |
{foo=""} |
"" |
{foo?bar} |
{} |
"bar" |
{foo?bar} |
{foo=false} |
"bar" |
Conditional subtemplate
Similar to fallback text, but the other way around:
{foo&the variable foo is {foo}}
.
template | input | output |
---|---|---|
{foo&bar} |
{foo="hi"} |
"bar" |
{foo&bar} |
{foo=""} |
"bar" |
{foo&bar} |
{} |
"" |
{foo&bar} |
{foo=true} |
"bar" |
{foo&bar} |
{foo=false} |
"" |
To insert text when a variable is falsy, without using the variable
itself, use {foo~the variable is falsy}
, which renders to
the empty string when foo
is truthy, unlike
{foo?fallback}
. (the ~
syntax added in
0.12)
template | input | output |
---|---|---|
{foo~bar} |
{foo="hi"} |
"" |
{foo~bar} |
{foo=""} |
"" |
{foo~bar} |
{} |
"bar" |
{foo~bar} |
{foo=true} |
"" |
{foo~bar} |
{foo=false} |
"bar" |
Iterating over arrays and maps
To render a list of things using the same template the expression
{list#subtemplate with {idx} and {item}}
can be used. Each
item will be available in the sub-template as an item
variable, and its index will be idx
.
local template = [[
<ul>{items#
<li id="item-{idx}">{item}</li>}
</ul>
]]
print(render(template, { items = { "lorem", "ipsum", "dolor", "sit", "amet" } }))
Iterating over arbitrary key-value tables is done like
{table%{idx} = {item}}
.
Filters
The third argument to new
is a table of filter
functions. To invoke these, the pipe symbol is used, like
{foo|uppercase}
. Multiple filters may be chained. The
filter functions get the input as one argument. Returning nil cancels
further chained filters. May be combined with one final modifier.