- Welcome to the Kancolle Wiki!
- If you have any questions regarding site content, account registration, etc., please visit the KanColle Wiki Discord
Module:GetArgs
Revision as of 00:51, 30 November 2014 by com>Ckwng (Testing if Scribunto works, 'cause templates are really stupid =()
Documentation for this module may be created at Module:GetArgs/doc
--[[
Handles most of the boilerplate necessary to fetch arguments, such as trimming
leading/trailing whitespace, making blank arguments evaluate to false, correctly
choosing between current-frame and parent-frame, etc.
Originally written on the English Wikipedia by Mr. Stradivarius, Jackmcbarn, and Anomie.
Code released under the GPL v2+ as per:
https://en.wikipedia.org/w/index.php?diff=624020648&oldid=624019645
https://en.wikipedia.org/w/index.php?diff=624073793&oldid=624020648
@license GNU GPL v2+
]]
local libraryUtil = require( 'libraryUtil' )
local sandboxSuffixPattern = string.format( '/%s$',
mw.message.new( 'scribunto-template-sandbox-subpage-name' ):plain():gsub("%p", "%%%0")
)
-- Generate four different tidyVal functions, so that we don't have to check the options every
-- time we call it.
local function tidyValDefault( k, v )
if type( v ) == 'string' then
v = v:match( '^%s*(.-)%s*$' )
if v == '' then
return nil
end
end
return v
end
local function tidyValTrimOnly( k, v )
if type( v ) == 'string' then
return v:match( '^%s*(.-)%s*$' )
else
return v
end
end
local function tidyValRemoveBlanksOnly( k, v )
if type( v ) == 'string' and not v:find( '%S' ) then
return nil
else
return v
end
end
local function tidyValNoChange( k, v )
return v
end
return function( options )
libraryUtil.checkType( 'getArgs', 1, options, 'table', true )
local frame = options.frame
if frame == nil then
return {}
end
libraryUtil.checkTypeForNamedArg( 'getArgs', 'frame', frame, 'table' )
--[[
-- Get the argument tables. If we were passed a valid frame object, see if we're being
-- called via a wrapper. If so, then get pargs, the wrapper's arguments (and if
-- wrappersUseFrame is set, the frame's arguments as well). Otherwise, just get fargs,
-- the frame's arguments. 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
local parent = frame:getParent()
local found = false
if parent then
local title = parent:getTitle():gsub( sandboxSuffixPattern, '' )
if options.wrappers == title then
found = true
elseif type( options.wrappers ) == 'table' then
-- If either a key or a value matches, it's a match
if options.wrappers[title] ~= nil then
found = true
else
for _,v in ipairs( options.wrappers ) do
if v == title then
found = true
break
end
end
end
end
if found then
pargs = parent.args
end
end
if not found or options.wrappersUseFrame then
fargs = frame.args
end
else
fargs = frame.args
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 = { pargs }
argTables[#argTables + 1] = fargs
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
libraryUtil.checkTypeForNamedArg( 'getArgs', 'valueFunc', tidyVal, 'function' )
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, fetchedArgs and nilArgs tables. args will be the one accessed from
-- functions, and fetchedArgs will hold the actual arguments. Nil arguments are memoized
-- in nilArgs, and args_mt connects all of them together.
local args, fetchedArgs, nilArgs, args_mt = {}, {}, {}, {}
local donePairs, doneIpairs = false, false
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 fetchedArgs[key] == nil then
local tidiedVal = tidyVal( key, val )
if tidiedVal == nil then
nilArgs[key] = true
else
fetchedArgs[key] = tidiedVal
end
end
end
end
end
-- Define metatable behaviour. Arguments are memoized in the fetchedArgs 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.
function args_mt.__index( 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 fetchedArgs before
-- nilArgs, as both can be non-nil at the same time. If the argument is not
-- present in fetchedArgs, 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 fetchedArgs by the mergeArgs function,
-- meaning that any other arguments must be nil.
local val = fetchedArgs[key]
if val ~= nil then
return val
elseif 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
fetchedArgs[key] = argTableVal
return argTableVal
end
end
return nil
end
function args_mt.__newindex( t, key, val )
if val == nil then
-- If the argument is to be overwritten with nil, we need to memoize the
-- nil in nilArgs, so that the value isn't looked up in the argument
-- tables if it is accessed again.
nilArgs[key] = true
end
fetchedArgs[key] = val
end
function args_mt.__pairs()
if not donePairs then
donePairs = true
mergeArgs( pairs, argTables )
end
return pairs( fetchedArgs )
end
function args_mt.__ipairs()
if not doneIpairs and not donePairs then
doneIpairs = true
mergeArgs( ipairs, argTables )
end
return ipairs( fetchedArgs )
end
return setmetatable( args, args_mt )
end