util/interpolation.lua
author Kim Alvefur <zash@zash.se>
Mon, 12 Dec 2022 07:03:31 +0100
branch0.11
changeset 12802 c4b1b5cbc20b
parent 11310 5798ab735619
child 11311 f2e276bb4ef8
permissions -rw-r--r--
Tag 0.11.14
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
6723
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
--
6774
60957dd5b41b util.{interpolation,prosodyctl,sql}: Trim trailing whitespace
Kim Alvefur <zash@zash.se>
parents: 6723
diff changeset
     3
-- The new() function takes a pattern and an escape function and returns
6723
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:
6774
60957dd5b41b util.{interpolation,prosodyctl,sql}: Trim trailing whitespace
Kim Alvefur <zash@zash.se>
parents: 6723
diff changeset
    12
-- {name} is substituted for values["name"] and is escaped using the
6723
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} }
6774
60957dd5b41b util.{interpolation,prosodyctl,sql}: Trim trailing whitespace
Kim Alvefur <zash@zash.se>
parents: 6723
diff changeset
    17
-- To show a defaults for missing values {name? sub-template } can be used,
6723
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.
6774
60957dd5b41b util.{interpolation,prosodyctl,sql}: Trim trailing whitespace
Kim Alvefur <zash@zash.se>
parents: 6723
diff changeset
    19
-- {name& sub-template } does the opposite, the sub-template is rendered
6723
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
6775
805baeca56b6 util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents: 6774
diff changeset
    27
local function new_render(pat, escape, funcs)
6723
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);
10352
3852fc91b2fc util.interpolation: Support unescaped variables with more modifiers (fixes #1452)
Kim Alvefur <zash@zash.se>
parents: 6775
diff changeset
    35
			local name, raw, opt, e = s_match(block, "^([%a_][%w_.]*)(!?)(%p?)()");
6723
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
6775
805baeca56b6 util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents: 6774
diff changeset
    45
			if funcs then
11310
5798ab735619 util.interpolation: Fix combination of filters and fallback values #1623
Kim Alvefur <zash@zash.se>
parents: 10352
diff changeset
    46
				while opt == '|' do
6775
805baeca56b6 util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents: 6774
diff changeset
    47
					local f;
10352
3852fc91b2fc util.interpolation: Support unescaped variables with more modifiers (fixes #1452)
Kim Alvefur <zash@zash.se>
parents: 6775
diff changeset
    48
					f, raw, opt, e = s_match(block, "^([%a_][%w_.]*)(!?)(%p?)()", e);
6775
805baeca56b6 util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents: 6774
diff changeset
    49
					f = funcs[f];
11310
5798ab735619 util.interpolation: Fix combination of filters and fallback values #1623
Kim Alvefur <zash@zash.se>
parents: 10352
diff changeset
    50
					if value ~= nil and f then value = f(value); end
6775
805baeca56b6 util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents: 6774
diff changeset
    51
				end
805baeca56b6 util.interpolation: Add support for filter functions
Kim Alvefur <zash@zash.se>
parents: 6774
diff changeset
    52
			end
6723
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);
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    67
			elseif opt == '?' and not value then
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    68
				return render(s_sub(block, e), values);
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    69
			elseif value ~= nil then
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    70
				if type(value) ~= "string" then
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    71
					value = tostring(value);
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    72
				end
10352
3852fc91b2fc util.interpolation: Support unescaped variables with more modifiers (fixes #1452)
Kim Alvefur <zash@zash.se>
parents: 6775
diff changeset
    73
				if raw ~= '!' then
6723
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    74
					return escape(value);
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    75
				end
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    76
				return value;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    77
			end
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
	end
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    80
	return render;
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
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    83
return {
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    84
	new = new_render;
936cf2f7531f util.interpolation: A template engine for text
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    85
};