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