- Welcome to the Kancolle Wiki!
- If you have any questions regarding site content, account registration, etc., please visit the KanColle Wiki Discord
Changes
Jump to navigation
Jump to search
Line 1:
Line 1:
− 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++
− +
− +
− 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.
−
− if type( v ) == 'string' then+
− v = v:match( '^%s*(.-)%s*$' )+
− if v == '' then+
− return nil+
− end+
− end+
− return v+
− +
− if type( v ) == 'string' then+
− return v:match( '^%s*(.-)%s*$' )+
− else+
− return v+
− end+
− +
− if type( v ) == 'string' and not v:find( '%S' ) then+
− return nil+
− else+
− return v+
− end+
− +
− return v+
− +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
− 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 )
Update to commit 4b5069155bdc582b5a0d39b96968cfdd0cbe2204 from https://gerrit.wikimedia.org/r/#/c/158323/
--[[
--[[
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 libraryUtil = require( 'libraryUtil' )
local sandboxSuffixPattern = string.format( '/%s$',
local sandboxSuffixPattern = string.format( '/%s$',
mw.message.new( 'scribunto-template-sandbox-subpage-name' ):plain():gsub("%p", "%%%0")
)
)
local function tidyValDefault( k, v )
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
end
local function tidyValTrimOnly( k, v )
local function tidyValTrimOnly( k, v )
if type( v ) == 'string' then
return v:match( '^%s*(.-)%s*$' )
else
return v
end
end
end
local function tidyValRemoveBlanksOnly( k, v )
local function tidyValRemoveBlanksOnly( k, v )
if type( v ) == 'string' and not v:find( '%S' ) then
return nil
else
return v
end
end
end
local function tidyValNoChange( k, v )
local function tidyValNoChange( k, v )
return v
end
end
local function matchesTitle( given, title )
local tp = type( given )
return ( tp == 'string' or tp == 'number' ) and mw.title.new( given ).prefixedText == title
end
-- Checks whether title matches any wrapper templates that were specified by
-- the user.
local function titleIsWrapper( title, wrappers )
title = title:gsub( sandboxSuffixPattern, '' )
if matchesTitle( wrappers, title ) then
return true
elseif type( wrappers ) == 'table' then
-- If either a key or a value matches, it's a match
if wrappers[title] ~= nil then
return true
else
for _,v in ipairs( wrappers ) do
if matchesTitle( v, title ) then
return true
end
end
end
end
return false
end
return function( options )
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 tables to look up arguments from. These could be any of:
-- * the frame arguments
-- * the parent frame arguments
-- * a table of arguments passed from a Lua module or from the debug console
-- We try to select the correct one(s) based on whether we were passed a
-- valid frame object and whether we are being called from a wrapper
-- template. Usually we only use one of these tables, but if
-- options.wrappersUseFrame is set we may use both the frame arguments and
-- the parent frame arguments.
--]]
local argTables = {}
if type( frame.args ) == 'table' and type( frame.getParent ) == 'function' then
-- We were passed a valid frame. Find out if the title of its parent
-- frame is contained in options.wrappers.
if options.wrappers then
local parent = frame:getParent()
if parent and titleIsWrapper( parent:getTitle(), options.wrappers ) then
argTables[1] = parent.args
end
end
if not argTables[1] or options.wrappersUseFrame then
table.insert( argTables, frame.args )
end
else
-- Assume frame is a table of arguments passed from a Lua module or
-- from the debug console.
argTables[1] = frame
end
-- Get tidyVal, the function that we use to trim whitespace and remove
-- blank arguments. This can be set by the user with options.valueFunc.
-- Otherwise it is generated from options.trim and options.removeBlanks.
-- We define four separate default tidyVal functions so that we can avoid
-- checking options.trim and options.removeBlanks every time we look up an
-- argument.
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 a metatable to allow transparent fetching of arguments from argTables
-- * mt - the metatable
-- * fetchedArgs - a table to store memoized arguments fetched from argTables
-- * nilArgs - a table to memoize nil arguments
-- * donePairs - whether pairs has been run
-- * doneIpairs - whether ipairs has been run
local mt, fetchedArgs, nilArgs = {}, {}, {}
local donePairs, doneIpairs = false, false
-- This function merges arguments from argument tables into fetchedArgs,
-- Earlier argument tables take precedence over later ones; once a value
-- is written it is not overwritten.
local function mergeArgs( tables )
for _, t in ipairs( tables ) do
for key, val in pairs( t ) do
if fetchedArgs[key] == nil and not nilArgs[key] then
local tidiedVal = tidyVal( key, val )
if tidiedVal == nil then
nilArgs[key] = true
else
fetchedArgs[key] = tidiedVal
end
end
end
end
end
function mt.__index( t, key )
local val = fetchedArgs[key]
if val ~= nil then
return val
elseif donePairs or nilArgs[key] then
-- If pairs has been run we already have all the arguments in
-- fetchedArgs.
return nil
end
for _, argTable in ipairs( argTables ) do
local argTableVal = tidyVal( key, argTable[key] )
if argTableVal ~= nil then
fetchedArgs[key] = argTableVal
return argTableVal
end
end
nilArgs[key] = true
return nil
end
function mt.__newindex( t, key, val )
if val == nil then
-- We need to memoize the nil so that we don't look up the key in
-- the argument tables if it is accessed again.
nilArgs[key] = true
end
fetchedArgs[key] = val
end
function mt.__pairs()
if not donePairs then
donePairs = true
mergeArgs( argTables )
end
return pairs( fetchedArgs )
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
function mt.__ipairs(t)
return inext, t, 0
end
return setmetatable( {}, mt )
end
end