Module:Arguments/doc
这是Module:Arguments的文档页面
此模块是调用其他模块的模块。
此模块提供了对通过{{#invoke:}}
(以下简称#invoke)传递参数的简单处理。这是元模块(meta-module),只能被其他模块使用,而不应被#invoke直接调用。其特性如下:
- 对参数的简易修整,移除空白参数。
- 参数可以在当前框架或父框架中同时传递。(具体见下)
- 参数可以直接通过其他Lua模块或调试控制台传递。
- 可自定义更多特性。
基本用法
首先,您需要通过require函数加载这个模块。这个模块包含了一个名为getArgs
的函数。
<syntaxhighlight lang="lua"> local getArgs = require('Module:Arguments').getArgs </syntaxhighlight>
最简单的方法是在使用getArgs函数。变量args
是包含#invoke参数的表(table)。(详见下文。)
<syntaxhighlight lang="lua">
local getArgs = require('Module:Arguments').getArgs
local p = {}
function p.main(frame) local args = getArgs(frame) -- 主要的模块放此处。 end
return p </syntaxhighlight>
最佳实践
最佳的做法是,先用专门的函数来处理来自#invoke的参数。这样,其他Lua模块直接调用该模块时,就无需再需要弄一个frame对象,从而提升性能,减小开销。
<syntaxhighlight lang="lua"> local getArgs = require('Module:Arguments').getArgs local p = {}
function p.main(frame) local args = getArgs(frame) -- 从#invoke中获得的参数 return p._main(args) end
function p._main(args) -- 主要模块放此处。 end
return p </syntaxhighlight>
多个函数
如果你需要多个函数使用这些参数,而且你希望这些函数可用于#invoke,你可以使用包装函数(wrapper function)。
<syntaxhighlight lang="lua"> local getArgs = require('Module:Arguments').getArgs
local p = {}
local function makeInvokeFunc(funcName) return function (frame) local args = getArgs(frame) return p[funcName](args) end end
p.func1 = makeInvokeFunc('_func1')
function p._func1(args) -- 第一个函数的代码。 end
p.func2 = makeInvokeFunc('_func2')
function p._func2(args) -- 第二个函数的代码。 end
return p </syntaxhighlight>
选项
你可以使用如下面这段代码所示的选项。这些选项会在下文中介绍。
<syntaxhighlight lang="lua"> local args = getArgs(frame, { trim = false, removeBlanks = false, valueFunc = function (key, value) -- 用于处理一个参数的函数的代码。 end, frameOnly = true, parentOnly = true, parentFirst = true, wrappers = { 'Template:一个包装模板', 'Template:另一个模板' }, readOnly = true, noOverwrite = true }) </syntaxhighlight>
修整参数和移除空白的参数
将模板转换为Lua的新手易在空白参数上犯错。在模板语法中,空白字符串和仅包含空白字符(whitespace,空格、换行等)的字符串被视为假(false)。然而,在Lua,空白字符串和只包含空白字符的字符串则会被视为真(true)。这就是说,如果你在写Lua模块时,不注意这些参数,你可能会把本想视为假的东西视为真。为了避免这种情况,这个模块默认会移除所有的空白参数。
类似地,空白字符在处理位置参数(positional arguments)时会发生问题。虽然来自#invoke的具名参数(named arguments)中的多余空白字符会被修整(trim),但是对一些位置参数仍然保留。大多数时候,多余的空白字符是不需要的,所以这个模块默认剔除这些空白字符。
然而,有时输入时又需要使用这些空白字符,或者需要保留空白参数。把某些模板准确地转化为模块时,可能有必要这么做。如果你需要这样,你可以将trim
和removeBlanks
参数设为false
。
<syntaxhighlight lang="lua"> local args = getArgs(frame, { trim = false, removeBlanks = false }) </syntaxhighlight>
对参数进行自定义格式化
有时,你需要移除某些空白参数,但是还有些空白参数又不想移除,或者,你需要将所有位置参数转化为小写字母。你可以使用valueFunc
选项。这个参数的值必须是一个接收两个参数key
和value
并且只返回一个值的函数,这个值是你在args
表中索引名为key
的域时得到的值。
例1:这个函数不会动第一个参数的空白字符,但是其他参数的空白字符会剔除并移除其他所有空白参数。 <syntaxhighlight lang="lua"> local args = getArgs(frame, { valueFunc = function (key, value) if key == 1 then return value elseif value then value = mw.text.trim(value) if value ~= then return value end end return nil end }) </syntaxhighlight>
例2:这个函数移除空白参数并将所有参数转化为小写字母,但是不会剔除位置参数的空白字符。 <syntaxhighlight lang="lua"> local args = getArgs(frame, { valueFunc = function (key, value) if not value then return nil end value = mw.ustring.lower(value) if mw.ustring.find(value, '%S') then return value end return nil end }) </syntaxhighlight>
注:如果传入了既不是字符串又不是空值(nil)的值,上面这个函数会失败。当你在你的模块的主函数使用getArgs
函数,而且那个函数被另一个Lua模块调用时,就可能出现此情况。这种情况下,你需要检查你输入的内容的类型(type)。如果你使用一个专门用于来自#invoke的参数的函数时,不会有这个问题,你如你有p.main
和p._main
函数,或者类似。
Template:Cot 例1: <syntaxhighlight lang="lua"> local args = getArgs(frame, { valueFunc = function (key, value) if key == 1 then return value elseif type(value) == 'string' then value = mw.text.trim(value) if value ~= then return value else return nil end else return value end end }) </syntaxhighlight>
例2: <syntaxhighlight lang="lua"> local args = getArgs(frame, { valueFunc = function (key, value) if type(value) == 'string' then value = mw.ustring.lower(value) if mw.ustring.find(value, '%S') then return value else return nil end else return value end end }) </syntaxhighlight> Template:Cob
而且,请注意,每次从args
表中请求参数时,都会调用valueFunc
函数,所以请留意性能,确保不要加入低效的代码。
框架与父框架
args
表中的参数可以从当前框架或父框架同时传递。这句话有点难懂,可以看下面的例子。假设我们有个称为模块:ExampleArgs
的模块,这个模块输出(print)前两个传入的位置参数。
Template:Cot <syntaxhighlight lang="lua"> local getArgs = require('Module:Arguments').getArgs local p = {}
function p.main(frame) local args = getArgs(frame) return p._main(args) end
function p._main(args) local first = args[1] or local second = args[2] or return first .. ' ' .. second end
return p </syntaxhighlight> Template:Cob
然后,模块:ExampleArgs
被模板:ExampleArgs
调用,模板:ExampleArgs
内容如下:{{#invoke:ExampleArgs|main|firstInvokeArg}}
。它会输出内容firstInvokeArg。
现在,如果我们调用模板:ExampleArgs
,其结果如下表所示:
代码 | 结果 |
---|---|
{{ExampleArgs}}
|
firstInvokeArg |
{{ExampleArgs|firstTemplateArg}}
|
firstInvokeArg |
{{ExampleArgs|firstTemplateArg|secondTemplateArg}}
|
firstInvokeArg secondTemplateArg |
有三个选项可以用来改变行为:frameOnly
、parentOnly
和parentFirst
。如果设置frameOnly
,那么只有从当前框架传入的参数可以被接受;如果设置 parentOnly
,那么只有从父框架传入的参数会被接受;如果你设置parentFirst
,那么当前框架和父框架的参数都会接受,但是父框架优先于当前框架。以下是对于模板:ExampleArgs
的结果:
- 设为frameOnly时
代码 | 结果 |
---|---|
{{ExampleArgs}}
|
firstInvokeArg |
{{ExampleArgs|firstTemplateArg}}
|
firstInvokeArg |
{{ExampleArgs|firstTemplateArg|secondTemplateArg}}
|
firstInvokeArg |
- 设为parentOnly时
代码 | 结果 |
---|---|
{{ExampleArgs}}
|
|
{{ExampleArgs|firstTemplateArg}}
|
firstTemplateArg |
{{ExampleArgs|firstTemplateArg|secondTemplateArg}}
|
firstTemplateArg secondTemplateArg |
- 设为parentFirst时
代码 | 结果 |
---|---|
{{ExampleArgs}}
|
firstInvokeArg |
{{ExampleArgs|firstTemplateArg}}
|
firstTemplateArg |
{{ExampleArgs|firstTemplateArg|secondTemplateArg}}
|
firstTemplateArg secondTemplateArg |
注意:
- 如果你同时设置了
frameOnly
和parentOnly
两个选项,模块将不会从#invoke获取任何参数。这显然不是你需要的。 - 有时,父框架可能无效,比如getArgs是从父框架传入的,而不是当前框架。这种情况下,只有框架参数会被使用(除非设置了parentOnly,那种情况下不会使用任何参数),而且
parentFirst
和frameOnly
选项都会没有效果。
包装
包装(wrapper)选项用于指定一部分模板作为包装模板(wrapper templates),也就是说,要调用模块的模板。如果模块检测到是被包装模板调用的,则只会检查父框架中的参数;否则,只检查传递到getArgs的框架的参数。这允许模块要么被#invoke调用,要么通过包装模板调用,而不会由于为每次参数寻找(argument lookup)同时检查框架和父框架而损失性能。
比如,Template:Side box的内容(除了Template:Tag标签内的)为{{#invoke:Side box|main}}
。检查直接传递到模板的#invoke语句的参数是没有道理的,因为这里没有指定参数。我们可以通过parentOnly选项避免检查传递到#invoke的参数,但如果这样做,#invoke也不会从其他页面起作用。如果是这样,代码{{#invoke:Side box|main|text=Some text}}
中的|text=Some text
会直接忽略,无论是从哪个页面使用的。使用wrappers
选项以指定“Template:Side box”为包装,我们可以使得{{#invoke:Side box|main|text=一些文本}}
能够从大多数页面使用,而不需要检查Template:Side box页面自身的参数。
容器可以指定为字符串,或字符串的数组。
<syntaxhighlight lang="lua"> local args = getArgs(frame, { wrappers = 'Template:Wrapper template' }) </syntaxhighlight>
<syntaxhighlight lang="lua">
local args = getArgs(frame, {
wrappers = {
'Template:Wrapper 1',
'Template:Wrapper 2',
-- 可以在此处添加多个包装模板。
}
})
</syntaxhighlight>
注意:
- 模块会自动检测是否是从包装模板的/sandbox子页面调用的,所以不需要清楚地指定沙盒页面。
- wrappers选项有效改变frameOnly和parentOnly的默认的选项。如果,比如,设置了wrappers时清楚地将parentOnly设为false,通过包装模板调用会导致同时加载框架和父框架的参数,尽管非经由包装模板的调用会导致只加载框架参数。
- 如果设置了wrappers但是没有可用的父框架,模块总是会从传递给
getArgs
的框架中得到参数。
写入参数表
有时给参数表写入新值会很有用。这可以通过此模块的默认设置实现。(然而,记住最好的代码风格是,将需要的参数表中的参数复制到一个新的表中。)
<syntaxhighlight lang="lua"> args.foo = '一些值' </syntaxhighlight>
可以带有readOnly
和noOverwrite
选项修改此行为。如果设置了readOnly
,则完全不可能将任何值写到参数表中。如果设置了noOverwrite
,则可以将新值添加到此表,但是如果需要重写从#invoke传递的任何参数则不可能添加值。
ref标签
模块使用元表以从#invoke中获取参数。这允许不使用pairs()
函数就获取框架参数和父框架参数。如果你需要将Template:Tag标签作为输入时,这会很有用。
Template:Tag标签是从Lua中获取的,因此会被MediaWiki软件处理,引用会在文章底部的参考文献列表中显示。如果模块继续从输出中省略索引标签,则会产生一个假引用 —— 在参考文献列表中显示,但是没有与之链接的数字。模块如果使用pairs()
来检测是否从框架或父框架中使用参数,就会出现此问题,因为这些模块会自动处理每一个可用变量。
此模块允许既获取框架又获取父框架而仅在需要时获取这些参数,从而解决此问题。然而,模块其他位置使用pairs(args)
时,仍会出现此问题。
已知限制
元表(metatable)的使用也有其缺点。大多数正常Lua表工具都不会对args表正常工作,包括#
操作符号、next()
函数和表库(table library)中的函数。如果这对你的模块重要,你需要使用你自己的用来处理参数的函数,而不是这个模块。