模組:Arguments/doc

这是Module:Arguments的文档页面
![]() | 此頁面是Module:Arguments的模块文档。 此頁面可能包含了模板的使用說明、分類和其他内容。 |
![]() | 此模块文档被引用於約4,180,000個頁面,佔全部頁面的52%。 為了避免造成大規模的影響,所有對此模块文档的編輯應先於沙盒或測試樣例上測試。 測試後無誤的版本可以一次性地加入此模块文档中,但是修改前請務必於討論頁發起討論。 模板引用數量會自動更新。 |
![]() | 此模块的文档不存在、不全面或不能详细描述其功能及/或其代码中的参数。请帮助扩充并改进其文档。 |
此模块提供了对通过{{#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
但实践中,最好先用专门的函数(指变量p
的一个域值,如下文中的p._main)来处理一个特定的参数表(lua的表,与#invoke无关),然后用另一个函数(如下文中的p.main)调用这个函数,并将调用#invoke时传用的参数(即下文中的getArgs(frame))作为调用这个函数时的参数。这样,其他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)
-- 主模块放这儿,这里的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:A wrapper template',
'Template:Another wrapper 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
函数都会迟早调用。So if you care about performance you should make sure you aren't doing anything inefficient with your code.
框架与父框架
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}}
。There is no point in checking the arguments passed directly to the #invoke statement for this template, as no arguments will ever be specified there. 我们可以通过parentOnly选项避免检查传递到#invoke的参数,但如果这样做,#invoke也不会从其他页面起作用。如果是这样,代码{{#invoke:Side box|main|text=Some text}}
中的|text=Some text
会直接忽略,无论是从哪个页面使用的。使用wrappers
选项以指定“Template:Side box”为包装,我们可以使得{{#invoke:Side box|main|text=Some 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 tags
This module uses metatables to fetch arguments from #invoke. This allows access to both the frame arguments and the parent frame arguments without using the pairs()
function. This can help if your module might be passed <ref>...</ref>
tags as input.
As soon as <ref>...</ref>
tags are accessed from Lua, they are processed by the MediaWiki software and the reference will appear in the reference list at the bottom of the article. If your module proceeds to omit the reference tag from the output, you will end up with a phantom reference - a reference that appears in the reference list, but no number that links to it. This has been a problem with modules that use pairs()
to detect whether to use the arguments from the frame or the parent frame, as those modules automatically process every available argument.
This module solves this problem by allowing access to both frame and parent frame arguments, while still only fetching those arguments when it is necessary. The problem will still occur if you use pairs(args)
elsewhere in your module, however.
已知限制
元表(metatable)的使用也有其缺点。大多数正常Lua表工具都不会对args表正常工作,包括#
操作符号、next()
函数和表库(table library)中的函数。如果这对你的模块重要,你需要使用你自己的用来处理参数的函数,而不是这个模块。