Modul:TemplatePar
--[=[ TemplatePar 2013-04-28 Template parameter utility
- check
- count
]=]
-- Module globals local invokeFrame local l10nDef = {} l10nDef[ "en" ] = {
dupOpt = "TemplatePar#invoke: repeated optional parameter", empty = "Error in template: undefined value for mandatory", undefined = "Error in template: mandatory parameter missing", unknown = "Error in template: unknown parameter name"
} l10nDef[ "de" ] = {
dupOpt = "TemplatePar#invoke: Wiederholter Optionsparameter", empty = "Fehler bei Vorlage: Pflichtparameter ohne Wert", undefined = "Fehler bei Vorlage: fehlender Pflichtparameter", unknown = "Fehler bei Vorlage: Unbekannter Parametername"
}
local function failed( spec, suspect )
-- Submit error message -- Precondition: -- spec -- string; message ID -- suspect -- string or nil; additional information -- Postcondition: -- Return string -- Uses: -- > invokeFrame -- > l10nDef local r local show = invokeFrame.args[ "template" ] local l10n = mw.language.getContentLanguage() l10n = l10nDef[ l10n:getCode() ] if not l10n then l10n = l10nDef[ "en" ] end r = l10n[ spec ] if show then r = r .. " (" .. show .. ")" end if suspect then r = r .. " " .. suspect end return r
end -- failed()
local function fault( store, key )
-- Add key to collection string and insert separator -- Precondition: -- store -- string or nil or false; collection string -- key -- string or number; to be appended -- Postcondition: -- Return string; extended local r local s if type( key ) == "number" then s = tostring( key ) else s = key end if store then r = store .. "; " .. s else r = s end return r
end -- fault()
local function fed( haystack, needle )
-- Find needle in haystack map -- Precondition: -- haystack -- table; map of key values -- needle -- any; identifier -- Postcondition: -- Return true iff found local k, v for k, v in pairs( haystack ) do if k == needle then return true end end -- for k, v return false
end -- fed()
local function fetch()
-- Return regular table with template parameters -- Postcondition: -- Return table; whitespace-only values as false -- Uses: -- > invokeFrame -- frame:getParent() local k, v local r = { } local t = invokeFrame:getParent() local o = t.args for k, v in pairs( o ) do if type( v ) == "string" then if v:match( "^%s*$" ) then v = false end else v = false end if type( k ) == "number" then k = tostring( k ) end r[ k ] = v end -- for k, v return r
end -- fetch()
local function figure()
-- Return number of template parameters -- Postcondition: -- Return number, starting at 0 -- Uses: -- > invokeFrame -- frame:getParent() local k, v local r = 0 local t = invokeFrame:getParent() local o = t.args for k, v in pairs( o ) do r = r + 1 end -- for k, v return r
end -- figure()
local function fill( specified )
-- Split requirement string separated by '=' -- Precondition: -- specified -- string or nil; requested parameter set -- Postcondition: -- Return sequence table local r if specified then local i, s r = mw.text.split( specified, "%s*=%s*" ) for i = #r, 1, -1 do s = r[ i ] if #s == 0 then table.remove( r, i ) end end -- for i, -1 else r = { } end return r
end -- fill()
local function finder( haystack, needle )
-- Find needle in haystack sequence -- Precondition: -- haystack -- table; sequence of key names -- needle -- any; key name -- Postcondition: -- Return true iff found local i for i = 1, #haystack do if haystack[ i ] == needle then return true end end -- for i return false
end -- finder()
local function fit( base, extend )
-- Merge two tables, create new sequence if both not empty -- Precondition: -- base -- table; sequence kept unchanged -- extend -- table; sequence to be appended -- Postcondition: -- Return merged table, or message string if duplicated entries -- Uses: -- finder() -- fault() local r if #base == 0 then if #extend == 0 then r = { } else r = extend end else if #extend == 0 then r = base else local i, s r = false for i = 1, #extend do s = extend[ i ] if finder( base, s ) then r = fault( r, s ) end end -- for i if not r then r = { } for i = 1, #base do table.insert( r, base[ i ] ) end -- for i for i = 1, #extend do table.insert( r, extend[ i ] ) end -- for i end end end return r
end -- fit()
local function fix( valid, duty )
-- Perform parameter analysis
-- Precondition:
-- valid -- table; unique sequence of known parameters
-- duty -- table; sequence of mandatory parameters
-- Postcondition:
-- Return string as configured; empty if valid
-- Uses:
-- > invokeFrame
-- fetch()
-- finder()
-- fault()
-- failed()
-- fed()
local k, v
local r = false
local got = fetch()
for k, v in pairs( got ) do
if not finder( valid, k ) then
r = fault( r, k )
end
end -- for k, v
if r then
r = failed( "unknown", r )
else -- all names valid
-- avoid confusing consecutive error messages
local i, s
for i = 1, #duty do
s = duty[ i ]
if not fed( got, s ) then
r = fault( r, s )
end
end -- for i
if r then
r = failed( "undefined", r )
else
for i = 1, #duty do
s = duty[ i ]
if not got[ s ] then
r = fault( r, s )
end
end -- for i
if r then
r = failed( "empty", r )
end
end
end
if r then
if invokeFrame.args[ "noError" ] then
r = ""
else
r = "" .. r .. ""
end
k = invokeFrame.args[ "cat" ]
if k then
if k:find( "@@@" ) then
v = invokeFrame.args[ "template" ]
if v then
k = k:gsub( "@@@", v )
end
end
r = r .. ""
end
else
r = ""
end
return r
end -- fix()
local function force()
-- Initialize parameter analysis -- Postcondition: -- Return string as configured; empty if valid -- Uses: -- > invokeFrame -- fill() -- fit() -- failed() -- fix() local duty = fill( invokeFrame.args[ 1 ] ) local options = fill( invokeFrame.args[ 2 ] ) local r = fit( duty, options ) if type( r ) == "string" then r = failed( "dupOpt", r ) else r = fix( r, duty ) end return r
end -- force()
-- Provide template access
local p = {}
function p.check( frame )
-- Check validity of template parameters -- Precondition: -- frame -- object; #invoke environment -- Postcondition: -- Return string with error message or "" -- Uses: -- force() -- < invokeFrame invokeFrame = frame return force()
end -- .check()
function p.count( frame )
-- Count number of template parameters -- Precondition: -- frame -- object; #invoke environment -- Postcondition: -- Return string with digits including "0" -- Uses: -- figure() -- < invokeFrame invokeFrame = frame return tostring( figure() )
end -- .count()
function p.valid( frame )
-- Check validity of one template parameter -- Precondition: -- frame -- object; #invoke environment -- Postcondition: -- Return string with error message or "" -- Uses: -- < invokeFrame invokeFrame = frame return "#invoke:TemplatePar|valid| Not yet available"
end -- .valid()
return p