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.