मॉड्यूल:Params
This module is rated as ready for general use. It has reached a mature form and is thought to be bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
See the ChangeLog | |
Last update: 11 अगस्त 2024 |
The {{#invoke:params}}
module is designed to be adopted by those templates that want to have a deep control of their parameters. It is particularly useful to variadic templates, to which it offers the possibility to count, list, map and propagate the parameters received without knowing their number in advance.
The module offers elegant shortcuts to non variadic templates as well. Outside templates it has virtually no applications; hence, if you plan to make experiments, make sure to do them from within a template, or you will not be able to see much (you can use {{Template sandbox}} for that). Under ./testcases you can find helper templates that can be specifically used for testing the module's capabilities in flexible ways (see in particular the {{./testcases/tmulti}} template).
साँचा:A note In case your template uses this module, please add साँचा:Tji to its documentation page, so that if breaking changes will be introduced in the future the template will be easily traceable.
--- ---
--- LOCAL ENVIRONMENT ---
--- ________________________________ ---
--- ---
--[[ Abstract utilities ]]--
----------------------------
-- Helper function for `string.gsub()` (for managing zero-padded numbers)
function zero_padded(str)
return ("%03d%s"):format(#str, str)
end
-- Helper function for `table.sort()` (for natural sorting)
function natural_sort(var1, var2)
return tostring(var1):gsub("%d+", zero_padded) <
tostring(var2):gsub("%d+", zero_padded)
end
-- Return a copy or a reference to a table
local function copy_or_ref_table(src, refonly)
if refonly then return src end
newtab = {}
for key, val in pairs(src) do newtab[key] = val end
return newtab
end
-- Remove numerical elements from a table, shifting everything to the left
function remove_numerical_keys(tbl, idx, len)
local cache = {}
local tmp = idx + len - 1
for key, val in pairs(tbl) do
if type(key) == 'number' and key >= idx then
if key > tmp then cache[key - len] = val end
tbl[key] = nil
end
end
for key, val in pairs(cache) do tbl[key] = val end
end
-- Make a reduced copy of a table (shifting in both directions if necessary)
function copy_table_reduced(tbl, idx, len)
local ret = {}
local tmp = idx + len - 1
if idx > 0 then
for key, val in pairs(tbl) do
if type(key) ~= 'number' or key < idx then
ret[key] = val
elseif key > tmp then ret[key - len] = val end
end
elseif tmp > 0 then
local nshift = 1 - idx
for key, val in pairs(tbl) do
if type(key) ~= 'number' then ret[key] = val
elseif key > tmp then ret[key - tmp] = val
elseif key < idx then ret[key + nshift] = val end
end
else
for key, val in pairs(tbl) do
if type(key) ~= 'number' or key > tmp then
ret[key] = val
elseif key < idx then ret[key + len] = val end
end
end
return ret
end
-- Make an expanded copy of a table (shifting in both directions if necessary)
function copy_table_expanded(tbl, idx, len)
local ret = {}
local tmp = idx + len - 1
if idx > 0 then
for key, val in pairs(tbl) do
if type(key) ~= 'number' or key < idx then
ret[key] = val
else ret[key + len] = val end
end
elseif tmp > 0 then
local nshift = idx - 1
for key, val in pairs(tbl) do
if type(key) ~= 'number' then ret[key] = val
elseif key > 0 then ret[key + tmp] = val
elseif key < 1 then ret[key + nshift] = val end
end
else
for key, val in pairs(tbl) do
if type(key) ~= 'number' or key > tmp then
ret[key] = val
else ret[key - len] = val end
end
end
return ret
end
-- Move a key from a table to another, but only if under a different name and
-- always parsing numerical strings as numbers
function steal_if_renamed(val, src, skey, dest, dkey)
local realkey = tonumber(dkey) or dkey:match'^%s*(.-)%s*$'
if skey ~= realkey then
dest[realkey] = val
src[skey] = nil
end
end
--[[ Public strings ]]--
------------------------
-- Special match keywords (functions and modifiers MUST avoid these names)
local mkeywords = {
['or'] = 0,
--pattern = 1, -- Simply uncommenting enables the option
plain = 2,
strict = 3
}
-- Sort functions (functions and modifiers MUST avoid these names)
local sortfunctions = {
--alphabetically = false, -- Simply uncommenting enables the option
naturally = natural_sort
}
-- Callback styles for the `mapping_*` and `renaming_*` class of modifiers
-- (functions and modifiers MUST avoid these names)
--[[
Meanings of the columns:
col[1] = Loop type (0-3)
col[2] = Number of module arguments that the style requires (1-3)
col[3] = Minimum number of sequential parameters passed to the callback
col[4] = Name of the callback parameter where to place each parameter name
col[5] = Name of the callback parameter where to place each parameter value
col[6] = Argument in the modifier's invocation that will override `col[4]`
col[7] = Argument in the modifier's invocation that will override `col[5]`
A value of `-1` indicates that no meaningful value is stored (i.e. `nil`)
]]--
local mapping_styles = {
names_and_values = { 3, 2, 2, 1, 2, -1, -1 },
values_and_names = { 3, 2, 2, 2, 1, -1, -1 },
values_only = { 1, 2, 1, -1, 1, -1, -1 },
names_only = { 2, 2, 1, 1, -1, -1, -1 },
names_and_values_as = { 3, 4, 0, -1, -1, 2, 3 },
names_only_as = { 2, 3, 0, -1, -1, 2, -1 },
values_only_as = { 1, 3, 0, -1, -1, -1, 2 },
blindly = { 0, 2, 0, -1, -1, -1, -1 }
}
-- Memory slots (functions and modifiers MUST avoid these names)
local memoryslots = {
i = 'itersep',
l = 'lastsep',
p = 'pairsep',
h = 'header',
f = 'footer',
n = 'ifngiven'
}
-- Functions and modifiers MUST avoid these names too: `let`
--[[ Module's private environment ]]--
--------------------------------------
-- Maximum number of numerical parameters that can be filled, if missing (we
-- chose an arbitrary number for this constant; you can discuss about its
-- optimal value at Module talk:Params)
local maxfill = 1024
-- The private table of functions
local library = {}
-- Functions that can only be invoked in first position
local static_iface = {}
-- Create a new context
local function context_new()
local ctx = {}
ctx.luaname = 'Module:Params' --[[ or `frame:getTitle()` ]]--
ctx.iterfunc = pairs
ctx.firstposonly = static_iface
ctx.n_available = maxfill
return ctx
end
-- Move to the next action within the user-given list
local function context_iterate(ctx, n_forward)
local nextfn
if ctx.pipe[n_forward] ~= nil then
nextfn = ctx.pipe[n_forward]:match'^%s*(.*%S)'
end
if nextfn == nil then error(ctx.luaname ..
': You must specify a function to call', 0) end
if library[nextfn] == nil then
if ctx.firstposonly[nextfn] == nil then error(ctx.luaname ..
': The function ‘' .. nextfn .. '’ does not exist', 0)
else error(ctx.luaname .. ': The ‘' .. nextfn ..
'’ directive can only appear in first position', 0)
end
end
remove_numerical_keys(ctx.pipe, 1, n_forward)
return library[nextfn]
end
-- Main loop
local function main_loop(ctx, start_with)
local fn = start_with
repeat fn = fn(ctx) until not fn
end
-- Parse the arguments of the `mapping_*` and `renaming_*` class of modifiers
function parse_child_args(dest, src, n_skip, default_style)
local style
local shf
local tmp = src[n_skip + 1]
if tmp ~= nil then style = mapping_styles[tmp:match'^%s*(.-)%s*$'] end
if style == nil then
style = default_style
shf = n_skip - 1
else shf = n_skip end
local names
local nargs
local pin = style[2] + shf
local n_exist = style[3]
local karg = style[4]
local varg = style[5]
tmp = style[6]
if tmp > -1 then
tmp = src[tmp + shf]
karg = tonumber(tmp)
if karg == nil then karg = tmp:match'^%s*(.-)%s*$'
else n_exist = math.max(n_exist, karg) end
end
tmp = style[7]
if tmp > -1 then
tmp = src[tmp + shf]
varg = tonumber(tmp)
if varg == nil then varg = tmp:match'^%s*(.-)%s*$'
else n_exist = math.max(n_exist, varg) end
end
if src[pin] ~= nil and src[pin]:match'^%s*let%s*$' then
names = {}
repeat
tmp = src[pin + 1] or ''
names[tonumber(tmp) or tmp:match'^%s*(.-)%s*$' or ''] =
src[pin + 2]
pin = pin + 3
until src[pin] == nil or not src[pin]:match'^%s*let%s*$'
end
tmp = tonumber(src[pin])
if tmp ~= nil then
if tmp < 0 then tmp = -1 end
shf = n_exist - pin
for idx = pin + 1, pin + tmp do dest[idx + shf] = src[idx] end
nargs = pin + tmp + 1
else nargs = pin end
if names ~= nil then
for key, val in pairs(names) do dest[key] = val end
end
tmp = style[1]
if (tmp == 3 or tmp == 2) and dest[karg] ~= nil then
tmp = tmp - 2 end
if (tmp == 3 or tmp == 1) and dest[varg] ~= nil then
tmp = tmp - 1 end
return nargs, tmp, karg, varg
end
-- Parse the arguments of the `with_*_matching` class of modifiers
local function parse_pattern_args(ctx, ptns, fname)
local state = 0
local cnt = 1
local keyw
local nptns = 0
for _, val in ipairs(ctx.pipe) do
if state == 0 then
nptns = nptns + 1
ptns[nptns] = { val, false, false }
state = -1
else
keyw = val:match'^%s*(.*%S)'
if keyw == nil or mkeywords[keyw] == nil or (
state > 0 and mkeywords[keyw] > 0
) then break
else
state = mkeywords[keyw]
if state > 1 then ptns[nptns][2] = true end
if state == 3 then ptns[nptns][3] = true end
end
end
cnt = cnt + 1
end
if state == 0 then error(ctx.luaname .. ', ‘' .. fname ..
'’: No pattern was given', 0) end
return cnt
end
-- Map parameters' values using a custom callback and a referenced table
function map_values(tbl, margs, karg, varg, looptype, fn)
if looptype == 1 then
for key, val in pairs(tbl) do
margs[varg] = val
tbl[key] = fn()
end
elseif looptype == 3 then
for key, val in pairs(tbl) do
margs[karg] = key
margs[varg] = val
tbl[key] = fn()
end
elseif looptype == 2 then
for key in pairs(tbl) do
margs[karg] = key
tbl[key] = fn()
end
elseif looptype == 0 then
for key in pairs(tbl) do
tbl[key] = fn()
end
end
end
-- Map parameters' names using a custom callback and a referenced table
function map_names(tbl, rargs, karg, varg, looptype, fn)
local cache = {}
if looptype == 2 then
for key, val in pairs(tbl) do
rargs[karg] = key
steal_if_renamed(val, tbl, key, cache, fn())
end
elseif looptype == 3 then
for key, val in pairs(tbl) do
rargs[karg] = key
rargs[varg] = val
steal_if_renamed(val, tbl, key, cache, fn())
end
elseif looptype == 1 then
for key, val in pairs(tbl) do
rargs[varg] = val
steal_if_renamed(val, tbl, key, cache, fn())
end
elseif looptype == 0 then
for key, val in pairs(tbl) do
steal_if_renamed(val, tbl, key, cache, fn())
end
end
for key, val in pairs(cache) do tbl[key] = val end
end
-- Concatenate the numerical keys from the table of parameters to the numerical
-- keys from the table of options; non-numerical keys from the table of options
-- will prevail over colliding non-numerical keys from the table of parameters
local function concat_params(ctx)
local tbl = ctx.params
local size = table.maxn(ctx.pipe)
local retval = {}
if ctx.subset == 1 then
-- We need only the sequence
for key, val in ipairs(tbl) do retval[key + size] = val end
else
if ctx.subset == -1 then
for key, val in ipairs(tbl) do tbl[key] = nil end
end
for key, val in pairs(tbl) do
if type(key) == 'number' then retval[key + size] = val
else retval[key] = val end
end
end
for key, val in pairs(ctx.pipe) do retval[key] = val end
return retval
end
-- Flush the parameters by calling a custom function for each value (after this
-- function has been invoked `ctx.params` will be no longer usable)
local function flush_params(ctx, fn)
local tbl = ctx.params
if ctx.subset == 1 then
for key, val in ipairs(tbl) do fn(key, val) end
return
end
if ctx.subset == -1 then
for key, val in ipairs(tbl) do tbl[key] = nil end
end
if ctx.dosort then
local nums = {}
local words = {}
local nlen = 0
local wlen = 0
for key, val in pairs(tbl) do
if type(key) == 'number' then
nlen = nlen + 1
nums[nlen] = key
else
wlen = wlen + 1
words[wlen] = key
end
end
table.sort(nums)
table.sort(words, natural_sort)
for idx = 1, nlen do fn(nums[idx], tbl[nums[idx]]) end
for idx = 1, wlen do fn(words[idx], tbl[words[idx]]) end
return
end
if ctx.subset ~= -1 then
for key, val in ipairs(tbl) do
fn(key, val)
tbl[key] = nil
end
end
for key, val in pairs(tbl) do fn(key, val) end
end
--[[ Modifiers ]]--
-----------------------------
-- Syntax: #invoke:params|sequential|pipe to
library.sequential = function(ctx)
if ctx.subset == -1 then error(ctx.luaname ..
': The two directives ‘non-sequential’ and ‘sequential’ are in contradiction with each other', 0) end
if ctx.dosort then error(ctx.luaname ..
': The ‘all_sorted’ directive is redundant when followed by ‘sequential’', 0) end
ctx.iterfunc = ipairs
ctx.subset = 1
return context_iterate(ctx, 1)
end
-- Syntax: #invoke:params|non-sequential|pipe to
library['non-sequential'] = function(ctx)
if ctx.subset == 1 then error(ctx.luaname ..
': The two directives ‘sequential’ and ‘non-sequential’ are in contradiction with each other', 0) end
ctx.iterfunc = pairs
ctx.subset = -1
return context_iterate(ctx, 1)
end
-- Syntax: #invoke:params|sort|pipe to
library.all_sorted = function(ctx)
if ctx.subset == 1 then error(ctx.luaname ..
': The ‘all_sorted’ directive is redundant after ‘sequential’', 0) end
ctx.dosort = true
return context_iterate(ctx, 1)
end
-- Syntax: #invoke:params|setting|directives|...|pipe to
library.setting = function(ctx)
local opts = ctx.pipe
local cmd = opts[1]
if cmd ~= nil then
cmd = cmd:gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])'
end
if cmd == nil then error(ctx.luaname ..
', ‘setting’: No directive was given', 0) end
local sep = string.byte('/')
local argc = 2
local dest = {}
local vname
local chr
for idx = 1, #cmd do
chr = cmd:byte(idx)
if chr == sep then
for key, val in ipairs(dest) do
ctx[val] = opts[argc]
dest[key] = nil
end
argc = argc + 1
else
vname = memoryslots[string.char(chr)]
if vname == nil then error(ctx.luaname ..
', ‘setting’: Unknown slot "' ..
string.char(chr) .. '"', 0) end
table.insert(dest, vname)
end
end
for key, val in ipairs(dest) do ctx[val] = opts[argc] end
return context_iterate(ctx, argc + 1)
end
-- Syntax: #invoke:params|squeezing|pipe to
library.squeezing = function(ctx)
local tbl = ctx.params
local store = {}
local indices = {}
local newlen = 0
for key, val in pairs(tbl) do
if type(key) == 'number' then
newlen = newlen + 1
indices[newlen] = key
store[key] = val
tbl[key] = nil
end
end
table.sort(indices)
for idx = 1, newlen do tbl[idx] = store[indices[idx]] end
return context_iterate(ctx, 1)
end
-- Syntax: #invoke:params|filling_the_gaps|pipe to
library.filling_the_gaps = function(ctx)
local tbl = ctx.params
local nmin = 1
local nmax = nil
local nnums = -1
local tmp = {}
for key, val in pairs(tbl) do
if type(key) == 'number' then
if nmax == nil then
if key < nmin then nmin = key end
nmax = key
elseif key > nmax then nmax = key
elseif key < nmin then nmin = key end
nnums = nnums + 1
tmp[key] = val
end
end
if nmax ~= nil and nmax - nmin > nnums then
ctx.n_available = ctx.n_available + nmin + nnums - nmax
if ctx.n_available < 0 then error(ctx.luaname ..
', ‘filling_the_gaps’: It is possible to fill at most ' ..
tostring(maxfill) .. ' parameters', 0) end
for idx = nmin, nmax, 1 do tbl[idx] = '' end
for key, val in pairs(tmp) do tbl[key] = val end
end
return context_iterate(ctx, 1)
end
-- Syntax: #invoke:params|clearing|pipe to
library.clearing = function(ctx)
local tbl = ctx.params
local numericals = {}
for key, val in pairs(tbl) do
if type(key) == 'number' then
numericals[key] = val
tbl[key] = nil
end
end
for key, val in ipairs(numericals) do tbl[key] = val end
return context_iterate(ctx, 1)
end
-- Syntax: #invoke:params|cutting|left cut|right cut|pipe to
library.cutting = function(ctx)
local lcut = tonumber(ctx.pipe[1])
if lcut == nil then error(ctx.luaname ..
', ‘cutting’: Left cut must be a number', 0) end
local rcut = tonumber(ctx.pipe[2])
if rcut == nil then error(ctx.luaname ..
', ‘cutting’: Right cut must be a number', 0) end
local tbl = ctx.params
local len = #tbl
if lcut < 0 then lcut = len + lcut end
if rcut < 0 then rcut = len + rcut end
local tot = lcut + rcut
if tot > 0 then
local cache = {}
if tot >= len then
for key in ipairs(tbl) do tbl[key] = nil end
tot = len
else
for idx = len - rcut + 1, len, 1 do tbl[idx] = nil end
for idx = 1, lcut, 1 do tbl[idx] = nil end
end
for key, val in pairs(tbl) do
if type(key) == 'number' and key > 0 then
if key > len then cache[key - tot] = val
else cache[key - lcut] = val end
tbl[key] = nil
end
end
for key, val in pairs(cache) do tbl[key] = val end
end
return context_iterate(ctx, 3)
end
-- Syntax: #invoke:params|cropping|left crop|right crop|pipe to
library.cropping = function(ctx)
local lcut = tonumber(ctx.pipe[1])
if lcut == nil then error(ctx.luaname ..
', ‘cropping’: Left crop must be a number', 0) end
local rcut = tonumber(ctx.pipe[2])
if rcut == nil then error(ctx.luaname ..
', ‘cropping’: Right crop must be a number', 0) end
local tbl = ctx.params
local nmin
local nmax
for key in pairs(tbl) do
if type(key) == 'number' then
if nmin == nil then
nmin = key
nmax = key
elseif key > nmax then nmax = key
elseif key < nmin then nmin = key end
end
end
if nmin ~= nil then
local len = nmax - nmin + 1
if lcut < 0 then lcut = len + lcut end
if rcut < 0 then rcut = len + rcut end
if lcut + rcut - len > -1 then
for key in pairs(tbl) do
if type(key) == 'number' then tbl[key] = nil end
end
elseif lcut + rcut > 0 then
for idx = nmax - rcut + 1, nmax do tbl[idx] = nil end
for idx = nmin, nmin + lcut - 1 do tbl[idx] = nil end
local lshift = nmin + lcut - 1
if lshift > 0 then
for idx = lshift + 1, nmax, 1 do
tbl[idx - lshift] = tbl[idx]
tbl[idx] = nil
end
end
end
end
return context_iterate(ctx, 3)
end
-- Syntax: #invoke:params|purging|start offset|length|pipe to
library.purging = function(ctx)
local idx = tonumber(ctx.pipe[1])
if idx == nil then error(ctx.luaname ..
', ‘purging’: Start offset must be a number', 0) end
local len = tonumber(ctx.pipe[2])
if len == nil then error(ctx.luaname ..
', ‘purging’: Length must be a number', 0) end
local tbl = ctx.params
if len < 1 then
len = len + table.maxn(tbl)
if idx > len then return context_iterate(ctx, 3) end
len = len - idx + 1
end
ctx.params = copy_table_reduced(tbl, idx, len)
return context_iterate(ctx, 3)
end
-- Syntax: #invoke:params|backpurging|start offset|length|pipe to
library.backpurging = function(ctx)
local last = tonumber(ctx.pipe[1])
if last == nil then error(ctx.luaname ..
', ‘backpurging’: Start offset must be a number', 0) end
local len = tonumber(ctx.pipe[2])
if len == nil then error(ctx.luaname ..
', ‘backpurging’: Length must be a number', 0) end
local idx
local tbl = ctx.params
if len > 0 then
idx = last - len + 1
else
for key in pairs(tbl) do
if type(key) == 'number' and (idx == nil or
key < idx) then idx = key end
end
if idx == nil then return context_iterate(ctx, 3) end
idx = idx - len
if last < idx then return context_iterate(ctx, 3) end
len = last - idx + 1
end
ctx.params = copy_table_reduced(ctx.params, idx, len)
return context_iterate(ctx, 3)
end
-- Syntax: #invoke:params|rotating|pipe to
library.rotating = function(ctx)
local tbl = ctx.params
local numericals = {}
local nmax = 0
for key, val in pairs(tbl) do
if type(key) == 'number' then
numericals[key] = val
tbl[key] = nil
if key > nmax then nmax = key end
end
end
for key, val in pairs(numericals) do tbl[nmax - key + 1] = val end
return context_iterate(ctx, 1)
end
-- Syntax: #invoke:params|pivoting|pipe to
--[[
library.pivoting = function(ctx)
local tbl = ctx.params
local shift = #tbl + 1
if shift < 2 then return library.rotating(ctx) end
local numericals = {}
for key, val in pairs(tbl) do
if type(key) == 'number' then
numericals[key] = val
tbl[key] = nil
end
end
for key, val in pairs(numericals) do tbl[shift - key] = val end
return context_iterate(ctx, 1)
end
]]--
-- Syntax: #invoke:params|mirroring|pipe to
--[[
library.mirroring = function(ctx)
local tbl = ctx.params
local numericals = {}
local nmax
local nmin
for key, val in pairs(tbl) do
if type(key) == 'number' then
numericals[key] = val
tbl[key] = nil
if nmax == nil then
nmax = key
nmin = key
elseif key > nmax then nmax = key
elseif key < nmin then nmin = key end
end
end
for key, val in pairs(numericals) do tbl[nmax + nmin - key] = val end
return context_iterate(ctx, 1)
end
]]--
-- Syntax: #invoke:params|swapping|pipe to
--[[
library.swapping = function(ctx)
local tbl = ctx.params
local cache = {}
local nsize = 0
local tmp
for key in pairs(tbl) do
if type(key) == 'number' then
nsize = nsize + 1
cache[nsize] = key
end
end
table.sort(cache)
for idx = math.floor(nsize / 2), 1, -1 do
tmp = tbl[cache[idx] ]
tbl[cache[idx] ] = tbl[cache[nsize - idx + 1] ]
tbl[cache[nsize - idx + 1] ] = tmp
end
return context_iterate(ctx, 1)
end
]]--
-- Syntax: #invoke:params|sorting_sequential_values|[criterion]|pipe to
library.sorting_sequential_values = function(ctx)
local sortfn
if ctx.pipe[1] ~= nil then sortfn = sortfunctions[ctx.pipe[1]] end
if sortfn then table.sort(ctx.params, sortfn)
else table.sort(ctx.params) end -- i.e. either `false` or `nil`
if sortfn == nil then return context_iterate(ctx, 1) end
return context_iterate(ctx, 2)
end
-- Syntax: #invoke:params|inserting|position|how many|...|pipe to
--[[
library.inserting = function(ctx)
-- NOTE: `ctx.params` might be the original metatable! As a modifier,
-- this function MUST create a copy of it before returning
local idx = tonumber(ctx.pipe[1])
if idx == nil then error(ctx.luaname ..
', ‘inserting’: Position must be a number', 0) end
local len = tonumber(ctx.pipe[2])
if len == nil or len < 1 then error(ctx.luaname ..
', ‘inserting’: The amount must be a number greater than zero', 0) end
local opts = ctx.pipe
local tbl = copy_table_expanded(ctx.params, idx, len)
for key = idx, idx + len - 1 do tbl[key] = opts[key - idx + 3] end
ctx.params = tbl
return context_iterate(ctx, len + 3)
end
]]--
-- Syntax: #invoke:params|imposing|name|value|pipe to
library.imposing = function(ctx)
if ctx.pipe[1] == nil then error(ctx.luaname ..
', ‘imposing’: Missing parameter name to impose', 0) end
local key = ctx.pipe[1]:match'^%s*(.-)%s*$'
ctx.params[tonumber(key) or key] = ctx.pipe[2]
return context_iterate(ctx, 3)
end
-- Syntax: #invoke:params|discarding|name|[how many]|pipe to
library.discarding = function(ctx)
if ctx.pipe[1] == nil then error(ctx.luaname ..
', ‘discarding’: Missing parameter name to discard', 0) end
local key = ctx.pipe[1]
local len = tonumber(ctx.pipe[2])
if len == nil then
ctx.params[tonumber(key) or key:match'^%s*(.-)%s*$'] = nil
return context_iterate(ctx, 2)
end
key = tonumber(key)
if key == nil then error(ctx.luaname ..
', ‘discarding’: A range was provided, but the initial parameter name is not numerical', 0) end
if len < 1 then error(ctx.luaname ..
', ‘discarding’: A range can only be a number greater than zero', 0) end
for idx = key, key + len - 1 do ctx.params[idx] = nil end
return context_iterate(ctx, 3)
end
-- Syntax: #invoke:params|with_name_matching|pattern 1|[plain flag 1]|[or]
-- |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag
-- N]|pipe to
library.with_name_matching = function(ctx)
local tbl = ctx.params
local patterns = {}
local argc = parse_pattern_args(ctx, patterns, 'with_name_matching')
local nomatch
for key in pairs(tbl) do
nomatch = true
for _, ptn in ipairs(patterns) do
if not ptn[3] then
if string.find(key, ptn[1], 1, ptn[2]) then
nomatch = false
break
end
elseif key == ptn[1] then
nomatch = false
break
end
end
if nomatch then tbl[key] = nil end
end
return context_iterate(ctx, argc)
end
-- Syntax: #invoke:params|with_name_not_matching|pattern 1|[plain flag 1]
-- |[and]|[pattern 2]|[plain flag 2]|[and]|[...]|[pattern N]|[plain
-- flag N]|pipe to
library.with_name_not_matching = function(ctx)
local tbl = ctx.params
local patterns = {}
local argc = parse_pattern_args(ctx, patterns,
'with_name_not_matching')
local yesmatch
for key in pairs(tbl) do
yesmatch = true
for _, ptn in ipairs(patterns) do
if ptn[3] then
if key ~= ptn[1] then
yesmatch = false
break
end
elseif not string.find(key, ptn[1], 1, ptn[2]) then
yesmatch = false
break
end
end
if yesmatch then tbl[key] = nil end
end
return context_iterate(ctx, argc)
end
-- Syntax: #invoke:params|with_value_matching|pattern 1|[plain flag 1]|[or]
-- |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag
-- N]|pipe to
library.with_value_matching = function(ctx)
local tbl = ctx.params
local patterns = {}
local argc = parse_pattern_args(ctx, patterns, 'with_value_matching')
local nomatch
for key, val in pairs(tbl) do
nomatch = true
for _, ptn in ipairs(patterns) do
if ptn[3] then
if val == ptn[1] then
nomatch = false
break
end
elseif string.find(val, ptn[1], 1, ptn[2]) then
nomatch = false
break
end
end
if nomatch then tbl[key] = nil end
end
return context_iterate(ctx, argc)
end
-- Syntax: #invoke:params|with_value_not_matching|pattern 1|[plain flag 1]
-- |[and]|[pattern 2]|[plain flag 2]|[and]|[...]|[pattern N]|[plain
-- flag N]|pipe to
library.with_value_not_matching = function(ctx)
local tbl = ctx.params
local patterns = {}
local argc = parse_pattern_args(ctx, patterns,
'with_value_not_matching')
local yesmatch
for key, val in pairs(tbl) do
yesmatch = true
for _, ptn in ipairs(patterns) do
if ptn[3] then
if val ~= ptn[1] then
yesmatch = false
break
end
elseif not string.find(val, ptn[1], 1, ptn[2]) then
yesmatch = false
break
end
end
if yesmatch then tbl[key] = nil end
end
return context_iterate(ctx, argc)
end
-- Syntax: #invoke:params|trimming_values|pipe to
library.trimming_values = function(ctx)
local tbl = ctx.params
for key, val in pairs(tbl) do tbl[key] = val:match'^%s*(.-)%s*$' end
return context_iterate(ctx, 1)
end
-- Syntax: #invoke:params|mapping_by_calling|template name|[call
-- style]|[let]|[...][number of additional parameters]|[parameter
-- 1]|[parameter 2]|[...]|[parameter N]|pipe to
library.mapping_by_calling = function(ctx)
local opts = ctx.pipe
local tname
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
if tname == nil then error(ctx.luaname ..
', ‘mapping_by_calling’: No template name was provided', 0) end
local margs = {}
local argc, looptype, karg, varg = parse_child_args(margs, opts, 1,
mapping_styles.values_only)
local model = { title = tname, args = margs }
map_values(ctx.params, margs, karg, varg, looptype, function()
return ctx.frame:expandTemplate(model)
end)
return context_iterate(ctx, argc)
end
-- Syntax: #invoke:params|mapping_by_invoking|module name|function
-- name|[call style]|[let]|[...]|[number of additional
-- arguments]|[argument 1]|[argument 2]|[...]|[argument N]|pipe to
library.mapping_by_invoking = function(ctx)
local opts = ctx.pipe
local mname
local fname
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
if mname == nil then error(ctx.luaname ..
', ‘mapping_by_invoking’: No module name was provided', 0) end
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
if fname == nil then error(ctx.luaname ..
', ‘mapping_by_invoking’: No function name was provided', 0) end
local margs = {}
local argc, looptype, karg, varg = parse_child_args(margs, opts, 2,
mapping_styles.values_only)
local model = { title = 'Module:' .. mname, args = margs }
local mfunc = require(model.title)[fname]
if mfunc == nil then error(ctx.luaname ..
', ‘mapping_by_invoking’: The function ‘' .. fname ..
'’ does not exist', 0) end
map_values(ctx.params, margs, karg, varg, looptype, function()
return mfunc(ctx.frame:newChild(model))
end)
return context_iterate(ctx, argc)
end
-- Syntax: #invoke:params|mapping_by_magic|parser function|[call
-- style]|[let]|[...][number of additional arguments]|[argument
-- 1]|[argument 2]|[...]|[argument N]|pipe to
library.mapping_by_magic = function(ctx)
local opts = ctx.pipe
local magic
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end
if magic == nil then error(ctx.luaname ..
', ‘mapping_by_magic’: No parser function was provided', 0) end
local margs = {}
local argc, looptype, karg, varg = parse_child_args(margs, opts, 1,
mapping_styles.values_only)
map_values(ctx.params, margs, karg, varg, looptype, function()
return ctx.frame:callParserFunction(magic, margs)
end)
return context_iterate(ctx, argc)
end
-- Syntax: #invoke:params|renaming_by_calling|template name|[call
-- style]|[let]|[...][number of additional parameters]|[parameter
-- 1]|[parameter 2]|[...]|[parameter N]|pipe to
library.renaming_by_calling = function(ctx)
local opts = ctx.pipe
local tname
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
if tname == nil then error(ctx.luaname ..
', ‘renaming_by_calling’: No template name was provided', 0) end
local rargs = {}
local argc, looptype, karg, varg = parse_child_args(rargs, opts, 1,
mapping_styles.names_only)
local model = { title = tname, args = rargs }
map_names(ctx.params, rargs, karg, varg, looptype, function()
return ctx.frame:expandTemplate(model)
end)
return context_iterate(ctx, argc)
end
-- Syntax: #invoke:params|renaming_by_invoking|module name|function
-- name|[call style]|[let]|[...]|[number of additional
-- arguments]|[argument 1]|[argument 2]|[...]|[argument N]|pipe to
library.renaming_by_invoking = function(ctx)
local opts = ctx.pipe
local mname
local fname
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
if mname == nil then error(ctx.luaname ..
', ‘renaming_by_invoking’: No module name was provided', 0) end
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
if fname == nil then error(ctx.luaname ..
', ‘renaming_by_invoking’: No function name was provided', 0) end
local rargs = {}
local argc, looptype, karg, varg = parse_child_args(rargs, opts, 2,
mapping_styles.names_only)
local model = { title = 'Module:' .. mname, args = rargs }
local mfunc = require(model.title)[fname]
if mfunc == nil then error(ctx.luaname ..
', ‘renaming_by_invoking’: The function ‘' .. fname ..
'’ does not exist', 0) end
map_names(ctx.params, rargs, karg, varg, looptype, function()
return mfunc(ctx.frame:newChild(model))
end)
return context_iterate(ctx, argc)
end
-- Syntax: #invoke:params|renaming_by_magic|parser function|[call
-- style]|[let]|[...][number of additional arguments]|[argument
-- 1]|[argument 2]|[...]|[argument N]|pipe to
library.renaming_by_magic = function(ctx)
local opts = ctx.pipe
local magic
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end
if magic == nil then error(ctx.luaname ..
', ‘renaming_by_magic’: No parser function was provided', 0) end
local rargs = {}
local argc, looptype, karg, varg = parse_child_args(rargs, opts, 1,
mapping_styles.names_only)
map_names(ctx.params, rargs, karg, varg, looptype, function()
return ctx.frame:callParserFunction(magic, rargs)
end)
return context_iterate(ctx, argc)
end
--[[ Functions ]]--
-----------------------------
-- Syntax: #invoke:params|count
library.count = function(ctx)
-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!
local retval = 0
for _ in ctx.iterfunc(ctx.params) do retval = retval + 1 end
if ctx.subset == -1 then retval = retval - #ctx.params end
ctx.text = retval
return false
end
-- Syntax: #invoke:args|concat_and_call|template name|[prepend 1]|[prepend 2]
-- |[...]|[item n]|[named item 1=value 1]|[...]|[named item n=value
-- n]|[...]
library.concat_and_call = function(ctx)
-- NOTE: `ctx.params` might be the original metatable!
local opts = ctx.pipe
local tname
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
if tname == nil then error(ctx.luaname ..
', ‘concat_and_call’: No template name was provided', 0) end
remove_numerical_keys(opts, 1, 1)
ctx.text = ctx.frame:expandTemplate{
title = tname,
args = concat_params(ctx)
}
return false
end
-- Syntax: #invoke:args|concat_and_invoke|module name|function name|[prepend
-- 1]|[prepend 2]|[...]|[item n]|[named item 1=value 1]|[...]|[named
-- item n=value n]|[...]
library.concat_and_invoke = function(ctx)
-- NOTE: `ctx.params` might be the original metatable!
local opts = ctx.pipe
local mname
local fname
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
if mname == nil then error(ctx.luaname ..
', ‘concat_and_invoke’: No module name was provided', 0) end
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
if fname == nil then error(ctx.luaname ..
', ‘concat_and_invoke’: No function name was provided', 0) end
remove_numerical_keys(opts, 1, 2)
local mfunc = require('Module:' .. mname)[fname]
if mfunc == nil then error(ctx.luaname ..
', ‘concat_and_invoke’: The function ‘' .. fname ..
'’ does not exist', 0) end
ctx.text = mfunc(ctx.frame:newChild{
title = 'Module:' .. fname,
args = concat_params(ctx)
})
return false
end
-- Syntax: #invoke:args|concat_and_magic|parser function|[prepend 1]|[prepend
-- 2]|[...]|[item n]|[named item 1=value 1]|[...]|[named item n=
-- value n]|[...]
library.concat_and_magic = function(ctx)
-- NOTE: `ctx.params` might be the original metatable!
local opts = ctx.pipe
local magic
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end
if magic == nil then error(ctx.luaname ..
', ‘concat_and_magic’: No parser function was provided', 0) end
remove_numerical_keys(opts, 1, 1)
ctx.text = ctx.frame:callParserFunction(magic, concat_params(ctx))
return false
end
-- Syntax: #invoke:params|value_of|parameter name
library.value_of = function(ctx)
-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!
local opts = ctx.pipe
local kstr
if opts[1] ~= nil then kstr = opts[1]:match'^%s*(.*%S)' end
if kstr == nil then error(ctx.luaname ..
', ‘value_of’: No parameter name was provided', 0) end
local knum = tonumber(kstr)
local len = #ctx.params
local val = ctx.params[knum or kstr]
if val ~= nil and (
ctx.subset ~= -1 or knum == nil or knum > len or knum < 1
) and (
ctx.subset ~= 1 or (knum ~= nil and knum <= len and knum > 0)
) then
ctx.text = (ctx.header or '') .. val .. (ctx.footer or '')
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
-- Syntax: #invoke:params|list
library.list = function(ctx)
-- NOTE: `ctx.pipe` might be the original metatable!
local kvs = ctx.pairsep or ''
local pps = ctx.itersep or ''
local ret = {}
local nss = 0
flush_params(
ctx,
function(key, val)
ret[nss + 1] = pps
ret[nss + 2] = key
ret[nss + 3] = kvs
ret[nss + 4] = val
nss = nss + 4
end
)
if nss > 0 then
if nss > 4 and ctx.lastsep ~= nil then
ret[nss - 3] = ctx.lastsep
end
ret[1] = ctx.header or ''
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
ctx.text = table.concat(ret)
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
-- Syntax: #invoke:params|list_values
library.list_values = function(ctx)
-- NOTE: `ctx.pipe` might be the original metatable!
local pps = ctx.itersep or ''
local ret = {}
local nss = 0
flush_params(
ctx,
function(key, val)
ret[nss + 1] = pps
ret[nss + 2] = val
nss = nss + 2
end
)
if nss > 0 then
if nss > 2 and ctx.lastsep ~= nil then
ret[nss - 1] = ctx.lastsep
end
ret[1] = ctx.header or ''
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
ctx.text = table.concat(ret)
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
-- Syntax: #invoke:params|for_each|wikitext
library.for_each = function(ctx)
-- NOTE: `ctx.pipe` might be the original metatable!
local txt = ctx.pipe[1] or ''
local pps = ctx.itersep or ''
local ret = {}
local nss = 0
flush_params(
ctx,
function(key, val)
ret[nss + 1] = pps
ret[nss + 2] = txt:gsub('%$#', key):gsub('%$@', val)
nss = nss + 2
end
)
if nss > 0 then
if nss > 2 and ctx.lastsep ~= nil then
ret[nss - 1] = ctx.lastsep
end
ret[1] = ctx.header or ''
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
ctx.text = table.concat(ret)
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
-- Syntax: #invoke:params|call_for_each|template name|[append 1]|[append 2]
-- |[...]|[append n]|[named param 1=value 1]|[...]|[named param
-- n=value n]|[...]
library.call_for_each = function(ctx)
local opts = ctx.pipe
local tname
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
if tname == nil then error(ctx.luaname ..
', ‘call_for_each’: No template name was provided', 0) end
local model = { title = tname, args = opts }
local ccs = ctx.itersep or ''
local ret = {}
local nss = 0
table.insert(opts, 1, true)
flush_params(
ctx,
function(key, val)
opts[1] = key
opts[2] = val
ret[nss + 1] = ccs
ret[nss + 2] = ctx.frame:expandTemplate(model)
nss = nss + 2
end
)
if nss > 0 then
if nss > 2 and ctx.lastsep ~= nil then
ret[nss - 1] = ctx.lastsep
end
ret[1] = ctx.header or ''
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
ctx.text = table.concat(ret)
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
-- Syntax: #invoke:params|invoke_for_each|module name|module function|[append
-- 1]|[append 2]|[...]|[append n]|[named param 1=value 1]|[...]
-- |[named param n=value n]|[...]
library.invoke_for_each = function(ctx)
local opts = ctx.pipe
local mname
local fname
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
if mname == nil then error(ctx.luaname ..
', ‘invoke_for_each’: No module name was provided', 0) end
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
if fname == nil then error(ctx.luaname ..
', ‘invoke_for_each’: No function name was provided', 0) end
local model = { title = 'Module:' .. mname, args = opts }
local mfunc = require(model.title)[fname]
local ccs = ctx.itersep or ''
local ret = {}
local nss = 0
flush_params(
ctx,
function(key, val)
opts[1] = key
opts[2] = val
ret[nss + 1] = ccs
ret[nss + 2] = mfunc(ctx.frame:newChild(model))
nss = nss + 2
end
)
if nss > 0 then
if nss > 2 and ctx.lastsep ~= nil then
ret[nss - 1] = ctx.lastsep
end
ret[1] = ctx.header or ''
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
ctx.text = table.concat(ret)
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
-- Syntax: #invoke:params|magic_for_each|parser function|[append 1]|[append 2]
-- |[...]|[append n]|[named param 1=value 1]|[...]|[named param
-- n=value n]|[...]
library.magic_for_each = function(ctx)
local opts = ctx.pipe
local magic
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end
if magic == nil then error(ctx.luaname ..
', ‘magic_for_each’: No parser function was provided', 0) end
local ccs = ctx.itersep or ''
local ret = {}
local nss = 0
table.insert(opts, 1, true)
flush_params(
ctx,
function(key, val)
opts[1] = key
opts[2] = val
ret[nss + 1] = ccs
ret[nss + 2] = ctx.frame:callParserFunction(magic,
opts)
nss = nss + 2
end
)
if nss > 0 then
if nss > 2 and ctx.lastsep ~= nil then
ret[nss - 1] = ctx.lastsep
end
ret[1] = ctx.header or ''
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
ctx.text = table.concat(ret)
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
-- Syntax: #invoke:params|call_for_each_value|template name|[append 1]|[append
-- 2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param
-- n=value n]|[...]
library.call_for_each_value = function(ctx)
local opts = ctx.pipe
local tname
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
if tname == nil then error(ctx.luaname ..
', ‘call_for_each_value’: No template name was provided', 0) end
local model = { title = tname, args = opts }
local ccs = ctx.itersep or ''
local ret = {}
local nss = 0
flush_params(
ctx,
function(key, val)
opts[1] = val
ret[nss + 1] = ccs
ret[nss + 2] = ctx.frame:expandTemplate(model)
nss = nss + 2
end
)
if nss > 0 then
if nss > 2 and ctx.lastsep ~= nil then
ret[nss - 1] = ctx.lastsep
end
ret[1] = ctx.header or ''
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
ctx.text = table.concat(ret)
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
-- Syntax: #invoke:params|invoke_for_each_value|module name|[append 1]|[append
-- 2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param
-- n=value n]|[...]
library.invoke_for_each_value = function(ctx)
local opts = ctx.pipe
local mname
local fname
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
if mname == nil then error(ctx.luaname ..
', ‘invoke_for_each_value’: No module name was provided', 0) end
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
if fname == nil then error(ctx.luaname ..
', ‘invoke_for_each_value’: No function name was provided', 0) end
local model = { title = 'Module:' .. mname, args = opts }
local mfunc = require(model.title)[fname]
local ccs = ctx.itersep or ''
local ret = {}
local nss = 0
remove_numerical_keys(opts, 1, 1)
flush_params(
ctx,
function(key, val)
opts[1] = val
ret[nss + 1] = ccs
ret[nss + 2] = mfunc(ctx.frame:newChild(model))
nss = nss + 2
end
)
if nss > 0 then
if nss > 2 and ctx.lastsep ~= nil then
ret[nss - 1] = ctx.lastsep
end
ret[1] = ctx.header or ''
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
ctx.text = table.concat(ret)
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
-- Syntax: #invoke:params|magic_for_each_value|parser function|[append 1]
-- |[append 2]|[...]|[append n]|[named param 1=value 1]|[...]|[named
-- param n=value n]|[...]
library.magic_for_each_value = function(ctx)
local opts = ctx.pipe
local magic
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end
if magic == nil then error(ctx.luaname ..
', ‘magic_for_each_value’: No parser function was provided', 0) end
local ccs = ctx.itersep or ''
local ret = {}
local nss = 0
flush_params(
ctx,
function(key, val)
opts[1] = val
ret[nss + 1] = ccs
ret[nss + 2] = ctx.frame:callParserFunction(magic,
opts)
nss = nss + 2
end
)
if nss > 0 then
if nss > 2 and ctx.lastsep ~= nil then
ret[nss - 1] = ctx.lastsep
end
ret[1] = ctx.header or ''
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
ctx.text = table.concat(ret)
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
-- Syntax: #invoke:params|call_for_each_group|template name|[append 1]|[append
-- 2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param
-- n=value n]|[...]
library.call_for_each_group = function(ctx)
-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!
local opts = ctx.pipe
local tmp
if opts[1] ~= nil then tmp = opts[1]:match'^%s*(.*%S)' end
if tmp == nil then error(ctx.luaname ..
', ‘call_for_each_group’: No template name was provided', 0) end
local model = { title = tmp }
local ccs = ctx.itersep or ''
local nss = 0
local prefix
local gid
local groups = {}
local ret = {}
opts = {}
for key, val in pairs(ctx.pipe) do
if type(key) == 'number' then opts[key - 1] = val
else opts[key] = val end
end
ctx.pipe = opts
for key, val in pairs(ctx.params) do
prefix, gid = tostring(key):match'^%s*(.-)%s*(%-?%d*)%s*$'
gid = tonumber(gid) or ''
if groups[gid] == nil then groups[gid] = {} end
tmp = tonumber(prefix)
if tmp ~= nil then
if tmp < 1 then prefix = tmp - 1 else prefix = tmp end
end
groups[gid][prefix] = val
end
ctx.params = groups
flush_params(
ctx,
function(gid, group)
for key, val in pairs(opts) do group[key] = val end
group[0] = gid
model.args = group
ret[nss + 1] = ccs
ret[nss + 2] = ctx.frame:expandTemplate(model)
nss = nss + 2
end
)
if nss > 0 then
if nss > 2 and ctx.lastsep ~= nil then
ret[nss - 1] = ctx.lastsep
end
ret[1] = ctx.header or ''
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
ctx.text = table.concat(ret)
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
--- ---
--- PUBLIC ENVIRONMENT ---
--- ________________________________ ---
--- ---
--[[ First-position-only modifiers ]]--
---------------------------------------
-- Syntax: #invoke:params|new|pipe to
--[[
static_iface.new = function(frame)
local ctx = context_new()
ctx.frame = frame:getParent()
ctx.pipe = copy_or_ref_table(frame.args, false)
ctx.params = {}
main_loop(ctx, context_iterate(ctx, 1))
return ctx.text
end
]]--
--[[ First-position-only functions ]]--
---------------------------------------
-- Syntax: #invoke:params|self
static_iface.self = function(frame)
return frame:getParent():getTitle()
end
--[[ Public metatable of functions ]]--
---------------------------------------
return setmetatable(static_iface, {
__index = function(iface, _fname_)
local ctx = context_new()
local fname = _fname_:match'^%s*(.*%S)'
if fname == nil then error(ctx.luaname ..
': You must specify a function to call', 0) end
if library[fname] == nil then error(ctx.luaname ..
': The function ‘' .. fname .. '’ does not exist', 0) end
return function(frame)
local func = library[fname]
local refpipe = {
count = true,
value_of = true,
list = true,
list_values = true,
for_each = true,
call_for_each_group = true
}
local refparams = {
--inserting = true,
count = true,
concat_and_call = true,
concat_and_invoke = true,
concat_and_magic = true,
value_of = true,
call_for_each_group = true
}
ctx.frame = frame:getParent()
ctx.pipe = copy_or_ref_table(frame.args, refpipe[fname])
ctx.params = copy_or_ref_table(ctx.frame.args, refparams[fname])
main_loop(ctx, func)
return ctx.text
end
end
})