Annotate

util/interpolation.lua @ 12764:bf6d2f9fad4d

util.dbuffer: Add a bunch of missing test cases Found via mutation testing.
author Matthew Wild <mwild1@gmail.com>
date Tue, 11 Oct 2022 11:38:32 +0100
parent 11307:f2e276bb4ef8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6720
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
1 -- Simple template language
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
2 --
6771
60957dd5b41b util.{interpolation,prosodyctl,sql}: Trim trailing whitespace
Kim Alvefur <zash@zash.se>
parents: 6720
diff changeset
3 -- The new() function takes a pattern and an escape function and returns
6720
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
4 -- a render() function. Both are required.
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
5 --
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
6 -- The function render() takes a string template and a table of values.
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
7 -- Sequences like {name} in the template string are substituted
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
8 -- with values from the table, optionally depending on a modifier
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
9 -- symbol.
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
10 --
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
11 -- Variants are:
6771
60957dd5b41b util.{interpolation,prosodyctl,sql}: Trim trailing whitespace
Kim Alvefur <zash@zash.se>
parents: 6720
diff changeset
12 -- {name} is substituted for values["name"] and is escaped using the
6720
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
13 -- second argument to new_render(). To disable the escaping, use {name!}.
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
14 -- {name.item} can be used to access table items.
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
15 -- To renter lists of items: {name# item number {idx} is {item} }
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
16 -- Or key-value pairs: {name% t[ {idx} ] = {item} }
6771
60957dd5b41b util.{interpolation,prosodyctl,sql}: Trim trailing whitespace
Kim Alvefur <zash@zash.se>
parents: 6720
diff changeset
17 -- To show a defaults for missing values {name? sub-template } can be used,
6720
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
18 -- which renders a sub-template if values["name"] is false-ish.
6771
60957dd5b41b util.{interpolation,prosodyctl,sql}: Trim trailing whitespace
Kim Alvefur <zash@zash.se>
parents: 6720
diff changeset
19 -- {name& sub-template } does the opposite, the sub-template is rendered
6720
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
20 -- if the selected value is anything but false or nil.
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
21
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
22 local type, tostring = type, tostring;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
23 local pairs, ipairs = pairs, ipairs;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
24 local s_sub, s_gsub, s_match = string.sub, string.gsub, string.match;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
25 local t_concat = table.concat;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
26
6772
805baeca56b6 util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents: 6771
diff changeset
27 local function new_render(pat, escape, funcs)
6720
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
28 -- assert(type(pat) == "string", "bad argument #1 to 'new_render' (string expected)");
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
29 -- assert(type(escape) == "function", "bad argument #2 to 'new_render' (function expected)");
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
30 local function render(template, values)
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
31 -- assert(type(template) == "string", "bad argument #1 to 'render' (string expected)");
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
32 -- assert(type(values) == "table", "bad argument #2 to 'render' (table expected)");
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
33 return (s_gsub(template, pat, function (block)
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
34 block = s_sub(block, 2, -2);
10348
3852fc91b2fc util.interpolation: Support unescaped variables with more modifiers (fixes #1452)
Kim Alvefur <zash@zash.se>
parents: 6772
diff changeset
35 local name, raw, opt, e = s_match(block, "^([%a_][%w_.]*)(!?)(%p?)()");
6720
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
36 if not name then return end
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
37 local value = values[name];
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
38 if not value and name:find(".", 2, true) then
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
39 value = values;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
40 for word in name:gmatch"[^.]+" do
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
41 value = value[word];
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
42 if not value then break; end
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
43 end
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
44 end
6772
805baeca56b6 util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents: 6771
diff changeset
45 if funcs then
11306
5798ab735619 util.interpolation: Fix combination of filters and fallback values #1623
Kim Alvefur <zash@zash.se>
parents: 10348
diff changeset
46 while opt == '|' do
6772
805baeca56b6 util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents: 6771
diff changeset
47 local f;
10348
3852fc91b2fc util.interpolation: Support unescaped variables with more modifiers (fixes #1452)
Kim Alvefur <zash@zash.se>
parents: 6772
diff changeset
48 f, raw, opt, e = s_match(block, "^([%a_][%w_.]*)(!?)(%p?)()", e);
6772
805baeca56b6 util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents: 6771
diff changeset
49 f = funcs[f];
11306
5798ab735619 util.interpolation: Fix combination of filters and fallback values #1623
Kim Alvefur <zash@zash.se>
parents: 10348
diff changeset
50 if value ~= nil and f then value = f(value); end
6772
805baeca56b6 util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents: 6771
diff changeset
51 end
805baeca56b6 util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents: 6771
diff changeset
52 end
6720
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
53 if opt == '#' or opt == '%' then
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
54 if type(value) ~= "table" then return ""; end
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
55 local iter = opt == '#' and ipairs or pairs;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
56 local out, i, subtpl = {}, 1, s_sub(block, e);
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
57 local subvalues = setmetatable({}, { __index = values });
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
58 for idx, item in iter(value) do
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
59 subvalues.idx = idx;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
60 subvalues.item = item;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
61 out[i], i = render(subtpl, subvalues), i+1;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
62 end
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
63 return t_concat(out);
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
64 elseif opt == '&' then
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
65 if not value then return ""; end
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
66 return render(s_sub(block, e), values);
11064
af1e3b7d9ea3 util.interpolation: Add '~' as the opposite of '&' (render sub-block if falsy)
Matthew Wild <mwild1@gmail.com>
parents: 10348
diff changeset
67 elseif opt == '~' then
af1e3b7d9ea3 util.interpolation: Add '~' as the opposite of '&' (render sub-block if falsy)
Matthew Wild <mwild1@gmail.com>
parents: 10348
diff changeset
68 if value then return ""; end
af1e3b7d9ea3 util.interpolation: Add '~' as the opposite of '&' (render sub-block if falsy)
Matthew Wild <mwild1@gmail.com>
parents: 10348
diff changeset
69 return render(s_sub(block, e), values);
6720
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
70 elseif opt == '?' and not value then
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
71 return render(s_sub(block, e), values);
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
72 elseif value ~= nil then
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
73 if type(value) ~= "string" then
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
74 value = tostring(value);
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
75 end
10348
3852fc91b2fc util.interpolation: Support unescaped variables with more modifiers (fixes #1452)
Kim Alvefur <zash@zash.se>
parents: 6772
diff changeset
76 if raw ~= '!' then
6720
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
77 return escape(value);
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
78 end
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
79 return value;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
80 end
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
81 end));
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
82 end
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
83 return render;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
84 end
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
85
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
86 return {
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
87 new = new_render;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
88 };