这是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),但是对一些位置参数仍然保留。大多数时候,多余的空白字符是不需要的,所以这个模块默认剔除这些空白字符。

然而,有时输入时又需要使用这些空白字符,或者需要保留空白参数。把某些模板准确地转化为模块时,可能有必要这么做。如果你需要这样,你可以将trimremoveBlanks参数设为false

local args = getArgs(frame, {
	trim = false,
	removeBlanks = false
})

对参数进行自定义格式化

编辑

有时,你需要移除某些空白参数,但是还有些空白参数又不想移除,或者,你需要将所有位置参数转化为小写字母。你可以使用valueFunc选项。这个参数的值必须是一个接收两个参数keyvalue并且只返回一个值的函数,这个值是你在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.mainp._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

有三个选项可以用来改变行为:frameOnlyparentOnlyparentFirst。如果设置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

注意:

  1. 如果你同时设置了frameOnlyparentOnly两个选项,模块将不会从#invoke获取任何参数。这显然不是你需要的。
  2. 有时,父框架可能无效,比如getArgs是从父框架传入的,而不是当前框架。这种情况下,只有框架参数会被使用(除非设置了parentOnly,那种情况下不会使用任何参数),而且parentFirstframeOnly选项都会没有效果。

包装

编辑

包装(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',
		-- 可以在此处添加多个包装模板。
	}
})

注意:

  1. 模块会自动检测是否是从包装模板的/sandbox子页面调用的,所以不需要清楚地指定沙盒页面。
  2. wrappers选项有效改变frameOnlyparentOnly的默认的选项。如果,比如,设置了wrappers时清楚地将parentOnly设为false,通过包装模板调用会导致同时加载框架和父框架的参数,尽管非经由包装模板的调用会导致只加载框架参数。
  3. 如果设置了wrappers但是没有可用的父框架,模块总是会从传递给getArgs的框架中得到参数。

写入参数表

编辑

有时给参数表写入新值会很有用。这可以通过此模块的默认设置实现。(然而,记住最好的代码风格是,将需要的参数表中的参数复制到一个新的表中。)

args.foo = '一些值'

可以带有readOnlynoOverwrite选项修改此行为。如果设置了readOnly,则完全不可能将任何值写到参数表中。如果设置了noOverwrite,则可以将新值添加到此表,但是如果需要重写从#invoke传递的任何参数则不可能添加值。

ref标签

编辑

模块使用元表以从#invoke中获取参数。这允许不使用pairs()函数就获取框架参数和父框架参数。如果你需要将<ref>...</ref>标签作为输入时,这会很有用。

<ref>...</ref>标签是从Lua中获取的,因此会被MediaWiki软件处理,引用会在文章底部的参考文献列表中显示。如果模块继续从输出中省略索引标签,则会产生一个假引用 —— 在参考文献列表中显示,但是没有与之链接的数字。模块如果使用pairs()来检测是否从框架或父框架中使用参数,就会出现此问题,因为这些模块会自动处理每一个可用变量。

此模块允许既获取框架又获取父框架而仅在需要时获取这些参数,从而解决此问题。然而,模块其他位置使用pairs(args)时,仍会出现此问题。

已知限制

编辑

元表(metatable)的使用也有其缺点。大多数正常Lua表工具都不会对args表正常工作,包括#操作符号、next()函数和表库(table library)中的函数。如果这对你的模块重要,你需要使用你自己的用来处理参数的函数,而不是这个模块。