IMPORTANT: due to a drive failure, as of 13-Mar-2021, the Mercurial repository had to be re-mirrored, which changed every commit SHA. The old SHAs and trees are backed up in the vault branches. Please migrate to the new branches as soon as you can.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
prosody/util/interpolation.lua

88 lines
3.1 KiB

-- Simple template language
--
-- The new() function takes a pattern and an escape function and returns
-- a render() function. Both are required.
--
-- The function render() takes a string template and a table of values.
-- Sequences like {name} in the template string are substituted
-- with values from the table, optionally depending on a modifier
-- symbol.
--
-- Variants are:
-- {name} is substituted for values["name"] and is escaped using the
-- second argument to new_render(). To disable the escaping, use {name!}.
-- {name.item} can be used to access table items.
-- To renter lists of items: {name# item number {idx} is {item} }
-- Or key-value pairs: {name% t[ {idx} ] = {item} }
-- To show a defaults for missing values {name? sub-template } can be used,
-- which renders a sub-template if values["name"] is false-ish.
-- {name& sub-template } does the opposite, the sub-template is rendered
-- if the selected value is anything but false or nil.
local type, tostring = type, tostring;
local pairs, ipairs = pairs, ipairs;
local s_sub, s_gsub, s_match = string.sub, string.gsub, string.match;
local t_concat = table.concat;
local function new_render(pat, escape, funcs)
-- assert(type(pat) == "string", "bad argument #1 to 'new_render' (string expected)");
-- assert(type(escape) == "function", "bad argument #2 to 'new_render' (function expected)");
local function render(template, values)
-- assert(type(template) == "string", "bad argument #1 to 'render' (string expected)");
-- assert(type(values) == "table", "bad argument #2 to 'render' (table expected)");
return (s_gsub(template, pat, function (block)
block = s_sub(block, 2, -2);
local name, raw, opt, e = s_match(block, "^([%a_][%w_.]*)(!?)(%p?)()");
if not name then return end
local value = values[name];
if not value and name:find(".", 2, true) then
value = values;
for word in name:gmatch"[^.]+" do
value = value[word];
if not value then break; end
end
end
if funcs then
while opt == '|' do
local f;
f, raw, opt, e = s_match(block, "^([%a_][%w_.]*)(!?)(%p?)()", e);
f = funcs[f];
if value ~= nil and f then value = f(value); end
end
end
if opt == '#' or opt == '%' then
if type(value) ~= "table" then return ""; end
local iter = opt == '#' and ipairs or pairs;
local out, i, subtpl = {}, 1, s_sub(block, e);
local subvalues = setmetatable({}, { __index = values });
for idx, item in iter(value) do
subvalues.idx = idx;
subvalues.item = item;
out[i], i = render(subtpl, subvalues), i+1;
end
return t_concat(out);
elseif opt == '&' then
if not value then return ""; end
return render(s_sub(block, e), values);
elseif opt == '~' then
if value then return ""; end
return render(s_sub(block, e), values);
elseif opt == '?' and not value then
return render(s_sub(block, e), values);
elseif value ~= nil then
if type(value) ~= "string" then
value = tostring(value);
end
if raw ~= '!' then
return escape(value);
end
return value;
end
end));
end
return render;
end
return {
new = new_render;
};