– 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
function arguments.getArgs(frame, options)
checkType('getArgs', 1, frame, 'table', true)
checkType('getArgs', 2, options, 'table', true)
frame = frame or {}
options = options or {}
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 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
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 args, metaArgs, nilArgs, metatable = {}, {}, {}, {}
setmetatable(args, metatable)
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 if metaArgs[key] #### nil then local tidiedVal = tidyVal(key, val) if tidiedVal #### nil then nilArgs[key] = true else metaArgs[key] = tidiedVal end end end end end
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. --]] 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 nilArgs[key] = true else metaArgs[key] = argTableVal return argTableVal end end 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 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] = true -- Memoize nils. else metaArgs[key] = val end end
metatable.__pairs = function () -- Called when pairs is run on the args table. if not metatable.donePairs then mergeArgs(pairs, argTables) metatable.donePairs = true metatable.doneIpairs = true end return pairs(metaArgs) end
metatable.__ipairs = function () -- Called when ipairs is run on the args table. if not metatable.doneIpairs then mergeArgs(ipairs, argTables) metatable.doneIpairs = true end return ipairs(metaArgs) end
return args
end
return arguments
