Modul:TemplatePar: Unterschied zwischen den Versionen
te>PerfektesChaos (Migration zur Umparametrisierung abgeschlossen; keine Einbindungen mehr) |
te>PerfektesChaos (update) |
||
Zeile 1: | Zeile 1: | ||
− | --[=[ TemplatePar 2013-06- | + | --[=[ TemplatePar 2013-06-10 |
Template parameter utility | Template parameter utility | ||
+ | * assert | ||
* check | * check | ||
* count | * count | ||
Zeile 108: | Zeile 109: | ||
end | end | ||
return r | return r | ||
− | end -- | + | end -- containsCJK() |
Zeile 545: | Zeile 546: | ||
− | local function format( | + | local function format( analyze, options ) |
− | -- Check validity of | + | -- Check validity of a value |
-- Precondition: | -- Precondition: | ||
− | -- | + | -- analyze -- string to be analyzed |
-- options -- table or nil; optional details | -- options -- table or nil; optional details | ||
-- options.pattern | -- options.pattern | ||
-- options.key | -- options.key | ||
− | -- options. | + | -- options.say |
-- options.min | -- options.min | ||
-- options.max | -- options.max | ||
Zeile 560: | Zeile 561: | ||
-- Uses: | -- Uses: | ||
-- > Patterns | -- > Patterns | ||
− | |||
− | |||
− | |||
-- failure() | -- failure() | ||
-- mw.text.trim() | -- mw.text.trim() | ||
-- failsafe() | -- failsafe() | ||
-- containsCJK() | -- containsCJK() | ||
− | local r = false | + | local r = false |
− | local s | + | local s = false |
− | local | + | local show = nil |
− | local | + | local scan = false |
− | if type( options ) | + | if type( options.pattern ) == "string" then |
− | + | if options.key then | |
− | + | r = failure( "dupRule", false, options ) | |
− | + | else | |
− | + | scan = options.pattern | |
+ | end | ||
else | else | ||
− | + | if type( options.key ) == "string" then | |
− | + | s = mw.text.trim( options.key ) | |
− | |||
− | |||
− | if type( options. | ||
− | |||
− | |||
− | |||
− | |||
− | |||
else | else | ||
− | + | s = "+" | |
− | + | end | |
− | + | scan = Patterns[ s ] | |
− | + | if type( scan ) == "string" then | |
− | + | if s == "n" or s == "0,0" or s == "0.0" then | |
− | + | if not analyze:match( "[0-9]" ) then | |
− | + | scan = false | |
− | + | if options.say then | |
− | + | show = "'" .. options.say .. "'" | |
− | |||
− | |||
− | |||
− | |||
end | end | ||
+ | r = failure( "invalid", show, options ) | ||
end | end | ||
− | |||
− | |||
end | end | ||
+ | else | ||
+ | r = failure( "unknownRule", s, options ) | ||
end | end | ||
− | |||
− | |||
end | end | ||
if scan then | if scan then | ||
− | local legal, got = pcall( failsafe, | + | local legal, got = pcall( failsafe, analyze, scan ) |
if legal then | if legal then | ||
if not got then | if not got then | ||
if s == "aa" then | if s == "aa" then | ||
− | got = containsCJK( | + | got = containsCJK( analyze ) |
end | end | ||
if not got then | if not got then | ||
− | + | if options.say then | |
− | r | + | show = "'" .. options.say .. "'" |
+ | end | ||
+ | r = failure( "invalid", show, options ) | ||
end | end | ||
end | end | ||
Zeile 639: | Zeile 627: | ||
end | end | ||
end | end | ||
− | if # | + | if #analyze < options.min and not r then |
− | + | show = " <" .. options.min | |
− | + | if options.say then | |
− | + | show = show .. " '" .. options.say .. "'" | |
+ | end | ||
+ | r = failure( "tooShort", show, options ) | ||
end | end | ||
else | else | ||
Zeile 650: | Zeile 640: | ||
if options.max and not r then | if options.max and not r then | ||
if type( options.max ) == "number" then | if type( options.max ) == "number" then | ||
− | if # | + | if #analyze > options.max then |
− | + | show = " >" .. options.max | |
− | + | if options.say then | |
− | + | show = show .. " '" .. options.say .. "'" | |
+ | end | ||
+ | r = failure( "tooLong", show, options ) | ||
end | end | ||
else | else | ||
Zeile 661: | Zeile 653: | ||
return r | return r | ||
end -- format() | end -- format() | ||
+ | |||
+ | |||
+ | |||
+ | local function formatted( assignment, access, options ) | ||
+ | -- Check validity of one particular parameter in a collection | ||
+ | -- Precondition: | ||
+ | -- assignment -- collection | ||
+ | -- access -- id of parameter in collection | ||
+ | -- options -- table or nil; optional details | ||
+ | -- Postcondition: | ||
+ | -- Return string with error message as configured; | ||
+ | -- false if valid or no answer permitted | ||
+ | -- Uses: | ||
+ | -- > Patterns | ||
+ | -- failure() | ||
+ | -- mw.text.trim() | ||
+ | -- format() | ||
+ | -- failure() | ||
+ | local r = false | ||
+ | if type( assignment ) == "table" then | ||
+ | local story = assignment.args[ access ] | ||
+ | if type( story ) == "string" then | ||
+ | if type( options ) ~= "table" then | ||
+ | options = { } | ||
+ | end | ||
+ | options.say = access | ||
+ | r = format( story, options ) | ||
+ | else | ||
+ | r = failure( "invalid", access, options ) | ||
+ | end | ||
+ | end | ||
+ | return r | ||
+ | end -- formatted() | ||
+ | |||
+ | |||
+ | |||
+ | TemplatePar.assert = function ( analyze, append, options ) | ||
+ | -- Perform parameter analysis on a single string | ||
+ | -- Precondition: | ||
+ | -- analyze -- string to be analyzed | ||
+ | -- append -- string: append error message, prepending <br /> | ||
+ | -- false or nil: throw error with message | ||
+ | -- options -- table; optional details | ||
+ | -- Postcondition: | ||
+ | -- Return string with error message as configured; | ||
+ | -- false if valid | ||
+ | -- Uses: | ||
+ | -- format() | ||
+ | local r = format( analyze, options ) | ||
+ | if ( r ) then | ||
+ | if ( type( append ) == "string" ) then | ||
+ | if ( append ~= "" ) then | ||
+ | r = append .. "<br />" .. r | ||
+ | end | ||
+ | else | ||
+ | error( r, 0 ) | ||
+ | end | ||
+ | end | ||
+ | return r | ||
+ | end -- TemplatePar.assert() | ||
Zeile 738: | Zeile 790: | ||
− | TemplatePar.valid = function ( | + | TemplatePar.valid = function ( access, options ) |
-- Check validity of one particular template parameter | -- Check validity of one particular template parameter | ||
-- Precondition: | -- Precondition: | ||
− | -- | + | -- access -- id of parameter in template transclusion |
-- options -- table or nil; optional details | -- options -- table or nil; optional details | ||
-- Postcondition: | -- Postcondition: | ||
Zeile 748: | Zeile 800: | ||
-- Uses: | -- Uses: | ||
-- mw.text.trim() | -- mw.text.trim() | ||
− | -- | + | -- TemplatePar.downcase() |
+ | -- mw.getCurrentFrame() | ||
+ | -- frame:getParent() | ||
+ | -- formatted() | ||
-- failure() | -- failure() | ||
-- finalize() | -- finalize() | ||
local r | local r | ||
− | if type( | + | if type( access ) == "string" then |
− | r = mw.text.trim( | + | r = mw.text.trim( access ) |
if #r == 0 then | if #r == 0 then | ||
r = false | r = false | ||
Zeile 759: | Zeile 814: | ||
end | end | ||
if r then | if r then | ||
− | r = | + | local params |
+ | if type( options ) ~= "table" then | ||
+ | options = { } | ||
+ | end | ||
+ | if options.low then | ||
+ | params = TemplatePar.downcase( options ) | ||
+ | else | ||
+ | params = mw.getCurrentFrame():getParent() | ||
+ | end | ||
+ | r = formatted( params, access, options ) | ||
else | else | ||
r = failure( "noname", false, options ) | r = failure( "noname", false, options ) | ||
Zeile 905: | Zeile 969: | ||
else | else | ||
s = frame.args[ 1 ] or "" | s = frame.args[ 1 ] or "" | ||
+ | r = tonumber( s ) | ||
+ | if ( r ) then | ||
+ | s = r | ||
+ | end | ||
r = TemplatePar.valid( s, options ) | r = TemplatePar.valid( s, options ) | ||
end | end |
Version vom 13. Juni 2013, 09:54 Uhr
Die Dokumentation für dieses Modul kann unter Modul:TemplatePar/Doku erstellt werden
--[=[ TemplatePar 2013-06-10
Template parameter utility
* assert
* check
* count
* countNotEmpty
* downcase
* valid
* verify
* TemplatePar()
]=]
-- Module globals
local TemplatePar = { }
local messagePrefix = "lua-module-TemplatePar-"
local l10nDef = {}
l10nDef[ "en" ] = {
badPattern = "#invoke:TemplatePar * pattern syntax error",
dupOpt = "#invoke:TemplatePar * repeated optional parameter",
dupRule = "#invoke:TemplatePar * parameter conflict key/pattern",
empty = "Error in template * undefined value for mandatory",
invalid = "Error in template * invalid parameter",
invalidPar = "#invoke:TemplatePar * invalid parameter",
minmax = "#invoke:TemplatePar * min > max",
multiSpell = "Error in template * multiple spelling of parameter",
noErrorCat = "#invoke:TemplatePar * noError and missing category",
noname = "#invoke:TemplatePar * 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 = "#invoke:TemplatePar * unknown rule"
}
l10nDef[ "de" ] = {
badPattern = "#invoke:TemplatePar * Syntaxfehler des pattern",
dupOpt = "#invoke:TemplatePar * Optionsparameter wiederholt",
dupRule = "#invoke:TemplatePar * Parameterkonflikt key/pattern",
empty = "Fehler bei Vorlage * Pflichtparameter ohne Wert",
invalid = "Fehler bei Vorlage * Parameter ungültig",
invalidPar = "#invoke:TemplatePar * Ungültiger Parameter",
minmax = "#invoke:TemplatePar * min > max",
multiSpell = "Fehler bei Vorlage * Mehrere Parameter-Schreibweisen",
noErrorCat = "#invoke:TemplatePar * noError und keine Kategorie",
noname = "#invoke:TemplatePar * 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 = "#invoke:TemplatePar * Unbekannte Regel"
}
local Patterns = {
[ "ASCII" ] = "^[ -~]*$",
[ "ASCII+" ] = "^[ -~]+$",
[ "ASCII+1" ] = "^[!-~]+$",
[ "n" ] = "^%-?[0-9]*$",
[ "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]+$",
[ "0,0" ] = "^%-?[0-9]*,?[0-9]*$",
[ "0,0+" ] = "^%-?[0-9]+,[0-9]+$",
[ "0,0+?" ] = "^%-?[0-9]+,?[0-9]*$",
[ "0.0" ] = "^%-?[0-9]*%.?[0-9]*$",
[ "0.0+" ] = "^%-?[0-9]+%.[0-9]+$",
[ "0.0+?" ] = "^%-?[0-9]+%.?[0-9]*$",
[ ".0+" ] = "^%-?[0-9]*%.?[0-9]+$",
[ "ID" ] = "^[A-Za-z]?[A-Za-z_0-9]*$",
[ "ID+" ] = "^[A-Za-z][A-Za-z_0-9]*$",
[ "ABC" ] = "^[A-Z]*$",
[ "ABC+" ] = "^[A-Z]+$",
[ "Abc" ] = "^[A-Z]*[a-z]*$",
[ "Abc+" ] = "^[A-Z][a-z]+$",
[ "abc" ] = "^[a-z]*$",
[ "abc+" ] = "^[a-z]+$",
[ "aBc+" ] = "^[a-z]+[A-Z][A-Za-z]*$",
[ "base64" ] = "^[A-Za-z0-9%+/]*$",
[ "base64+" ] = "^[A-Za-z0-9%+/]+$",
[ "aa" ] = "[%a%a].*[%a%a]",
[ "+" ] = "%S"
}
local patternCJK = false
local function containsCJK( s )
-- Is any CJK character present?
-- Precondition:
-- s -- string
-- Postcondition:
-- Return false iff no CJK present
-- Uses:
-- >< patternCJK
-- mw.ustring.char()
-- mw.ustring.match()
local r = false
if not patternCJK then
patternCJK = mw.ustring.char( 91,
13312, 45, 40959,
131072, 45, 178207,
93 )
end
if mw.ustring.match( s, patternCJK ) then
r = true
end
return r
end -- containsCJK()
local function factory( say )
-- Retrieve localized message string in content language
-- Precondition:
-- say -- string; message ID
-- Postcondition:
-- Return some message string
-- Uses:
-- > messagePrefix
-- > l10nDef
-- mw.language.getContentLanguage()
-- mw.message.new()
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 failsafe( story, scan )
-- Test for match (possibly user-defined with syntax error)
-- Precondition:
-- story -- string; parameter value
-- scan -- string; pattern
-- Postcondition:
-- Return nil, if not matching, else non-nil
-- Uses:
-- mw.ustring.match()
return mw.ustring.match( story, scan )
end -- failsafe()
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( light, options )
-- Return regular table with all parameters
-- Precondition:
-- light -- true: template transclusion; false: #invoke
-- options -- table; optional details
-- options.low
-- Postcondition:
-- Return table; whitespace-only values as false
-- Uses:
-- TemplatePar.downcase()
-- mw.getCurrentFrame()
-- frame:getParent()
local g, k, v
local r = { }
if options.low then
g = TemplatePar.downcase( options )
else
g = mw.getCurrentFrame()
if light then
g = g:getParent()
end
g = g.args
end
if type( g ) == "table" then
r = { }
for k, v in pairs( g ) 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
else
r = g
end
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
-- Uses:
-- mw.text.split()
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
-- Uses:
-- factory()
local r = false
if submit then
local opt, s
if type( options ) == "table" then
opt = options
else
opt = { }
end
if opt.noError then
if not opt.cat then
r = submit .. " " .. factory( "noErrorCat" )
end
else
r = submit
end
if r then
r = "<span class='error'>" .. r .. "</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()
local function finder( haystack, needle )
-- Find needle in haystack sequence
-- Precondition:
-- haystack -- table; sequence of key names, downcased if low
-- 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 fix( valid, duty, got, options )
-- Perform parameter analysis
-- Precondition:
-- valid -- table; unique sequence of known parameters
-- duty -- table; sequence of mandatory parameters
-- got -- table; sequence of current parameters
-- options -- table or nil; optional details
-- Postcondition:
-- Return string as configured; empty if valid
-- Uses:
-- finder()
-- fault()
-- failure()
-- fed()
local k, v
local r = false
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 flat( collection, options )
-- Return all table elements with downcased string
-- Precondition:
-- collection -- table; k=v pairs
-- options -- table or nil; optional messaging details
-- Postcondition:
-- Return table, may be empty; or string with error message.
-- Uses:
-- mw.ustring.lower()
-- fault()
-- failure()
local k, v
local r = { }
local e = false
for k, v in pairs( collection ) do
if type ( k ) == "string" then
k = mw.ustring.lower( k )
if r[ k ] then
e = fault( e, k )
end
end
r[ k ] = v
end -- for k, v
if e then
r = failure( "multiSpell", e, options )
end
return r
end -- flat()
local function fold( options )
-- Merge two tables, create new sequence if both not empty
-- Precondition:
-- options -- table; details
-- options.mandatory sequence to keep unchanged
-- options.optional sequence to be appended
-- options.low downcased expected
-- Postcondition:
-- Return merged table, or message string if error
-- Uses:
-- finder()
-- fault()
-- failure()
-- flat()
local i, e, r, s
local base = options.mandatory
local extend = options.optional
if #base == 0 then
if #extend == 0 then
r = { }
else
r = extend
end
else
if #extend == 0 then
r = base
else
e = false
for i = 1, #extend do
s = extend[ i ]
if finder( base, s ) then
e = fault( e, s )
end
end -- for i
if e then
r = failure( "dupOpt", e, options )
else
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
if options.low and type( r ) == "table" then
r = flat( r, options )
end
return r
end -- fold()
local function form( light, options )
-- Run parameter analysis on current environment
-- Precondition:
-- light -- true: template transclusion; false: #invoke
-- options -- table or nil; optional details
-- options.mandatory
-- options.optional
-- Postcondition:
-- Return string with error message as configured;
-- false if valid
-- Uses:
-- fold()
-- failure()
-- fetch()
-- fix()
-- finalize()
local duty, r
if type( options ) == "table" then
if type( options.mandatory ) ~= "table" then
options.mandatory = { }
end
duty = options.mandatory
if type( options.optional ) ~= "table" then
options.optional = { }
end
r = fold( options )
else
options = { }
duty = { }
r = { }
end
if type( r ) == "table" then
local got = fetch( light, options )
if type( got ) == "table" then
r = fix( r, duty, got, options )
else
r = got
end
end
return finalize( r, options )
end -- form()
local function format( analyze, options )
-- Check validity of a value
-- Precondition:
-- analyze -- string to be analyzed
-- options -- table or nil; optional details
-- options.pattern
-- options.key
-- options.say
-- options.min
-- options.max
-- Postcondition:
-- Return string with error message as configured;
-- false if valid or no answer permitted
-- Uses:
-- > Patterns
-- failure()
-- mw.text.trim()
-- failsafe()
-- containsCJK()
local r = false
local s = false
local show = nil
local scan = false
if type( options.pattern ) == "string" then
if options.key then
r = failure( "dupRule", false, options )
else
scan = options.pattern
end
else
if type( options.key ) == "string" then
s = mw.text.trim( options.key )
else
s = "+"
end
scan = Patterns[ s ]
if type( scan ) == "string" then
if s == "n" or s == "0,0" or s == "0.0" then
if not analyze:match( "[0-9]" ) then
scan = false
if options.say then
show = "'" .. options.say .. "'"
end
r = failure( "invalid", show, options )
end
end
else
r = failure( "unknownRule", s, options )
end
end
if scan then
local legal, got = pcall( failsafe, analyze, scan )
if legal then
if not got then
if s == "aa" then
got = containsCJK( analyze )
end
if not got then
if options.say then
show = "'" .. options.say .. "'"
end
r = failure( "invalid", show, options )
end
end
else
r = failure( "badPattern",
scan .. " *** " .. got,
options )
end
end
if options.min and not r then
if type( options.min ) == "number" then
if type( options.max ) == "number" then
if options.max < options.min then
r = failure( "minmax",
tostring( options.min )
.. " > " ..
tostring( options.max ),
options )
end
end
if #analyze < options.min and not r then
show = " <" .. options.min
if options.say then
show = show .. " '" .. options.say .. "'"
end
r = failure( "tooShort", show, options )
end
else
r = failure( "invalidPar", "min", options )
end
end
if options.max and not r then
if type( options.max ) == "number" then
if #analyze > options.max then
show = " >" .. options.max
if options.say then
show = show .. " '" .. options.say .. "'"
end
r = failure( "tooLong", show, options )
end
else
r = failure( "invalidPar", "max", options )
end
end
return r
end -- format()
local function formatted( assignment, access, options )
-- Check validity of one particular parameter in a collection
-- Precondition:
-- assignment -- collection
-- access -- id of parameter in collection
-- options -- table or nil; optional details
-- Postcondition:
-- Return string with error message as configured;
-- false if valid or no answer permitted
-- Uses:
-- > Patterns
-- failure()
-- mw.text.trim()
-- format()
-- failure()
local r = false
if type( assignment ) == "table" then
local story = assignment.args[ access ]
if type( story ) == "string" then
if type( options ) ~= "table" then
options = { }
end
options.say = access
r = format( story, options )
else
r = failure( "invalid", access, options )
end
end
return r
end -- formatted()
TemplatePar.assert = function ( analyze, append, options )
-- Perform parameter analysis on a single string
-- Precondition:
-- analyze -- string to be analyzed
-- append -- string: append error message, prepending <br />
-- false or nil: throw error with message
-- options -- table; optional details
-- Postcondition:
-- Return string with error message as configured;
-- false if valid
-- Uses:
-- format()
local r = format( analyze, options )
if ( r ) then
if ( type( append ) == "string" ) then
if ( append ~= "" ) then
r = append .. "<br />" .. r
end
else
error( r, 0 )
end
end
return r
end -- TemplatePar.assert()
TemplatePar.check = function ( options )
-- Run parameter analysis on current template environment
-- Precondition:
-- options -- table or nil; optional details
-- options.mandatory
-- options.optional
-- Postcondition:
-- Return string with error message as configured;
-- false if valid
-- Uses:
-- form()
return form( true, 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.countNotEmpty = function ()
-- Return number of template parameters with more than whitespace
-- 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
if not v:match( "^%s*$" ) then
r = r + 1
end
end -- for k, v
return r
end -- TemplatePar.countNotEmpty()
TemplatePar.downcase = function ( options )
-- Return all template parameters with downcased name
-- Precondition:
-- options -- table or nil; optional messaging details
-- Postcondition:
-- Return table, may be empty; or string with error message.
-- Uses:
-- mw.getCurrentFrame()
-- frame:getParent()
-- mw.ustring.lower()
-- fault()
-- failure()
local t = mw.getCurrentFrame():getParent()
return flat( t.args, options )
end -- TemplatePar.downcase()
TemplatePar.valid = function ( access, options )
-- Check validity of one particular template parameter
-- Precondition:
-- access -- id of parameter in template transclusion
-- options -- table or nil; optional details
-- Postcondition:
-- Return string with error message as configured;
-- false if valid or no answer permitted
-- Uses:
-- mw.text.trim()
-- TemplatePar.downcase()
-- mw.getCurrentFrame()
-- frame:getParent()
-- formatted()
-- failure()
-- finalize()
local r
if type( access ) == "string" then
r = mw.text.trim( access )
if #r == 0 then
r = false
end
end
if r then
local params
if type( options ) ~= "table" then
options = { }
end
if options.low then
params = TemplatePar.downcase( options )
else
params = mw.getCurrentFrame():getParent()
end
r = formatted( params, access, options )
else
r = failure( "noname", false, options )
end
return finalize( r, options )
end -- TemplatePar.valid()
TemplatePar.verify = function ( options )
-- Perform #invoke parameter analysis
-- Precondition:
-- options -- table or nil; optional details
-- Postcondition:
-- Return string with error message as configured;
-- false if valid
-- Uses:
-- form()
return form( false, options )
end -- TemplatePar.verify()
-- 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:
-- form()
-- fill()
local options = { optional = { "all",
"opt",
"cat",
"low",
"noError",
"template" },
template = "#invoke:TemplatePar|check|"
}
local r = form( false, options )
if not r then
options = { mandatory = fill( frame.args.all ),
optional = fill( frame.args.opt ),
cat = frame.args.cat,
low = frame.args.low,
noError = frame.args.noError,
template = frame.args.template
}
r = form( true, options )
end
return r 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.countNotEmpty( frame )
-- Count number of template parameters which are not empty
-- Postcondition:
-- Return string with digits including "0"
-- Uses:
-- TemplatePar.countNotEmpty()
return tostring( TemplatePar.countNotEmpty() )
end -- .countNotEmpty()
function p.valid( frame )
-- Check validity of one particular template parameter
-- Precondition:
-- frame -- object; #invoke environment
-- Postcondition:
-- Return string with error message or ""
-- Uses:
-- form()
-- mw.text.trim()
-- TemplatePar.valid()
local options = { mandatory = { "1" },
optional = { "2",
"cat",
"low",
"max",
"min",
"noError",
"template" },
template = "#invoke:TemplatePar|valid|"
}
local r = form( false, options )
if not r then
local s = mw.text.trim( frame.args[ 2 ] )
options = { cat = frame.args.cat,
low = frame.args.low,
noError = frame.args.noError,
template = frame.args.template
}
if type( s ) == "string" then
local sub = s:match( "^/(.*%S)/$" )
if type( sub ) == "string" then
sub = sub:gsub( "%%!", "|" )
sub = sub:gsub( "%%%(%(", "{{" )
sub = sub:gsub( "%%%)%)", "}}" )
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 = tonumber( s )
if ( r ) then
s = r
end
r = TemplatePar.valid( s, options )
end
end
return r or ""
end -- .valid()
function p.TemplatePar()
-- Retrieve function access for modules
-- Postcondition:
-- Return table with functions
return TemplatePar
end -- .TemplatePar()
return p