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的内容(除了...标签内的)为{{#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()函数就获取框架参数和父框架参数。如果你需要将...标签作为输入时,这会很有用。

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

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

已知限制

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

-- This module provides easy processing of arguments passed to Scribunto from -- #invoke. It is intended for use by other Lua modules, and should not be -- called from #invoke directly.  local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType  local arguments = {}  -- Generate four different tidyVal functions, so that we don't have to check the -- options every time we call it.  local function tidyValDefault(key, val) if type(val) == 'string' then val = val:match('^%s*(.-)%s*$') if val == '' then return nil else return val end else return val end end  local function tidyValTrimOnly(key, val) if type(val) == 'string' then return val:match('^%s*(.-)%s*$') else return val end end  local function tidyValRemoveBlanksOnly(key, val) if type(val) == 'string' then if val:find('%S') then return val else return nil end else return val end end  local function tidyValNoChange(key, val) return val end  local function matchesTitle(given, title) local tp = type( given ) return (tp == 'string' or tp == 'number') and mw.title.new( given ).prefixedText == title end  local translate_mt = { __index = function(t, k) return k end }  function arguments.getArgs(frame, options) checkType('getArgs', 1, frame, 'table', true) checkType('getArgs', 2, options, 'table', true) frame = frame or {} options = options or {}  --[[ -- Set up argument translation. --]] options.translate = options.translate or {} if getmetatable(options.translate) == nil then setmetatable(options.translate, translate_mt) end if options.backtranslate == nil then options.backtranslate = {} for k,v in pairs(options.translate) do options.backtranslate[v] = k end end if options.backtranslate and getmetatable(options.backtranslate) == nil then setmetatable(options.backtranslate, { __index = function(t, k) if options.translate[k] ~= k then return nil else return k end end }) end  --[[ -- Get the argument tables. If we were passed a valid frame object, get the -- frame arguments (fargs) and the parent frame arguments (pargs), depending -- on the options set and on the parent frame's availability. If we weren't -- passed a valid frame object, we are being called from another Lua module -- or from the debug console, so assume that we were passed a table of args -- directly, and assign it to a new variable (luaArgs). --]] local fargs, pargs, luaArgs if type(frame.args) == 'table' and type(frame.getParent) == 'function' then if options.wrappers then --[[ -- The wrappers option makes Module:Arguments look up arguments in -- either the frame argument table or the parent argument table, but -- not both. This means that users can use either the #invoke syntax -- or a wrapper template without the loss of performance associated -- with looking arguments up in both the frame and the parent frame. -- Module:Arguments will look up arguments in the parent frame -- if it finds the parent frame's title in options.wrapper; -- otherwise it will look up arguments in the frame object passed -- to getArgs. --]] local parent = frame:getParent() if not parent then fargs = frame.args else local title = parent:getTitle():gsub('/sandbox$', '') local found = false if matchesTitle(options.wrappers, title) then found = true elseif type(options.wrappers) == 'table' then for _,v in pairs(options.wrappers) do if matchesTitle(v, title) then found = true break end end end  -- We test for false specifically here so that nil (the default) acts like true. if found or options.frameOnly == false then pargs = parent.args end if not found or options.parentOnly == false then fargs = frame.args end end else -- options.wrapper isn't set, so check the other options. if not options.parentOnly then fargs = frame.args end if not options.frameOnly then local parent = frame:getParent() pargs = parent and parent.args or nil end end if options.parentFirst then fargs, pargs = pargs, fargs end else luaArgs = frame end  -- Set the order of precedence of the argument tables. If the variables are -- nil, nothing will be added to the table, which is how we avoid clashes -- between the frame/parent args and the Lua args. local argTables = {fargs} argTables[#argTables + 1] = pargs argTables[#argTables + 1] = luaArgs  --[[ -- Generate the tidyVal function. If it has been specified by the user, we -- use that; if not, we choose one of four functions depending on the -- options chosen. This is so that we don't have to call the options table -- every time the function is called. --]] local tidyVal = options.valueFunc if tidyVal then if type(tidyVal) ~= 'function' then error( "bad value assigned to option 'valueFunc'" .. '(function expected, got ' .. type(tidyVal) .. ')', 2 ) end elseif options.trim ~= false then if options.removeBlanks ~= false then tidyVal = tidyValDefault else tidyVal = tidyValTrimOnly end else if options.removeBlanks ~= false then tidyVal = tidyValRemoveBlanksOnly else tidyVal = tidyValNoChange end end  --[[ -- Set up the args, metaArgs and nilArgs tables. args will be the one -- accessed from functions, and metaArgs will hold the actual arguments. Nil -- arguments are memoized in nilArgs, and the metatable connects all of them -- together. --]] local args, metaArgs, nilArgs, metatable = {}, {}, {}, {} setmetatable(args, metatable)  local function mergeArgs(tables) --[[ -- Accepts multiple tables as input and merges their keys and values -- into one table. If a value is already present it is not overwritten; -- tables listed earlier have precedence. We are also memoizing nil -- values, which can be overwritten if they are 's' (soft). --]] for _, t in ipairs(tables) do for key, val in pairs(t) do if metaArgs[key] == nil and nilArgs[key] ~= 'h' then local tidiedVal = tidyVal(key, val) if tidiedVal == nil then nilArgs[key] = 's' else metaArgs[key] = tidiedVal end end end end end  --[[ -- Define metatable behaviour. Arguments are memoized in the metaArgs table, -- and are only fetched from the argument tables once. Fetching arguments -- from the argument tables is the most resource-intensive step in this -- module, so we try and avoid it where possible. For this reason, nil -- arguments are also memoized, in the nilArgs table. Also, we keep a record -- in the metatable of when pairs and ipairs have been called, so we do not -- run pairs and ipairs on the argument tables more than once. We also do -- not run ipairs on fargs and pargs if pairs has already been run, as all -- the arguments will already have been copied over. --]]  metatable.__index = function (t, key) --[[ -- Fetches an argument when the args table is indexed. First we check -- to see if the value is memoized, and if not we try and fetch it from -- the argument tables. When we check memoization, we need to check -- metaArgs before nilArgs, as both can be non-nil at the same time. -- If the argument is not present in metaArgs, we also check whether -- pairs has been run yet. If pairs has already been run, we return nil. -- This is because all the arguments will have already been copied into -- metaArgs by the mergeArgs function, meaning that any other arguments -- must be nil. --]] if type(key) == 'string' then key = options.translate[key] end local val = metaArgs[key] if val ~= nil then return val elseif metatable.donePairs or nilArgs[key] then return nil end for _, argTable in ipairs(argTables) do local argTableVal = tidyVal(key, argTable[key]) if argTableVal ~= nil then metaArgs[key] = argTableVal return argTableVal end end nilArgs[key] = 'h' return nil end  metatable.__newindex = function (t, key, val) -- This function is called when a module tries to add a new value to the -- args table, or tries to change an existing value. if type(key) == 'string' then key = options.translate[key] end if options.readOnly then error( 'could not write to argument table key "' .. tostring(key) .. '"; the table is read-only', 2 ) elseif options.noOverwrite and args[key] ~= nil then error( 'could not write to argument table key "' .. tostring(key) .. '"; overwriting existing arguments is not permitted', 2 ) elseif val == nil then --[[ -- If the argument is to be overwritten with nil, we need to erase -- the value in metaArgs, so that __index, __pairs and __ipairs do -- not use a previous existing value, if present; and we also need -- to memoize the nil in nilArgs, so that the value isn't looked -- up in the argument tables if it is accessed again. --]] metaArgs[key] = nil nilArgs[key] = 'h' else metaArgs[key] = val end end  local function translatenext(invariant) local k, v = next(invariant.t, invariant.k) invariant.k = k if k == nil then return nil elseif type(k) ~= 'string' or not options.backtranslate then return k, v else local backtranslate = options.backtranslate[k] if backtranslate == nil then -- Skip this one. This is a tail call, so this won't cause stack overflow return translatenext(invariant) else return backtranslate, v end end end  metatable.__pairs = function () -- Called when pairs is run on the args table. if not metatable.donePairs then mergeArgs(argTables) metatable.donePairs = true end return translatenext, { t = metaArgs } end  local function inext(t, i) -- This uses our __index metamethod local v = t[i + 1] if v ~= nil then return i + 1, v end end  metatable.__ipairs = function (t) -- Called when ipairs is run on the args table. return inext, t, 0 end  return args end  return arguments 

Tags:

🔥 Trending searches on Wiki 中文:

食戟之靈以愛為營此時此刻 (電視劇)周峻纬機動戰士GUNDAM SEED系列角色列表谢锋周處除三害 (電影)蔣萬安中華民國媒體列表一带一路多曼拉朱·古凯什周雨彤年少日記為美好的世界獻上祝福! (動畫)泰坦鱼龙属邱國正全少妮卢旺达姜濤趙麗穎宋朝許光漢ADOR媽祖SOURCE MUSIC千与千寻環狀線 (台北捷運)中越战争婚後事钱学森佛教般若波羅蜜多心經梦华录4月26日BLUE LOCK 藍色監獄姜大衞李克强之死长城劉俊謙 (香港)楊茜堯PLEDIS娛樂四通桥事件張藝興李多慧 (啦啦隊)梅艷芳TOMORROW X TOGETHER周文健五條悟罗云熙徐熙娣孟波 (電影)阿斯達年代記西班牙Aespa邊佑錫朴成焄俄羅斯入侵烏克蘭河北彩花劉彥澧鄭文燦麻豆传媒中國國民黨崇禎帝檀健次大長今 (電視劇)劍星各国人均名义国内生产总值列表張雷 (香港)意大利希腊字母宋美齡細川伽羅奢狂猎習近平派系羅天宇热辣滚烫無職轉生~到了異世界就拿出真本事~角色列表今天的她們🡆 More