Module:ArgRest
![]() | This module is rated as alpha. It is ready for third-party input, and may be used on a few pages to see if problems arise, but should be watched. Suggestions for new features or changes in their input and output mechanisms are welcome. |
This is an auxiliary module intended to be invoked by templates; it permits templates to support an arbitrary set of parameters by repeating a block of wikitext multiple times. This module works with named as well as unnamed parameters, can handle multiple named parameters at the same time, and supports defaults,
Usage
If you want to use this module in your template: take the block of wikitext that you want to be repeated for an arbitrary set of parameters, wrap it in <nowiki>
, and pass that as the module's first parameter; then, choose a "base" parameter such that the module will stop repeating the wikitext if the parameter wasn't defined by the user, and pass its name as the second parameter. Example usage:
...{{#invoke:ArgRest|main|<nowiki>...{{{named-2-a}}}...{{{named-2-b|default}}}...</nowiki>|named-2-a}}
Afterwards, the module will "fill in" parameters with larger numbers than the ones originally given; i.e. in the above example, the module would allow the containing template to receive parameters {{{named-3-a}}}
, {{{named-3-b}}}
, {{{named-4-a}}}
, etc.
Note: You MUST wrap the first parameter in <nowiki>
; otherwise, Mediawiki processes all wikitext and HTML syntax before the module receives it, which makes it impossible to use pattern matching due to the resulting pollution. If you do, the module will give this error:
- Lua error in Module:ArgRest at line 8: <nowiki> tags missing from first parameter.
Example
If the (imaginary) template {{PlusMinusLoop}} has the following code:
{{{plus1}}} - {{{minus1}}}{{#invoke:ArgRest|main|<nowiki> + {{plus2}}} - {{{minus2|5}}}</nowiki>|plus2}}
then
{{PlusMinusLoop|plus1{{{=}}}0|minus1{{{=}}}1|plus2{{{=}}}1|minus2{{{=}}}2|plus3{{{=}}}3|plus5{{{=}}}21}}
will yield 0 - 1 + 1 - 2 + 3 - 5
. The - 5
is present because |minus3
defaulted to 5, but 21
never appears because, although |plus5
is defined, |plus4
isn't, so the module halts there.
Helpful templates
There are a few templates that can used with this module to help it adapt to certain scenarios:
- {{Call wikitext}}: This template allows ArgRest to be demoed without the need to create a template.
- For example,
{{Call wikitext|sourceCode=<nowiki>{{#invoke:ArgRest|main|<nowiki>{{{1}}}</nowiki>|1}}</nowiki>|foo|bar}}
outputsfoofoo
.
- For example,
- {{Expand wikitext}}: If you try to use ArgRest to generate parameters inside of an outer template (e.g.
{{enum{{#invoke:ArgRest|main|<nowiki>|{{{1}}}</nowiki>|1}}}}
), it will fail to do so because the outer template won't get processed after ArgRest is done parsing. This template fixes this by invoking the parser to process the outer template.- For example, a template defined as
{{Expand wikitext|{{enum{{#invoke:ArgRest|main|<nowiki>|{{{1}}}</nowiki>|1}}}}}}
called with the arguments{{__TEMPLATE__|foo|bar|Baz}}
would outputTemplate:Enumfoofoofoo
where as one defined as{{enum{{#invoke:ArgRest|main|<nowiki>|{{{1}}}</nowiki>|1}}}}
would outputTemplate:Enumfoofoofoo
. - WARNING: ArgRest may become highly unstable if you use it this way, and is rather likely to not work as expected in these scenarios. If you do use it like this, heavy caution should be taken.
- For example, a template defined as
Note
Be wary when using ArgRest wrapped inside of an outer template; it hasn't quite been thoroughly tested in such scenarios, and should be watched carefully when it is used this way.
Limitations
This module currently suffers from a few limitations:
- It cannot handle aliases;
{{{parameter1| {{{alias1|default}}} }}}
will fail to be recognized by the module as a parameter. - It cannot handle parameters with names that contain two or more distinct numbers; the module's pattern matching is ignorant of this possibility, and will treat something like
{{{named-3-1}}}
as equivalent to{{{named-3-3}}}
. - It cannot handle multiple parameters that have different numbers; similarly to the above example, all numbers are converted by the module into the same number, so
...{{{1}}}...{{{2}}}...
won't work.
See also
- {{#invoke:params|with_name_matching}}, {{#invoke:params|for_each}}
- {{#invoke:for nowiki|template}}
- {{for nowiki}}
p = {}
--creates a frame object that cannot access any of the parent's args
--unless a table containing a list keys of not to inherit is provided
function disinherit(frame, onlyTheseKeys)
local parent = frame:getParent() or frame
local orphan = parent:newChild{}
orphan.getParent = parent.getParent --returns nil
orphan.args = {}
if onlyTheseKeys then
local family = {parent, frame}
for f = 1, 2 do
for k, v in pairs(family[f] and family[f].args or {}) do
orphan.args[k] = orphan.args[k] or v
end
end
parent.args = mw.clone(orphan.args)
setmetatable(orphan.args, nil)
for _, k in ipairs(onlyTheseKeys) do
rawset(orphan.args, k, nil)
end
end
return orphan, parent
end
function p.get(frame, arg, passArgs)
local orphan, frame = disinherit(frame, passArgs and {arg or 1})
local code, noWiki, preserve = frame.args[arg or 1] or ''
if code:match'nowiki' then
local placeholder, preserve = ('6'):char(), {}
code = mw.text.unstripNoWiki(code)
noWiki = code:gsub('%%', placeholder):gsub('<', '<'):gsub('>', '>')
for k in noWiki:gmatch('&.-;') do
if not preserve[k] then
preserve[k] = true
table.insert(preserve, (k:gsub('&', '&')))
noWiki = noWiki:gsub('(&.-;)', '%%%s')
end
end
noWiki = mw.text.nowiki(noWiki):format(unpack(preserve)):gsub(placeholder, '%%')
end
local kill_categories = frame.args.demo_kill_categories or frame.args.nocat
return {
source = noWiki or code,
output = orphan:preprocess(code):gsub(kill_categories and '%[%[Category.-%]%]' or '', ''),
frame = frame
}
end
function p.main(frame)
local show = demoTable or p.get(frame)
local args = show.frame.args
args.br = tonumber(args.br or 1) and ('<br>'):rep(args.br or 1) or args.br or ''
local wikitext = show.output
local secondParam = frame.args[2] or ''
local start = tonumber(secondParam:match('(%d+)')) -- Extract the first number from the second parameter
local result = ''
local function replaceTripleBraces(parameter, _, default) -- extract corresponding arguments from the parent function. the _ is necessary because the pipe still gets caught in the second group
return frame:getParent().args[parameter:gsub("%d+", tostring(i))] or default
end
for i = start, math.huge do
-- Check if the parameter is defined
if not frame:getParent().args[secondParam:gsub('%d+', tostring(i))] then
break
end
-- Locate template parameter syntax
local processed = wikitext:gsub("{{{([^{}<>|]+)(|?([^{}<>|]*)}}}", replaceTripleBraces)
result = result .. processed
end
return result
--return string.format('<pre%s>%s</pre>%s%s', args.style and string.format(" style='%s'", args.style) or '', show.source, args.br, show.output)
end
function p.module(frame)
local orphan, frame = disinherit(frame, {
'demo_template',
'demo_module',
'demo_module_func',
'demo_main',
'demo_br',
'demo_result_arg',
'demo_kill_categories',
'nocat'
})
local template = frame.args.demo_template and 'Template:'..frame.args.demo_template
local demoFunc = frame.args.demo_module_func or 'main\n'
local demoModule = require('Module:' .. frame.args.demo_module)[demoFunc:match('^%s*(.-)%s*$')]
frame.args.br, frame.args.result_arg = frame.args.demo_br, frame.args.demo_result_arg
local kill_categories = frame.args.demo_kill_categories or frame.args.nocat
if demoModule then
local named = {insert = function(self, ...) table.insert(self, ...) return self end}
local source = {insert = named.insert, '{{', frame.args.demo_template or frame.args.demo_module, '\n'}
if not template then
source:insert(2, '#invoke:'):insert(4, '|'):insert(5, demoFunc)
end
local insertNamed = #source + 1
for k, v in pairs(orphan.args) do
local nan, insert = type(k) ~= 'number', {v}
local target = nan and named or source
target:insert'|'
if nan then
target:insert(k):insert'=':insert'\n'
table.insert(insert, 1, #target)
end
target:insert(unpack(insert))
local nowiki = v:match('nowiki')
if nowiki or v:match('{{.-}}') then
orphan.args[k] = frame:preprocess(nowiki and mw.text.unstripNoWiki(v) or v)
end
end
source:insert'}}'
table.insert(source, insertNamed, table.concat(named))
return p.main(orphan, {
source = mw.text.encode(table.concat(source), "<>'|=~"),
output = tostring(demoModule(orphan)):gsub(kill_categories and '%[%[Category.-%]%]' or '', ''),
frame = frame
})
else
return "ERROR: Invalid module function: "..demoFunc
end
end
return p