Modul:TemplatePar: Unterschied zwischen den Versionen
te>Leyo K (Schützte „Modul:TemplatePar“: Häufig eingebundenes Modul ([Bearbeiten=Nur angemeldete, nicht neue Benutzer] (unbeschränkt) [Verschieben=Nur Administratoren] (unbeschränkt))) |
te>PerfektesChaos (update) |
||
Zeile 1: | Zeile 1: | ||
− | --[=[ TemplatePar 2013- | + | --[=[ TemplatePar 2013-05-03 |
Template parameter utility | Template parameter utility | ||
* check | * check | ||
* count | * count | ||
+ | * valid | ||
+ | * TemplatePar() | ||
]=] | ]=] | ||
Zeile 8: | Zeile 10: | ||
-- Module globals | -- Module globals | ||
− | local | + | local TemplatePar = { } |
+ | local messagePrefix = "lua-module-TemplatePar-" | ||
local l10nDef = {} | local l10nDef = {} | ||
l10nDef[ "en" ] = { | l10nDef[ "en" ] = { | ||
− | dupOpt | + | dupOpt = "TemplatePar#invoke: repeated optional parameter", |
− | empty | + | empty = "Error in template: undefined value for mandatory", |
− | undefined = "Error in template: mandatory parameter missing", | + | invalid = "Error in template: invalid parameter", |
− | unknown | + | invalidPar = "TemplatePar#invoke: invalid parameter", |
+ | noname = "TemplatePar#invoke: missing parameter name", | ||
+ | tooLong = "Error in template: parameter too long", | ||
+ | tooShort = "Error in template: parameter too short", | ||
+ | undefined = "Error in template: mandatory parameter missing", | ||
+ | unknown = "Error in template: unknown parameter name", | ||
+ | unknownRule = "TemplatePar#invoke: unknown rule" | ||
} | } | ||
− | l10nDef[ "de" ] = { | + | l10nDef[ "de" ] = { |
− | dupOpt | + | dupOpt = "TemplatePar#invoke: Optionsparameter wiederholt", |
− | empty | + | empty = "Fehler bei Vorlage: Pflichtparameter ohne Wert", |
− | undefined = "Fehler bei Vorlage: | + | invalid = "Fehler bei Vorlage: Parameter ungültig", |
− | unknown | + | invalidPar = "TemplatePar#invoke: Ungültiger Parameter", |
+ | noname = "TemplatePar#invoke: Parametername nicht angegeben", | ||
+ | tooLong = "Fehler bei Vorlage: Parameter zu lang", | ||
+ | tooShort = "Fehler bei Vorlage: Parameter zu kurz", | ||
+ | undefined = "Fehler bei Vorlage: Pflichtparameter fehlt", | ||
+ | unknown = "Fehler bei Vorlage: Parametername unbekannt", | ||
+ | unknownRule = "TemplatePar#invoke: Unbekannte Regel" | ||
} | } | ||
+ | local Patterns = { | ||
+ | [ "ASCII" ] = "^[ -~]*$", | ||
+ | [ "ASCII+" ] = "^[ -~]+$", | ||
+ | [ "ASCII+1" ] = "^[!-~]+$", | ||
+ | [ "n" ] = "^%-?[0-9]*$", -- einzelnes Minus ausschließen | ||
+ | [ "n>0" ] = "^[0-9]*[1-9][0-9]*$", | ||
+ | [ "N+" ] = "^%-?[1-9][0-9]*$", | ||
+ | [ "N>0" ] = "^[1-9][0-9]*$", | ||
+ | [ "x" ] = "^[0-9A-Fa-f]*$", | ||
+ | [ "x+" ] = "^[0-9A-Fa-f]+$", | ||
+ | [ "X" ] = "^[0-9A-F]*$", | ||
+ | [ "X+" ] = "^[0-9A-F]+$", | ||
+ | [ "+" ] = "%S" | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | function trim( s ) | ||
+ | -- Trim string | ||
+ | -- Precondition: | ||
+ | -- s -- string or nil; to be trimmed | ||
+ | -- Postcondition: | ||
+ | -- Return trimmed string or nil | ||
+ | local r = s | ||
+ | if type( s ) == "string" then | ||
+ | if s:match( "^%s*$" ) then | ||
+ | r = "" | ||
+ | else | ||
+ | r = s:match( "^%s*(%S.*)$" ) | ||
+ | r = r:match( "^(.*%S)%s*$" ) | ||
+ | end | ||
+ | end | ||
+ | return r | ||
+ | end -- trim() | ||
+ | |||
+ | |||
+ | |||
+ | local function factory( say ) | ||
+ | -- Retrieve localized message string in content language | ||
+ | -- Precondition: | ||
+ | -- say -- string; message ID | ||
+ | -- Postcondition: | ||
+ | -- Return some message string | ||
+ | -- Uses: | ||
+ | -- > messagePrefix | ||
+ | -- > l10nDef | ||
+ | local c = mw.language.getContentLanguage():getCode() | ||
+ | local m = mw.message.new( messagePrefix .. say ) | ||
+ | local r = false | ||
+ | if m:isBlank() then | ||
+ | local l10n = l10nDef[ c ] | ||
+ | if not l10n then | ||
+ | l10n = l10nDef[ "en" ] | ||
+ | end | ||
+ | r = l10n[ say ] | ||
+ | else | ||
+ | m:inLanguage( c ) | ||
+ | r = m:plain() | ||
+ | end | ||
+ | if not r then | ||
+ | r = "(((".. say .. ")))" | ||
+ | end | ||
+ | return r | ||
+ | end -- factory() | ||
− | local function | + | local function failure( spec, suspect, options ) |
− | -- Submit error message | + | -- Submit localized error message |
-- Precondition: | -- Precondition: | ||
-- spec -- string; message ID | -- spec -- string; message ID | ||
-- suspect -- string or nil; additional information | -- suspect -- string or nil; additional information | ||
+ | -- options -- table or nil; optional details | ||
+ | -- options.template | ||
-- Postcondition: | -- Postcondition: | ||
-- Return string | -- Return string | ||
-- Uses: | -- Uses: | ||
− | -- | + | -- factory() |
− | + | local r = factory( spec ) | |
− | local r | + | if type( options ) == "table" then |
− | + | if type( options.template ) == "string" then | |
− | + | if #options.template > 0 then | |
− | + | r = r .. " (" .. options.template .. ")" | |
− | + | end | |
− | + | end | |
− | |||
− | |||
− | |||
− | |||
end | end | ||
if suspect then | if suspect then | ||
Zeile 50: | Zeile 127: | ||
end | end | ||
return r | return r | ||
− | end -- | + | end -- failure() |
Zeile 97: | Zeile 174: | ||
local function fetch() | local function fetch() | ||
− | -- Return regular table with template parameters | + | -- Return regular table with all template transclusion parameters |
-- Postcondition: | -- Postcondition: | ||
-- Return table; whitespace-only values as false | -- Return table; whitespace-only values as false | ||
-- Uses: | -- Uses: | ||
− | -- | + | -- mw.getCurrentFrame() |
-- frame:getParent() | -- frame:getParent() | ||
local k, v | local k, v | ||
local r = { } | local r = { } | ||
− | local t = | + | local t = mw.getCurrentFrame():getParent() |
local o = t.args | local o = t.args | ||
for k, v in pairs( o ) do | for k, v in pairs( o ) do | ||
Zeile 122: | Zeile 199: | ||
return r | return r | ||
end -- fetch() | end -- fetch() | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
Zeile 165: | Zeile 223: | ||
return r | return r | ||
end -- fill() | end -- fill() | ||
+ | |||
+ | |||
+ | |||
+ | local function finalize( submit, options ) | ||
+ | -- Finalize message | ||
+ | -- Precondition: | ||
+ | -- submit -- string or false or nil; non-empty error message | ||
+ | -- options -- table or nil; optional details | ||
+ | -- options.noError | ||
+ | -- options.cat | ||
+ | -- options.template | ||
+ | -- Postcondition: | ||
+ | -- Return string or false | ||
+ | local r = false | ||
+ | if submit then | ||
+ | local opt, s | ||
+ | if type( options ) == "table" then | ||
+ | opt = options | ||
+ | else | ||
+ | opt = { } | ||
+ | end | ||
+ | if opt.noError then | ||
+ | r = false | ||
+ | else | ||
+ | r = "<span class='error'>" .. submit .. "</span>" | ||
+ | end | ||
+ | s = opt.cat | ||
+ | if type( s ) == "string" then | ||
+ | if not r then | ||
+ | r = "" | ||
+ | end | ||
+ | if s:find( "@@@" ) then | ||
+ | if type( opt.template ) == "string" then | ||
+ | s = s:gsub( "@@@", opt.template ) | ||
+ | end | ||
+ | end | ||
+ | r = r .. "[[Category:" .. s .. "]]" | ||
+ | end | ||
+ | end | ||
+ | return r | ||
+ | end -- finalize() | ||
Zeile 231: | Zeile 330: | ||
− | local function fix( valid, duty ) | + | local function fix( valid, duty, options ) |
− | -- Perform parameter analysis | + | -- Perform transclusion parameter analysis |
-- Precondition: | -- Precondition: | ||
− | -- valid | + | -- valid -- table; unique sequence of known parameters |
− | -- duty | + | -- duty -- table; sequence of mandatory parameters |
+ | -- options -- table or nil; optional details | ||
-- Postcondition: | -- Postcondition: | ||
-- Return string as configured; empty if valid | -- Return string as configured; empty if valid | ||
-- Uses: | -- Uses: | ||
− | |||
-- fetch() | -- fetch() | ||
-- finder() | -- finder() | ||
-- fault() | -- fault() | ||
− | -- | + | -- failure() |
-- fed() | -- fed() | ||
local k, v | local k, v | ||
Zeile 254: | Zeile 353: | ||
end -- for k, v | end -- for k, v | ||
if r then | if r then | ||
− | r = | + | r = failure( "unknown", r, options ) |
else -- all names valid | else -- all names valid | ||
− | |||
local i, s | local i, s | ||
for i = 1, #duty do | for i = 1, #duty do | ||
Zeile 265: | Zeile 363: | ||
end -- for i | end -- for i | ||
if r then | if r then | ||
− | r = | + | r = failure( "undefined", r, options ) |
− | else | + | else -- all mandatory present |
for i = 1, #duty do | for i = 1, #duty do | ||
s = duty[ i ] | s = duty[ i ] | ||
Zeile 274: | Zeile 372: | ||
end -- for i | end -- for i | ||
if r then | if r then | ||
− | r = | + | r = failure( "empty", r, options ) |
end | end | ||
end | end | ||
end | end | ||
− | if r | + | return r |
− | + | end -- fix() | |
− | r = "" | + | |
+ | |||
+ | |||
+ | local function format( seek, options ) | ||
+ | -- Check validity of one particular template parameter | ||
+ | -- Precondition: | ||
+ | -- seek -- string non-empty; name of template parameter | ||
+ | -- options -- table or nil; optional details | ||
+ | -- options.pattern | ||
+ | -- options.key | ||
+ | -- options.min | ||
+ | -- options.max | ||
+ | -- Postcondition: | ||
+ | -- Return string with error message as configured; | ||
+ | -- false if valid or no answer permitted | ||
+ | -- Uses: | ||
+ | -- > Patterns | ||
+ | -- failure() | ||
+ | -- mw.ustring.match() | ||
+ | -- frame:getParent() | ||
+ | local r = false | ||
+ | local s | ||
+ | local scan = false | ||
+ | local story = mw.getCurrentFrame():getParent() | ||
+ | story = ( story.args[ seek ] or "" ) | ||
+ | if type( options.pattern ) == "string" then | ||
+ | if options.key then | ||
+ | r = failure( "duplicatedRule", false, options ) | ||
+ | else | ||
+ | scan = options.pattern | ||
+ | end | ||
+ | else | ||
+ | if type( options.key ) == "string" then | ||
+ | s = trim( options.key ) | ||
else | else | ||
− | + | s = "+" | |
end | end | ||
− | + | scan = Patterns[ s ] | |
− | if | + | if type( scan ) == "string" then |
− | if | + | if s == "n" then |
− | + | if trim( story ) == "-" then | |
− | + | scan = false | |
− | + | r = failure( "invalid", | |
+ | "'" .. seek .. "'", | ||
+ | options ) | ||
end | end | ||
end | end | ||
− | r = r .. " | + | else |
+ | r = failure( "unknownRule", s, options ) | ||
+ | end | ||
+ | end | ||
+ | if scan then | ||
+ | if not mw.ustring.match( story, scan ) then | ||
+ | r = failure( "invalid", "'" .. seek .. "'", options ) | ||
+ | end | ||
+ | end | ||
+ | if options.min and not r then | ||
+ | if type( options.min ) == "number" then | ||
+ | if #story < options.min then | ||
+ | r = failure( "tooShort", | ||
+ | " <" .. options.min .. " '" .. seek .. "'", | ||
+ | options ) | ||
+ | end | ||
+ | else | ||
+ | r = failure( "invalidPar", "min", options ) | ||
+ | end | ||
+ | end | ||
+ | if options.max and not r then | ||
+ | if type( options.max ) == "number" then | ||
+ | if #story > options.max then | ||
+ | r = failure( "tooLong", | ||
+ | " >" .. options.max .. " '" .. seek .. "'", | ||
+ | options ) | ||
+ | end | ||
+ | else | ||
+ | r = failure( "invalidPar", "max", options ) | ||
end | end | ||
− | |||
− | |||
end | end | ||
return r | return r | ||
− | end -- | + | end -- format() |
− | + | TemplatePar.check = function ( options ) | |
− | -- | + | -- Run parameter analysis |
+ | -- Precondition: | ||
+ | -- options -- table or nil; optional details | ||
+ | -- options.mandatory | ||
+ | -- options.optional | ||
-- Postcondition: | -- Postcondition: | ||
− | -- Return string as configured; | + | -- Return string with error message as configured; |
+ | -- false if valid or no answer permitted | ||
-- Uses: | -- Uses: | ||
− | |||
− | |||
-- fit() | -- fit() | ||
− | -- | + | -- failure() |
-- fix() | -- fix() | ||
− | local duty | + | -- finalize() |
− | + | local duty, r | |
− | + | if type( options ) == "table" then | |
+ | if type( options.mandatory ) == "table" then | ||
+ | duty = options.mandatory | ||
+ | else | ||
+ | duty = { } | ||
+ | end | ||
+ | if type( options.optional ) ~= "table" then | ||
+ | options.optional = { } | ||
+ | end | ||
+ | r = fit( duty, options.optional ) | ||
+ | else | ||
+ | duty = { } | ||
+ | r = { } | ||
+ | end | ||
if type( r ) == "string" then | if type( r ) == "string" then | ||
− | r = | + | r = failure( "dupOpt", r, options ) |
else | else | ||
− | r = fix( r, duty ) | + | r = fix( r, duty, options ) |
end | end | ||
+ | return finalize( r, options ) | ||
+ | end -- TemplatePar.check() | ||
+ | |||
+ | |||
+ | |||
+ | TemplatePar.count = function () | ||
+ | -- Return number of template parameters | ||
+ | -- Postcondition: | ||
+ | -- Return number, starting at 0 | ||
+ | -- Uses: | ||
+ | -- mw.getCurrentFrame() | ||
+ | -- frame:getParent() | ||
+ | local k, v | ||
+ | local r = 0 | ||
+ | local t = mw.getCurrentFrame():getParent() | ||
+ | local o = t.args | ||
+ | for k, v in pairs( o ) do | ||
+ | r = r + 1 | ||
+ | end -- for k, v | ||
return r | return r | ||
− | end -- | + | end -- TemplatePar.count() |
+ | |||
+ | |||
+ | TemplatePar.valid = function ( seek, options ) | ||
+ | -- Check validity of one particular template parameter | ||
+ | -- Precondition: | ||
+ | -- seek -- string; name of template parameter | ||
+ | -- options -- table or nil; optional details | ||
+ | -- Postcondition: | ||
+ | -- Return string with error message as configured; | ||
+ | -- false if valid or no answer permitted | ||
+ | -- Uses: | ||
+ | -- trim() | ||
+ | -- format() | ||
+ | -- failure() | ||
+ | -- finalize() | ||
+ | local r | ||
+ | if type( seek ) == "string" then | ||
+ | r = trim( seek ) | ||
+ | if #r == 0 then | ||
+ | r = false | ||
+ | end | ||
+ | end | ||
+ | if r then | ||
+ | r = format( seek, options ) | ||
+ | else | ||
+ | r = failure( "noname", false, options ) | ||
+ | end | ||
+ | return finalize( r, options ) | ||
+ | end -- TemplatePar.valid() | ||
− | |||
+ | -- Provide external access | ||
local p = {} | local p = {} | ||
+ | |||
+ | |||
function p.check( frame ) | function p.check( frame ) | ||
Zeile 336: | Zeile 561: | ||
-- Return string with error message or "" | -- Return string with error message or "" | ||
-- Uses: | -- Uses: | ||
− | -- | + | -- fill() |
− | -- | + | -- TemplatePar.check() |
− | + | local options = { mandatory = fill( frame.args[ 1 ] ), | |
− | return | + | optional = fill( frame.args[ 2 ] ), |
+ | cat = frame.args.cat, | ||
+ | noError = frame.args.noError, | ||
+ | template = frame.args.template | ||
+ | } | ||
+ | return TemplatePar.check( options ) or "" | ||
end -- .check() | end -- .check() | ||
+ | |||
+ | |||
function p.count( frame ) | function p.count( frame ) | ||
-- Count number of template parameters | -- Count number of template parameters | ||
− | |||
− | |||
-- Postcondition: | -- Postcondition: | ||
-- Return string with digits including "0" | -- Return string with digits including "0" | ||
-- Uses: | -- Uses: | ||
− | -- | + | -- TemplatePar.count() |
− | + | return tostring( TemplatePar.count() ) | |
− | |||
− | return tostring( | ||
end -- .count() | end -- .count() | ||
+ | |||
+ | |||
function p.valid( frame ) | function p.valid( frame ) | ||
− | -- Check validity of one template parameter | + | -- Check validity of one particular template parameter |
-- Precondition: | -- Precondition: | ||
-- frame -- object; #invoke environment | -- frame -- object; #invoke environment | ||
Zeile 362: | Zeile 592: | ||
-- Return string with error message or "" | -- Return string with error message or "" | ||
-- Uses: | -- Uses: | ||
− | -- | + | -- trim() |
− | + | -- TemplatePar.valid() | |
− | + | local r = false | |
+ | local s | ||
+ | local options = { cat = frame.args.cat, | ||
+ | noError = frame.args.noError, | ||
+ | template = frame.args.template | ||
+ | } | ||
+ | s = trim( frame.args[ 2 ] ) | ||
+ | if type( s ) == "string" then | ||
+ | local sub = s:match( "^/(.*%S)/$" ) | ||
+ | if type( sub ) == "string" then | ||
+ | options.pattern = sub | ||
+ | else | ||
+ | options.key = s | ||
+ | end | ||
+ | end | ||
+ | if type( frame.args.min ) == "string" then | ||
+ | s = frame.args.min:match( "^%s*([0-9]+)%s*$" ) | ||
+ | if s then | ||
+ | options.min = tonumber( s ) | ||
+ | else | ||
+ | r = failure( "invalidPar", | ||
+ | "min=" .. frame.args.min, | ||
+ | options ) | ||
+ | end | ||
+ | end | ||
+ | if type( frame.args.max ) == "string" then | ||
+ | s = frame.args.max:match( "^%s*([1-9][0-9]*)%s*$" ) | ||
+ | if s then | ||
+ | options.max = tonumber( s ) | ||
+ | else | ||
+ | r = failure( "invalidPar", | ||
+ | "max=" .. frame.args.max, | ||
+ | options ) | ||
+ | end | ||
+ | end | ||
+ | if r then | ||
+ | r = finalize( r, options ) | ||
+ | else | ||
+ | s = frame.args[ 1 ] or "" | ||
+ | r = TemplatePar.valid( s, options ) or "" | ||
+ | end | ||
+ | return r | ||
end -- .valid() | end -- .valid() | ||
+ | |||
+ | |||
+ | |||
+ | function p.TemplatePar() | ||
+ | -- Retrieve function access for modules | ||
+ | -- Postcondition: | ||
+ | -- Return table with functions | ||
+ | return TemplatePar | ||
+ | end -- .TemplatePar() | ||
+ | |||
+ | |||
return p | return p |
Version vom 4. Mai 2013, 10:10 Uhr
--[=[ TemplatePar 2013-05-03 Template parameter utility
- check
- count
- valid
- TemplatePar()
]=]
-- Module globals local TemplatePar = { } local messagePrefix = "lua-module-TemplatePar-" local l10nDef = {} l10nDef[ "en" ] = {
dupOpt = "TemplatePar#invoke: repeated optional parameter", empty = "Error in template: undefined value for mandatory", invalid = "Error in template: invalid parameter", invalidPar = "TemplatePar#invoke: invalid parameter", noname = "TemplatePar#invoke: missing parameter name", tooLong = "Error in template: parameter too long", tooShort = "Error in template: parameter too short", undefined = "Error in template: mandatory parameter missing", unknown = "Error in template: unknown parameter name", unknownRule = "TemplatePar#invoke: unknown rule"
} l10nDef[ "de" ] = {
dupOpt = "TemplatePar#invoke: Optionsparameter wiederholt", empty = "Fehler bei Vorlage: Pflichtparameter ohne Wert", invalid = "Fehler bei Vorlage: Parameter ungültig", invalidPar = "TemplatePar#invoke: Ungültiger Parameter", noname = "TemplatePar#invoke: Parametername nicht angegeben", tooLong = "Fehler bei Vorlage: Parameter zu lang", tooShort = "Fehler bei Vorlage: Parameter zu kurz", undefined = "Fehler bei Vorlage: Pflichtparameter fehlt", unknown = "Fehler bei Vorlage: Parametername unbekannt", unknownRule = "TemplatePar#invoke: Unbekannte Regel"
} local Patterns = {
[ "ASCII" ] = "^[ -~]*$", [ "ASCII+" ] = "^[ -~]+$", [ "ASCII+1" ] = "^[!-~]+$", [ "n" ] = "^%-?[0-9]*$", -- einzelnes Minus ausschließen [ "n>0" ] = "^[0-9]*[1-9][0-9]*$", [ "N+" ] = "^%-?[1-9][0-9]*$", [ "N>0" ] = "^[1-9][0-9]*$", [ "x" ] = "^[0-9A-Fa-f]*$", [ "x+" ] = "^[0-9A-Fa-f]+$", [ "X" ] = "^[0-9A-F]*$", [ "X+" ] = "^[0-9A-F]+$", [ "+" ] = "%S"
}
function trim( s )
-- Trim string -- Precondition: -- s -- string or nil; to be trimmed -- Postcondition: -- Return trimmed string or nil local r = s if type( s ) == "string" then if s:match( "^%s*$" ) then r = "" else r = s:match( "^%s*(%S.*)$" ) r = r:match( "^(.*%S)%s*$" ) end end return r
end -- trim()
local function factory( say )
-- Retrieve localized message string in content language -- Precondition: -- say -- string; message ID -- Postcondition: -- Return some message string -- Uses: -- > messagePrefix -- > l10nDef local c = mw.language.getContentLanguage():getCode() local m = mw.message.new( messagePrefix .. say ) local r = false if m:isBlank() then local l10n = l10nDef[ c ] if not l10n then l10n = l10nDef[ "en" ] end r = l10n[ say ] else m:inLanguage( c ) r = m:plain() end if not r then r = "(((".. say .. ")))" end return r
end -- factory()
local function failure( spec, suspect, options )
-- Submit localized error message -- Precondition: -- spec -- string; message ID -- suspect -- string or nil; additional information -- options -- table or nil; optional details -- options.template -- Postcondition: -- Return string -- Uses: -- factory() local r = factory( spec ) if type( options ) == "table" then if type( options.template ) == "string" then if #options.template > 0 then r = r .. " (" .. options.template .. ")" end end end if suspect then r = r .. " " .. suspect end return r
end -- failure()
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 all template transclusion parameters -- Postcondition: -- Return table; whitespace-only values as false -- Uses: -- mw.getCurrentFrame() -- frame:getParent() local k, v local r = { } local t = mw.getCurrentFrame():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 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 finalize( submit, options )
-- Finalize message
-- Precondition:
-- submit -- string or false or nil; non-empty error message
-- options -- table or nil; optional details
-- options.noError
-- options.cat
-- options.template
-- Postcondition:
-- Return string or false
local r = false
if submit then
local opt, s
if type( options ) == "table" then
opt = options
else
opt = { }
end
if opt.noError then
r = false
else
r = "" .. submit .. ""
end
s = opt.cat
if type( s ) == "string" then
if not r then
r = ""
end
if s:find( "@@@" ) then
if type( opt.template ) == "string" then
s = s:gsub( "@@@", opt.template )
end
end
r = r .. ""
end
end
return r
end -- finalize()
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, options )
-- Perform transclusion parameter analysis -- Precondition: -- valid -- table; unique sequence of known parameters -- duty -- table; sequence of mandatory parameters -- options -- table or nil; optional details -- Postcondition: -- Return string as configured; empty if valid -- Uses: -- fetch() -- finder() -- fault() -- failure() -- 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 = failure( "unknown", r, options ) else -- all names valid 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 = failure( "undefined", r, options ) else -- all mandatory present 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 = failure( "empty", r, options ) end end end return r
end -- fix()
local function format( seek, options )
-- Check validity of one particular template parameter -- Precondition: -- seek -- string non-empty; name of template parameter -- options -- table or nil; optional details -- options.pattern -- options.key -- options.min -- options.max -- Postcondition: -- Return string with error message as configured; -- false if valid or no answer permitted -- Uses: -- > Patterns -- failure() -- mw.ustring.match() -- frame:getParent() local r = false local s local scan = false local story = mw.getCurrentFrame():getParent() story = ( story.args[ seek ] or "" ) if type( options.pattern ) == "string" then if options.key then r = failure( "duplicatedRule", false, options ) else scan = options.pattern end else if type( options.key ) == "string" then s = trim( options.key ) else s = "+" end scan = Patterns[ s ] if type( scan ) == "string" then if s == "n" then if trim( story ) == "-" then scan = false r = failure( "invalid", "'" .. seek .. "'", options ) end end else r = failure( "unknownRule", s, options ) end end if scan then if not mw.ustring.match( story, scan ) then r = failure( "invalid", "'" .. seek .. "'", options ) end end if options.min and not r then if type( options.min ) == "number" then if #story < options.min then r = failure( "tooShort", " <" .. options.min .. " '" .. seek .. "'", options ) end else r = failure( "invalidPar", "min", options ) end end if options.max and not r then if type( options.max ) == "number" then if #story > options.max then r = failure( "tooLong", " >" .. options.max .. " '" .. seek .. "'", options ) end else r = failure( "invalidPar", "max", options ) end end return r
end -- format()
TemplatePar.check = function ( options )
-- Run parameter analysis -- Precondition: -- options -- table or nil; optional details -- options.mandatory -- options.optional -- Postcondition: -- Return string with error message as configured; -- false if valid or no answer permitted -- Uses: -- fit() -- failure() -- fix() -- finalize() local duty, r if type( options ) == "table" then if type( options.mandatory ) == "table" then duty = options.mandatory else duty = { } end if type( options.optional ) ~= "table" then options.optional = { } end r = fit( duty, options.optional ) else duty = { } r = { } end if type( r ) == "string" then r = failure( "dupOpt", r, options ) else r = fix( r, duty, options ) end return finalize( r, options )
end -- TemplatePar.check()
TemplatePar.count = function ()
-- Return number of template parameters -- Postcondition: -- Return number, starting at 0 -- Uses: -- mw.getCurrentFrame() -- frame:getParent() local k, v local r = 0 local t = mw.getCurrentFrame():getParent() local o = t.args for k, v in pairs( o ) do r = r + 1 end -- for k, v return r
end -- TemplatePar.count()
TemplatePar.valid = function ( seek, options )
-- Check validity of one particular template parameter -- Precondition: -- seek -- string; name of template parameter -- options -- table or nil; optional details -- Postcondition: -- Return string with error message as configured; -- false if valid or no answer permitted -- Uses: -- trim() -- format() -- failure() -- finalize() local r if type( seek ) == "string" then r = trim( seek ) if #r == 0 then r = false end end if r then r = format( seek, options ) else r = failure( "noname", false, options ) end return finalize( r, options )
end -- TemplatePar.valid()
-- Provide external 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: -- fill() -- TemplatePar.check() local options = { mandatory = fill( frame.args[ 1 ] ), optional = fill( frame.args[ 2 ] ), cat = frame.args.cat, noError = frame.args.noError, template = frame.args.template } return TemplatePar.check( options ) or ""
end -- .check()
function p.count( frame )
-- Count number of template parameters -- Postcondition: -- Return string with digits including "0" -- Uses: -- TemplatePar.count() return tostring( TemplatePar.count() )
end -- .count()
function p.valid( frame )
-- Check validity of one particular template parameter -- Precondition: -- frame -- object; #invoke environment -- Postcondition: -- Return string with error message or "" -- Uses: -- trim() -- TemplatePar.valid() local r = false local s local options = { cat = frame.args.cat, noError = frame.args.noError, template = frame.args.template } s = trim( frame.args[ 2 ] ) if type( s ) == "string" then local sub = s:match( "^/(.*%S)/$" ) if type( sub ) == "string" then options.pattern = sub else options.key = s end end if type( frame.args.min ) == "string" then s = frame.args.min:match( "^%s*([0-9]+)%s*$" ) if s then options.min = tonumber( s ) else r = failure( "invalidPar", "min=" .. frame.args.min, options ) end end if type( frame.args.max ) == "string" then s = frame.args.max:match( "^%s*([1-9][0-9]*)%s*$" ) if s then options.max = tonumber( s ) else r = failure( "invalidPar", "max=" .. frame.args.max, options ) end end if r then r = finalize( r, options ) else s = frame.args[ 1 ] or "" r = TemplatePar.valid( s, options ) or "" end return r
end -- .valid()
function p.TemplatePar()
-- Retrieve function access for modules -- Postcondition: -- Return table with functions return TemplatePar
end -- .TemplatePar()
return p