Module:Params: Difference between revisions
From All Skies Encyclopaedia
imported>Grufo m (Comments only) |
imported>Grufo (Extend the logic of `with_name_matching`, `with_name_not_matching`, `with_value_matching` and `with_value_not_matching`; minor code review) |
||
Line 3: | Line 3: | ||
--- ________________________________ --- |
--- ________________________________ --- |
||
--- --- |
--- --- |
||
-- Special user-given keywords (function names MUST avoid these names) |
|||
local mkeywords = { |
|||
-- ['pattern'] = false, |
|||
['plain'] = true, |
|||
['or'] = 0 |
|||
} |
|||
Line 46: | Line 54: | ||
end |
end |
||
if nextfn == nil then |
if nextfn == nil then |
||
error(' |
error('No function name was given', 0) |
||
end |
end |
||
if library[nextfn] == nil then |
if library[nextfn] == nil then |
||
Line 119: | Line 127: | ||
end |
end |
||
for key, val in pairs(tbl) do fn(key, val) end |
for key, val in pairs(tbl) do fn(key, val) end |
||
end |
|||
-- Parse the arguments of the `with_*_matching` class of modifiers |
|||
local function parse_match_args(opts, ptns, fname) |
|||
local state = 0 |
|||
local cnt = 1 |
|||
local keyw |
|||
for _, val in ipairs(opts) do |
|||
if state == 0 then |
|||
ptns[#ptns + 1] = { val, false } |
|||
state = -1 |
|||
else |
|||
keyw = val:match'^%s*(.*%S)' |
|||
if keyw == nil or mkeywords[keyw] == nil then break |
|||
else |
|||
state = mkeywords[keyw] |
|||
if state ~= 0 then ptns[#ptns][2] = state end |
|||
end |
|||
end |
|||
cnt = cnt + 1 |
|||
end |
|||
if state == 0 then error(fname .. ': No pattern was given', 0) end |
|||
return cnt |
|||
end |
end |
||
Line 129: | Line 161: | ||
-- See iface.sequential() |
-- See iface.sequential() |
||
library.sequential = function(ctx) |
library.sequential = function(ctx) |
||
if ctx.subset == -1 then error('The two directives "non-sequential" and "sequential" are in contradiction with each other', 0) end |
|||
if ctx.subset == -1 then |
|||
if ctx.dosort then error('The "all_sorted" directive is redundant when followed by "sequential"', 0) end |
|||
error('The two directives "non-sequential" and "sequential" are in contradiction with each other', 0) |
|||
end |
|||
if ctx.dosort then |
|||
error('The "all_sorted" directive is redundant when followed by "sequential"', 0) |
|||
end |
|||
ctx.iterfunc = ipairs |
ctx.iterfunc = ipairs |
||
ctx.subset = 1 |
ctx.subset = 1 |
||
Line 143: | Line 171: | ||
-- See iface['non-sequential']() |
-- See iface['non-sequential']() |
||
library['non-sequential'] = function(ctx) |
library['non-sequential'] = function(ctx) |
||
if ctx.subset == 1 then error('The two directives "sequential" and "non-sequential" are in contradiction with each other', 0) end |
|||
if ctx.subset == 1 then |
|||
error('The two directives "sequential" and "non-sequential" are in contradiction with each other', 0) |
|||
end |
|||
ctx.iterfunc = pairs |
ctx.iterfunc = pairs |
||
ctx.subset = -1 |
ctx.subset = -1 |
||
Line 154: | Line 180: | ||
-- See iface.all_sorted() |
-- See iface.all_sorted() |
||
library.all_sorted = function(ctx) |
library.all_sorted = function(ctx) |
||
if ctx.subset == 1 then |
if ctx.subset == 1 then error('The "all_sorted" directive is redundant after "sequential"', 0) end |
||
error('The "all_sorted" directive is redundant after "sequential"', 0) |
|||
end |
|||
ctx.dosort = true |
ctx.dosort = true |
||
return context_iterate(ctx, 1) |
return context_iterate(ctx, 1) |
||
Line 169: | Line 193: | ||
cmd = opts[1]:gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])' |
cmd = opts[1]:gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])' |
||
end |
end |
||
if cmd == nil then error('No directive was given', 0) end |
if cmd == nil then error('setting: No directive was given', 0) end |
||
local sep = string.byte('/') |
local sep = string.byte('/') |
||
local argc = 2 |
local argc = 2 |
||
Line 185: | Line 209: | ||
else |
else |
||
vname = memoryslots[string.char(chr)] |
vname = memoryslots[string.char(chr)] |
||
if vname == nil then error('Unknown slot "' .. |
if vname == nil then error('setting: Unknown slot "' .. |
||
string.char(chr) .. '"', 0) end |
string.char(chr) .. '"', 0) end |
||
table.insert(dest, vname) |
table.insert(dest, vname) |
||
Line 216: | Line 240: | ||
library.cutting = function(ctx) |
library.cutting = function(ctx) |
||
local lcut = tonumber(ctx.pipe[1]) |
local lcut = tonumber(ctx.pipe[1]) |
||
if lcut == nil then error('Left cut must be a number', 0) end |
if lcut == nil then error('cutting: Left cut must be a number', 0) end |
||
local rcut = tonumber(ctx.pipe[2]) |
local rcut = tonumber(ctx.pipe[2]) |
||
if rcut == nil then error('Right cut must be a number', 0) end |
if rcut == nil then error('cutting: Right cut must be a number', 0) end |
||
local tbl = ctx.params |
local tbl = ctx.params |
||
local len = #tbl |
local len = #tbl |
||
Line 251: | Line 275: | ||
-- See iface.with_name_matching() |
-- See iface.with_name_matching() |
||
library.with_name_matching = function(ctx) |
library.with_name_matching = function(ctx) |
||
local ptn = ctx.pipe[1] |
|||
local tbl = ctx.params |
local tbl = ctx.params |
||
local patterns = {} |
|||
for key, val in pairs(tbl) do |
|||
local argc = parse_match_args(ctx.pipe, patterns, 'with_name_matching') |
|||
if not string.find(key, ptn, 1, false) then tbl[key] = nil end |
|||
local nomatch |
|||
for key in pairs(tbl) do |
|||
nomatch = true |
|||
for _, ptn in ipairs(patterns) do |
|||
if string.find(key, ptn[1], 1, ptn[2]) then |
|||
nomatch = false |
|||
break |
|||
end |
|||
end |
|||
if nomatch then tbl[key] = nil end |
|||
end |
end |
||
return context_iterate(ctx, |
return context_iterate(ctx, argc) |
||
end |
end |
||
Line 262: | Line 295: | ||
-- See iface.with_name_not_matching() |
-- See iface.with_name_not_matching() |
||
library.with_name_not_matching = function(ctx) |
library.with_name_not_matching = function(ctx) |
||
local ptn = ctx.pipe[1] |
|||
local tbl = ctx.params |
local tbl = ctx.params |
||
local patterns = {} |
|||
for key, val in pairs(tbl) do |
|||
local argc = parse_match_args(ctx.pipe, patterns, |
|||
if string.find(key, ptn, 1, false) then tbl[key] = nil end |
|||
'with_name_not_matching') |
|||
local yesmatch |
|||
for key in pairs(tbl) do |
|||
yesmatch = true |
|||
for _, ptn in ipairs(patterns) do |
|||
if not string.find(key, ptn[1], 1, ptn[2]) then |
|||
yesmatch = false |
|||
break |
|||
end |
|||
end |
|||
if yesmatch then tbl[key] = nil end |
|||
end |
end |
||
return context_iterate(ctx, |
return context_iterate(ctx, argc) |
||
end |
end |
||
Line 273: | Line 316: | ||
-- See iface.with_value_matching() |
-- See iface.with_value_matching() |
||
library.with_value_matching = function(ctx) |
library.with_value_matching = function(ctx) |
||
local ptn = ctx.pipe[1] |
|||
local tbl = ctx.params |
local tbl = ctx.params |
||
local patterns = {} |
|||
local argc = parse_match_args(ctx.pipe, patterns, |
|||
'with_value_matching') |
|||
local nomatch |
|||
for key, val in pairs(tbl) do |
for key, val in pairs(tbl) do |
||
nomatch = true |
|||
if not string.find(val, ptn, 1, false) then tbl[key] = nil end |
|||
for _, ptn in ipairs(patterns) do |
|||
if string.find(val, ptn[1], 1, ptn[2]) then |
|||
nomatch = false |
|||
break |
|||
end |
|||
end |
|||
if nomatch then tbl[key] = nil end |
|||
end |
end |
||
return context_iterate(ctx, |
return context_iterate(ctx, argc) |
||
end |
end |
||
Line 284: | Line 337: | ||
-- See iface.with_value_not_matching() |
-- See iface.with_value_not_matching() |
||
library.with_value_not_matching = function(ctx) |
library.with_value_not_matching = function(ctx) |
||
local ptn = ctx.pipe[1] |
|||
local tbl = ctx.params |
local tbl = ctx.params |
||
local patterns = {} |
|||
local argc = parse_match_args(ctx.pipe, patterns, |
|||
'with_value_not_matching') |
|||
local yesmatch |
|||
for key, val in pairs(tbl) do |
for key, val in pairs(tbl) do |
||
yesmatch = true |
|||
if string.find(val, ptn, 1, false) then tbl[key] = nil end |
|||
for _, ptn in ipairs(patterns) do |
|||
if not string.find(val, ptn[1], 1, ptn[2]) then |
|||
yesmatch = false |
|||
break |
|||
end |
|||
end |
|||
if yesmatch then tbl[key] = nil end |
|||
end |
end |
||
return context_iterate(ctx, |
return context_iterate(ctx, argc) |
||
end |
end |
||
Line 317: | Line 380: | ||
-- See iface.concat_and_call() |
-- See iface.concat_and_call() |
||
library.concat_and_call = function(ctx) |
library.concat_and_call = function(ctx) |
||
local opts = ctx.pipe |
local opts = ctx.pipe |
||
local tname |
local tname |
||
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end |
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end |
||
if tname == nil then error('No template name was provided', 0) end |
if tname == nil then error('concat_and_call: No template name was provided', 0) end |
||
table.remove(opts, 1) |
table.remove(opts, 1) |
||
return ctx.frame:expandTemplate{ |
return ctx.frame:expandTemplate{ |
||
title = tname, |
title = tname, |
||
args = concat_params(ctx) |
args = concat_params(ctx) |
||
} |
} |
||
end |
end |
||
Line 336: | Line 394: | ||
-- See iface.concat_and_invoke() |
-- See iface.concat_and_invoke() |
||
library.concat_and_invoke = function(ctx) |
library.concat_and_invoke = function(ctx) |
||
local opts = ctx.pipe |
local opts = ctx.pipe |
||
local mname |
local mname |
||
local fname |
local fname |
||
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end |
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end |
||
if mname == nil then error('No module name was provided', 0) end |
if mname == nil then error('concat_and_invoke: No module name was provided', 0) end |
||
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end |
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end |
||
if fname == nil then error('No function name was provided', 0) end |
if fname == nil then error('concat_and_invoke: No function name was provided', 0) end |
||
table.remove(opts, 2) |
table.remove(opts, 2) |
||
table.remove(opts, 1) |
table.remove(opts, 1) |
||
return require('Module:' .. mname)[fname](ctx.frame:newChild{ |
return require('Module:' .. mname)[fname](ctx.frame:newChild{ |
||
title = 'Module:' .. fname, |
title = 'Module:' .. fname, |
||
args = concat_params(ctx) |
args = concat_params(ctx) |
||
}) |
}) |
||
end |
end |
||
Line 362: | Line 415: | ||
local keystr |
local keystr |
||
if opts[1] ~= nil then keystr = opts[1]:match'^%s*(.*%S)' end |
if opts[1] ~= nil then keystr = opts[1]:match'^%s*(.*%S)' end |
||
if keystr == nil then error('No parameter name was provided', 0) end |
if keystr == nil then error('value_of: No parameter name was provided', 0) end |
||
local keynum = tonumber(keystr) |
local keynum = tonumber(keystr) |
||
if ( |
if ( |
||
Line 445: | Line 498: | ||
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end |
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end |
||
if tname == nil then error('No template name was provided', 0) end |
if tname == nil then error('call_for_each: No template name was provided', 0) end |
||
local ccs = ctx.itersep or '' |
local ccs = ctx.itersep or '' |
||
Line 480: | Line 533: | ||
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end |
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end |
||
if mname == nil then error('No module name was provided', 0) end |
if mname == nil then error('invoke_for_each: No module name was provided', 0) end |
||
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end |
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end |
||
if fname == nil then error('No function name was provided', 0) end |
if fname == nil then error('invoke_for_each: No function name was provided', 0) end |
||
local ccs = ctx.itersep or '' |
local ccs = ctx.itersep or '' |
||
Line 515: | Line 568: | ||
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end |
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end |
||
if magic == nil then error('No parser function was provided', 0) end |
if magic == nil then error('magic_for_each: No parser function was provided', 0) end |
||
local ccs = ctx.itersep or '' |
local ccs = ctx.itersep or '' |
||
Line 548: | Line 601: | ||
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end |
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end |
||
if tname == nil then error('No template name was provided', 0) end |
if tname == nil then error('call_for_each_value: No template name was provided', 0) end |
||
local ccs = ctx.itersep or '' |
local ccs = ctx.itersep or '' |
||
Line 580: | Line 633: | ||
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end |
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end |
||
if mname == nil then error('No module name was provided', 0) end |
if mname == nil then error('invoke_for_each_value: No module name was provided', 0) end |
||
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end |
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end |
||
if fname == nil then error('No function name was provided', 0) end |
if fname == nil then error('invoke_for_each_value: No function name was provided', 0) end |
||
local ccs = ctx.itersep or '' |
local ccs = ctx.itersep or '' |
||
Line 616: | Line 669: | ||
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end |
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end |
||
if magic == nil then error('No parser function was provided', 0) end |
if magic == nil then error('magic_for_each_value: No parser function was provided', 0) end |
||
local ccs = ctx.itersep or '' |
local ccs = ctx.itersep or '' |
||
Line 628: | Line 681: | ||
function(key, val) |
function(key, val) |
||
opts[1] = val |
opts[1] = val |
||
ret = ret .. sep .. ctx.frame:callParserFunction(magic, |
ret = ret .. sep .. ctx.frame:callParserFunction(magic, |
||
opts) |
|||
sep = ccs |
sep = ccs |
||
foo = las |
foo = las |
||
Line 691: | Line 745: | ||
-- Syntax: #invoke:params|with_name_matching|pattern| |
-- Syntax: #invoke:params|with_name_matching|pattern 1|[plain flag 1]|[or] |
||
-- |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag |
|||
-- N]|function name |
|||
iface.with_name_matching = function(frame) |
iface.with_name_matching = function(frame) |
||
return context_init(frame, library.with_name_matching, false, false) |
return context_init(frame, library.with_name_matching, false, false) |
||
Line 697: | Line 753: | ||
-- Syntax: #invoke:params|with_name_not_matching|pattern| |
-- Syntax: #invoke:params|with_name_not_matching|pattern 1|[plain flag 1] |
||
-- |[and]|[pattern 2]|[plain flag 2]|[and]|[...]|[pattern N]|[plain |
|||
-- flag N]|function name |
|||
iface.with_name_not_matching = function(frame) |
iface.with_name_not_matching = function(frame) |
||
return context_init(frame, library.with_name_not_matching, false, |
return context_init(frame, library.with_name_not_matching, false, |
||
false) |
|||
end |
end |
||
-- Syntax: #invoke:params|with_value_matching|pattern| |
-- Syntax: #invoke:params|with_value_matching|pattern 1|[plain flag 1]|[or] |
||
-- |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag |
|||
-- N]|function name |
|||
iface.with_value_matching = function(frame) |
iface.with_value_matching = function(frame) |
||
return context_init(frame, library.with_value_matching, false, false) |
return context_init(frame, library.with_value_matching, false, false) |
||
Line 709: | Line 770: | ||
-- Syntax: #invoke:params|with_value_not_matching|pattern| |
-- Syntax: #invoke:params|with_value_not_matching|pattern 1|[plain flag 1] |
||
-- |[and]|[pattern 2]|[plain flag 2]|[and]|[...]|[pattern N]|[plain |
|||
-- flag N]|function name |
|||
iface.with_value_not_matching = function(frame) |
iface.with_value_not_matching = function(frame) |
||
return context_init(frame, library.with_value_not_matching, false, |
return context_init(frame, library.with_value_not_matching, false, |
||
false) |
|||
end |
end |
||
Revision as of 00:51, 20 July 2023
Documentation for this module may be created at Module:Params/doc
--- ---
--- LOCAL ENVIRONMENT ---
--- ________________________________ ---
--- ---
-- Special user-given keywords (function names MUST avoid these names)
local mkeywords = {
-- ['pattern'] = false,
['plain'] = true,
['or'] = 0
}
-- Set directives
local memoryslots = {
i = 'itersep',
p = 'pairsep',
h = 'header',
f = 'footer',
n = 'ifngiven'
}
-- The private table of functions
local library = {}
-- 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
-- Prepare the context
local function context_init(frame, funcname, refpipe, refparams)
local ctx = {}
ctx.iterfunc = pairs
ctx.pipe = copy_or_ref_table(frame.args, refpipe)
ctx.frame = frame:getParent()
ctx.params = copy_or_ref_table(ctx.frame.args, refparams)
return funcname(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('No function name was given', 0)
end
if library[nextfn] == nil then
error('The function "' .. nextfn .. '" does not exist', 0)
end
for idx = n_forward, 1, -1 do table.remove(ctx.pipe, idx) end
return library[nextfn](ctx)
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 shift = table.maxn(ctx.pipe)
local newargs = {}
if ctx.subset == 1 then
-- We need only the sequence
for key, val in ipairs(ctx.params) do
newargs[key + shift] = val
end
else
if ctx.subset == -1 then
for key, val in ipairs(ctx.params) do
ctx.params[key] = nil
end
end
for key, val in pairs(ctx.params) do
if type(key) == 'number' then
newargs[key + shift] = val
else
newargs[key] = val
end
end
end
for key, val in pairs(ctx.pipe) do newargs[key] = val end
return newargs
end
local function do_for_each_param(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 = {}
for key, val in pairs(tbl) do
if type(key) == 'number' then
nums[#nums + 1] = key
else
words[#words + 1] = key
end
end
table.sort(nums)
table.sort(words)
for idx = 1, #nums do fn(nums[idx], tbl[nums[idx]]) end
for idx = 1, #words 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
-- Parse the arguments of the `with_*_matching` class of modifiers
local function parse_match_args(opts, ptns, fname)
local state = 0
local cnt = 1
local keyw
for _, val in ipairs(opts) do
if state == 0 then
ptns[#ptns + 1] = { val, false }
state = -1
else
keyw = val:match'^%s*(.*%S)'
if keyw == nil or mkeywords[keyw] == nil then break
else
state = mkeywords[keyw]
if state ~= 0 then ptns[#ptns][2] = state end
end
end
cnt = cnt + 1
end
if state == 0 then error(fname .. ': No pattern was given', 0) end
return cnt
end
--[[ Piped modifiers ]]--
--------------------------------
-- See iface.sequential()
library.sequential = function(ctx)
if ctx.subset == -1 then error('The two directives "non-sequential" and "sequential" are in contradiction with each other', 0) end
if ctx.dosort then error('The "all_sorted" directive is redundant when followed by "sequential"', 0) end
ctx.iterfunc = ipairs
ctx.subset = 1
return context_iterate(ctx, 1)
end
-- See iface['non-sequential']()
library['non-sequential'] = function(ctx)
if ctx.subset == 1 then error('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
-- See iface.all_sorted()
library.all_sorted = function(ctx)
if ctx.subset == 1 then error('The "all_sorted" directive is redundant after "sequential"', 0) end
ctx.dosort = true
return context_iterate(ctx, 1)
end
-- See iface.setting()
library.setting = function(ctx)
local opts = ctx.pipe
local cmd
if opts[1] ~= nil then
cmd = opts[1]:gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])'
end
if cmd == nil then error('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('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
-- See iface.squeezing()
library.squeezing = function(ctx)
local tbl = ctx.params
local store = {}
local indices = {}
for key, val in pairs(tbl) do
if type(key) == 'number' then
indices[#indices + 1] = key
store[key] = val
tbl[key] = nil
end
end
table.sort(indices)
for idx = 1, #indices do tbl[idx] = store[indices[idx]] end
return context_iterate(ctx, 1)
end
-- See iface.cutting()
library.cutting = function(ctx)
local lcut = tonumber(ctx.pipe[1])
if lcut == nil then error('cutting: Left cut must be a number', 0) end
local rcut = tonumber(ctx.pipe[2])
if rcut == nil then error('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, val 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
-- See iface.with_name_matching()
library.with_name_matching = function(ctx)
local tbl = ctx.params
local patterns = {}
local argc = parse_match_args(ctx.pipe, patterns, 'with_name_matching')
local nomatch
for key in pairs(tbl) do
nomatch = true
for _, ptn in ipairs(patterns) do
if string.find(key, 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
-- See iface.with_name_not_matching()
library.with_name_not_matching = function(ctx)
local tbl = ctx.params
local patterns = {}
local argc = parse_match_args(ctx.pipe, patterns,
'with_name_not_matching')
local yesmatch
for key in pairs(tbl) do
yesmatch = true
for _, ptn in ipairs(patterns) do
if 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
-- See iface.with_value_matching()
library.with_value_matching = function(ctx)
local tbl = ctx.params
local patterns = {}
local argc = parse_match_args(ctx.pipe, patterns,
'with_value_matching')
local nomatch
for key, val in pairs(tbl) do
nomatch = true
for _, ptn in ipairs(patterns) do
if 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
-- See iface.with_value_not_matching()
library.with_value_not_matching = function(ctx)
local tbl = ctx.params
local patterns = {}
local argc = parse_match_args(ctx.pipe, patterns,
'with_value_not_matching')
local yesmatch
for key, val in pairs(tbl) do
yesmatch = true
for _, ptn in ipairs(patterns) do
if 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
-- See iface.trimming_values()
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
--[[ Piped functions ]]--
------------------------------------
-- See iface.count()
library.count = function(ctx)
local count = 0
for _ in ctx.iterfunc(ctx.params) do count = count + 1 end
if ctx.subset == -1 then count = count - #ctx.params end
return count
end
-- See iface.concat_and_call()
library.concat_and_call = 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('concat_and_call: No template name was provided', 0) end
table.remove(opts, 1)
return ctx.frame:expandTemplate{
title = tname,
args = concat_params(ctx)
}
end
-- See iface.concat_and_invoke()
library.concat_and_invoke = 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('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('concat_and_invoke: No function name was provided', 0) end
table.remove(opts, 2)
table.remove(opts, 1)
return require('Module:' .. mname)[fname](ctx.frame:newChild{
title = 'Module:' .. fname,
args = concat_params(ctx)
})
end
-- See iface.value_of()
library.value_of = function(ctx)
local opts = ctx.pipe
local keystr
if opts[1] ~= nil then keystr = opts[1]:match'^%s*(.*%S)' end
if keystr == nil then error('value_of: No parameter name was provided', 0) end
local keynum = tonumber(keystr)
if (
ctx.subset == -1 and keynum ~= nil and #ctx.params >= keynum
) or (
ctx.subset == 1 and (keynum == nil or #ctx.params < keynum)
) then return (ctx.ifngiven or '') end
local val = ctx.params[keynum or keystr]
if val == nil then return (ctx.ifngiven or '') end
return (ctx.header or '') .. val .. (ctx.footer or '')
end
-- See iface.list()
library.list = function(ctx)
local pps = ctx.itersep or ''
local kvs = ctx.pairsep or ''
local sep = ctx.header or ''
local las = ctx.footer or ''
local foo = ctx.ifngiven or ''
local ret = ''
do_for_each_param(
ctx,
function(key, val)
ret = ret .. sep .. key .. kvs .. val
sep = pps
foo = las
end
)
return ret .. foo
end
-- See iface.list_values()
library.list_values = function(ctx)
local pps = ctx.itersep or ''
local sep = ctx.header or ''
local las = ctx.footer or ''
local foo = ctx.ifngiven or ''
local ret = ''
do_for_each_param(
ctx,
function(key, val)
ret = ret .. sep .. val
sep = pps
foo = las
end
)
return ret .. foo
end
-- See iface.for_each()
library.for_each = function(ctx)
local pps = ctx.itersep or ''
local las = ctx.footer or ''
local sep = ctx.header or ''
local foo = ctx.ifngiven or ''
local txt = ctx.pipe[1] or ''
local ret = ''
do_for_each_param(
ctx,
function(key, val)
ret = ret .. sep .. string.gsub(
string.gsub(txt, '%$#', key),
'%$@',
val
)
sep = pps
foo = las
end
)
return ret .. foo
end
-- See iface.call_for_each()
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('call_for_each: No template name was provided', 0) end
local ccs = ctx.itersep or ''
local sep = ctx.header or ''
local las = ctx.footer or ''
local foo = ctx.ifngiven or ''
local model = { title = tname, args = opts }
local ret = ''
table.insert(opts, 1, true)
do_for_each_param(
ctx,
function(key, val)
opts[1] = key
opts[2] = val
ret = ret .. sep .. ctx.frame:expandTemplate(model)
sep = ccs
foo = las
end
)
return ret .. foo
end
-- See iface.invoke_for_each()
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('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('invoke_for_each: No function name was provided', 0) end
local ccs = ctx.itersep or ''
local sep = ctx.header or ''
local las = ctx.footer or ''
local foo = ctx.ifngiven or ''
local model = { title = 'Module:' .. mname, args = opts }
local mfunc = require(model.title)[fname]
local ret = ''
do_for_each_param(
ctx,
function(key, val)
opts[1] = key
opts[2] = val
ret = ret .. sep .. mfunc(ctx.frame:newChild(model))
sep = ccs
foo = las
end
)
return ret .. foo
end
-- See iface.magic_for_each()
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('magic_for_each: No parser function was provided', 0) end
local ccs = ctx.itersep or ''
local sep = ctx.header or ''
local las = ctx.footer or ''
local foo = ctx.ifngiven or ''
local ret = ''
table.insert(opts, 1, true)
do_for_each_param(
ctx,
function(key, val)
opts[1] = key
opts[2] = val
ret = ret .. sep .. ctx.frame:callParserFunction(magic, opts)
sep = ccs
foo = las
end
)
return ret .. foo
end
-- See iface.call_for_each_value()
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('call_for_each_value: No template name was provided', 0) end
local ccs = ctx.itersep or ''
local sep = ctx.header or ''
local las = ctx.footer or ''
local foo = ctx.ifngiven or ''
local model = { title = tname, args = opts }
local ret = ''
do_for_each_param(
ctx,
function(key, val)
opts[1] = val
ret = ret .. sep .. ctx.frame:expandTemplate(model)
sep = ccs
foo = las
end
)
return ret .. foo
end
-- See iface.invoke_for_each_value()
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('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('invoke_for_each_value: No function name was provided', 0) end
local ccs = ctx.itersep or ''
local sep = ctx.header or ''
local las = ctx.footer or ''
local foo = ctx.ifngiven or ''
local model = { title = 'Module:' .. mname, args = opts }
local mfunc = require(model.title)[fname]
local ret = ''
table.remove(opts, 1)
do_for_each_param(
ctx,
function(key, val)
opts[1] = val
ret = ret .. sep .. mfunc(ctx.frame:newChild(model))
sep = ccs
foo = las
end
)
return ret .. foo
end
-- See iface.magic_for_each_value()
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('magic_for_each_value: No parser function was provided', 0) end
local ccs = ctx.itersep or ''
local sep = ctx.header or ''
local las = ctx.footer or ''
local foo = ctx.ifngiven or ''
local ret = ''
do_for_each_param(
ctx,
function(key, val)
opts[1] = val
ret = ret .. sep .. ctx.frame:callParserFunction(magic,
opts)
sep = ccs
foo = las
end
)
return ret .. foo
end
--- ---
--- PUBLIC ENVIRONMENT ---
--- ________________________________ ---
--- ---
-- The public table of functions
local iface = {}
--[[ Non-piped modifiers ]]--
------------------------------------
-- Syntax: #invoke:params|sequential|function name
iface.sequential = function(frame)
return context_init(frame, library.sequential, false, false)
end
-- Syntax: #invoke:params|non-sequential|function name
iface['non-sequential'] = function(frame)
return context_init(frame, library['non-sequential'], false, false)
end
-- Syntax: #invoke:params|sort|function name
iface.all_sorted = function(frame)
return context_init(frame, library.all_sorted, false, false)
end
-- Syntax: #invoke:params|setting|directives|...|function name
iface.setting = function(frame)
return context_init(frame, library.setting, false, false)
end
-- Syntax: #invoke:params|squeezing|function name
iface.squeezing = function(frame)
return context_init(frame, library.squeezing, false, false)
end
-- Syntax: #invoke:params|cutting|left cut|right cut|function name
iface.cutting = function(frame)
return context_init(frame, library.cutting, false, false)
end
-- Syntax: #invoke:params|with_name_matching|pattern 1|[plain flag 1]|[or]
-- |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag
-- N]|function name
iface.with_name_matching = function(frame)
return context_init(frame, library.with_name_matching, false, false)
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]|function name
iface.with_name_not_matching = function(frame)
return context_init(frame, library.with_name_not_matching, false,
false)
end
-- Syntax: #invoke:params|with_value_matching|pattern 1|[plain flag 1]|[or]
-- |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag
-- N]|function name
iface.with_value_matching = function(frame)
return context_init(frame, library.with_value_matching, false, false)
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]|function name
iface.with_value_not_matching = function(frame)
return context_init(frame, library.with_value_not_matching, false,
false)
end
-- Syntax: #invoke:params|trimming_values|function name
iface.trimming_values = function(frame)
return context_init(frame, library.trimming_values, false, false)
end
--[[ Non-piped functions ]]--
----------------------------------------
-- Syntax: #invoke:params|count
iface.count = function(frame)
return context_init(frame, library.count, true, true)
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]|[...]
iface.concat_and_call = function(frame)
return context_init(frame, library.concat_and_call, false, true)
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]|[...]
iface.concat_and_invoke = function(frame)
return context_init(frame, library.concat_and_invoke, false, true)
end
-- Syntax: #invoke:params|value_of|parameter name
iface.value_of = function(frame)
return context_init(frame, library.value_of, true, true)
end
-- Syntax: #invoke:params|list
iface.list = function(frame)
return context_init(frame, library.list, true, false)
end
-- Syntax: #invoke:params|list_values
iface.list_values = function(frame)
return context_init(frame, library.list_values, true, false)
end
-- Syntax: #invoke:params|for_each|wikitext
iface.for_each = function(frame)
return context_init(frame, library.for_each, true, 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]|[...]
iface.call_for_each = function(frame)
return context_init(frame, library.call_for_each, false, 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]|[...]
iface.invoke_for_each = function(frame)
return context_init(frame, library.invoke_for_each, false, 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]|[...]
iface.magic_for_each = function(frame)
return context_init(frame, library.magic_for_each, false, 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]|[...]
iface.call_for_each_value = function(frame)
return context_init(frame, library.call_for_each_value, false, 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]|[...]
iface.invoke_for_each_value = function(frame)
return context_init(frame, library.invoke_for_each_value, false, 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]|[...]
iface.magic_for_each_value = function(frame)
return context_init(frame, library.magic_for_each_value, false, false)
end
return iface