- Welcome to the Kancolle Wiki!
- If you have any questions regarding site content, account registration, etc., please visit the KanColle Wiki Discord
Difference between revisions of "Module:GetArgs"
Jump to navigation
Jump to search
com>Ckwng m (Protected "Module:GetArgs": High traffic page: This module is used by an extremely high number of pages. It is also based upon the getArgs built-in in Scribunto, so it should not be edited except to update. ([edit=autoconfirmed] (indefinite) [mo) |
m (4 revisions imported) |
||
(2 intermediate revisions by 2 users not shown) | |||
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+ | |
]] | ]] | ||
− | + | ||
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 |
Latest revision as of 11:50, 12 May 2021
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")
)
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
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 )
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