Строка 1: |
Строка 1: |
− | -- This module provides easy processing of arguments passed to Scribunto from #invoke.
| + | {{#invoke:Message box|fmbox}}<noinclude> |
− | -- It is intended for use by other Lua modules, and should not be called from #invoke directly.
| + | {{documentation}} |
− | | + | <!-- Add categories and interwikis to the /doc subpage, not here! --> |
− | local libraryUtil = require('libraryUtil')
| + | </noinclude> |
− | local checkType = libraryUtil.checkType
| |
− | | |
− | local arguments = {}
| |
− | | |
− | local nilArg = {} -- Used for memoizing nil arguments in metaArgs.
| |
− | | |
− | -- 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
| |
− | | |
− | function arguments.getArgs(frame, options)
| |
− | checkType('getArgs', 1, frame, 'table', true)
| |
− | checkType('getArgs', 2, options, 'table', true)
| |
− | frame = frame or {}
| |
− | options = options or {}
| |
− | | |
− | -- Get the arguments from the frame object if available. If the frame object is not available, we are being called
| |
− | -- from another Lua module or from the debug console, so assign the args to a new variable so we can differentiate them.
| |
− | local fargs, pargs, luaArgs
| |
− | if type(frame.args) == 'table' and type(frame.getParent) == 'function' then
| |
− | if not options.parentOnly then
| |
− | fargs = frame.args
| |
− | end
| |
− | if not options.frameOnly then
| |
− | pargs = frame:getParent().args
| |
− | end
| |
− | if options.parentFirst then
| |
− | fargs, pargs = pargs, fargs
| |
− | end
| |
− | else
| |
− | luaArgs = frame
| |
− | end
| |
− | | |
− | -- Set up the args and metaArgs tables. args will be the one accessed from functions, and metaArgs will hold the actual arguments.
| |
− | -- The metatable connects the two together.
| |
− | local args, metaArgs, metatable = {}, {}, {}
| |
− | setmetatable(args, metatable)
| |
− | | |
− | -- 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
| |
− | | |
− | local function mergeArgs(iterator, tables)
| |
− | -- Accepts multiple tables as input and merges their keys and values into one table using the specified iterator.
| |
− | -- If a value is already present it is not overwritten; tables listed earlier have precedence.
| |
− | -- We are also memoizing nil values, but those values can be overwritten.
| |
− | for _, t in ipairs(tables) do
| |
− | for key, val in iterator(t) do
| |
− | local metaArgsVal = metaArgs[key]
| |
− | if metaArgsVal == nil or metaArgsVal == nilArg then
| |
− | local tidiedVal = tidyVal(key, val)
| |
− | if tidiedVal == nil then
| |
− | metaArgs[key] = nilArg
| |
− | else
| |
− | metaArgs[key] = tidiedVal
| |
− | end
| |
− | end
| |
− | end
| |
− | end
| |
− | 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
| |
− | | |
− | --[[
| |
− | -- Define metatable behaviour. Arguments are memoized in the metaArgs table, and are only fetched from the
| |
− | -- argument tables once. Nil arguments are also memoized using the nilArg variable in order to increase
| |
− | -- performance. 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 fargs and pargs 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)
| |
− | local val = metaArgs[key]
| |
− | if val ~= nil then
| |
− | if val == nilArg then
| |
− | return nil
| |
− | else
| |
− | return val
| |
− | end
| |
− | end
| |
− | for _, argTable in ipairs(argTables) do
| |
− | local argTableVal = tidyVal(key, argTable[key])
| |
− | if argTableVal == nil then
| |
− | metaArgs[key] = nilArg
| |
− | else
| |
− | metaArgs[key] = argTableVal
| |
− | return argTableVal
| |
− | end
| |
− | end
| |
− | return nil
| |
− | end
| |
− | | |
− | metatable.__newindex = function (t, key, val)
| |
− | 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
| |
− | metaArgs[key] = nilArg -- Memoize nils.
| |
− | else
| |
− | metaArgs[key] = val
| |
− | end
| |
− | end
| |
− | | |
− | metatable.__pairs = function ()
| |
− | if not metatable.donePairs then
| |
− | mergeArgs(pairs, argTables)
| |
− | metatable.donePairs = true
| |
− | metatable.doneIpairs = true
| |
− | end
| |
− | return function (t, k)
| |
− | local nk, val = next(metaArgs, k)
| |
− | if val == nilArg then
| |
− | val = nil
| |
− | end
| |
− | return nk, val
| |
− | end
| |
− | end
| |
− | | |
− | metatable.__ipairs = function ()
| |
− | if not metatable.doneIpairs then
| |
− | mergeArgs(ipairs, argTables)
| |
− | metatable.doneIpairs = true
| |
− | end
| |
− | return function (t, i)
| |
− | local val = metaArgs[i + 1]
| |
− | if val == nil then
| |
− | return nil
| |
− | elseif val == nilArg then
| |
− | val = nil
| |
− | end
| |
− | return i + 1, val
| |
− | end, nil, 0
| |
− | end
| |
− | | |
− | return args
| |
− | end
| |
− | | |
− | return arguments
| |