Module:TemplatePar: Difference between revisions

Content deleted Content added
+pagename
updates + match
Line 1:
--[=[ TemplatePar 2013-0607-2809
Template parameter utility
* assert
Line 6:
* countNotEmpty
* downcase
* match
* valid
* verify
Line 18 ⟶ 19:
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 * ParameterkonfliktKonflikt 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 * ParameternameParameter 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 = {
Line 209 ⟶ 210:
return r
end -- fault()
 
 
 
local function feasible( analyze, options, abbr )
-- Check content of a value
-- Precondition:
-- analyze -- string to be analyzed
-- options -- table or nil; optional details
-- options.pattern
-- options.key
-- options.say
-- abbr -- true: abbreviated error message
-- 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
if s ~= "*" then
scan = Patterns[ s ]
end
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
if abbr then
r = show
else
r = failure( "invalid", show, options )
end
end
end
elseif s ~= "*" then
local op, n, plus = s:match( "([<!>]=?)([-0-9][%S]*)(+?)" )
if op then
n = tonumber( n )
if n then
local i = tonumber( analyze )
if i then
if op == "<" then
i = ( i < n )
elseif op == "<=" then
i = ( i <= n )
elseif op == ">" then
i = ( i > n )
elseif op == ">=" then
i = ( i >= n )
elseif op == "!=" then
i = ( i ~= n )
else
n = false
end
end
if not i then
r = "invalid"
end
elseif plus then
r = "undefined"
end
end
if not n and not r then
r = "unknownRule"
end
if r then
if options.say then
show = "'" .. options.say .. "' " .. s
else
show = s
end
if abbr then
r = show
else
r = failure( r, show, options )
end
end
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
if abbr then
r = show
else
r = failure( "invalid", show, options )
end
end
end
else
r = failure( "badPattern",
scan .. " *** " .. got,
options )
end
end
return r
end -- feasible()
 
 
Line 273 ⟶ 399:
return r
end -- fetch()
 
 
 
local function figure( append, options )
-- Extend options by rule from #invoke strings
-- Precondition:
-- append -- string or nil; requested rule
-- options -- table; details
-- ++ .key
-- ++ .pattern
-- Postcondition:
-- Return sequence table
local r = options
if type( append ) == "string" then
local story = mw.text.trim( append )
local sub = story:match( "^/(.*%S)/$" )
if type( sub ) == "string" then
sub = sub:gsub( "%%!", "|" )
sub = sub:gsub( "%%%(%(", "{{" )
sub = sub:gsub( "%%%)%)", "}}" )
options.pattern = sub
options.key = nil
else
options.key = story
options.pattern = nil
end
end
return r
end -- figure()
 
 
Line 390 ⟶ 545:
end -- for k, v
if r then
r = failure( "unknown", "'" .. r .. "'", options )
else -- all names valid
local i, s
Line 516 ⟶ 671:
-- Uses:
-- fold()
-- failure()
-- fetch()
-- fix()
Line 553 ⟶ 707:
-- analyze -- string to be analyzed
-- options -- table or nil; optional details
-- options.pattern
-- options.key
-- options.say
-- options.min
Line 562 ⟶ 714:
-- false if valid or no answer permitted
-- Uses:
-- > Patternsfeasible()
-- failure()
--local r mw.text.trim= feasible( analyze, options, false )
--local failsafe()show
-- 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
Line 668 ⟶ 768:
-- false if valid or no answer permitted
-- Uses:
-- > Patterns
-- failure()
-- mw.text.trim()
-- format()
-- failure()
Line 688 ⟶ 785:
return r
end -- formatted()
 
 
 
Line 702 ⟶ 798:
-- form()
-- mw.text.trim()
-- failure()
-- TemplatePar.assert()
-- TemplatePar.valid()
Line 712 ⟶ 809:
"noError",
"template" },
template = "&#35;invoke:TemplatePar|".. action .. "|"
}
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,
Line 722 ⟶ 819:
template = frame.args.template
}
ifoptions type= figure( sframe.args[ )2 ==], "string"options 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*$" )
Line 861 ⟶ 948:
-- mw.getCurrentFrame()
-- frame:getParent()
-- mw.ustring.lowerflat()
-- fault()
-- failure()
local t = mw.getCurrentFrame():getParent()
return flat( t.args, options )
Line 959 ⟶ 1,044:
"noError",
"template" },
template = "&#35;invoke:TemplatePar|check|"
}
local r = form( false, options )
Line 996 ⟶ 1,081:
return tostring( TemplatePar.countNotEmpty() )
end -- .countNotEmpty()
 
 
 
function p.match( frame )
-- Combined analysis of parameters and their values
-- Postcondition:
-- Return string with error message or ""
-- Uses:
-- mw.text.trim()
-- mw.ustring.lower()
-- failure()
-- form()
-- TemplatePar.downcase()
-- figure()
-- feasible()
-- fault()
-- finalize()
local r = false
local options = { cat = frame.args.cat,
low = frame.args.low,
noError = frame.args.noError,
template = frame.args.template
}
local k, v, s
local params = { }
for k, v in pairs( frame.args ) do
if type( k ) == "number" then
s, v = v:match( "^ *([^=]+) *= *(%S.*%S*) *$" )
if s then
s = mw.text.trim( s )
if s == "" then
s = false
end
end
if s then
if options.low then
s = mw.ustring.lower( s )
end
if params[ s ] then
s = params[ s ]
s[ #s + 1 ] = v
else
params[ s ] = { v }
end
else
r = failure( "invalidPar", tostring( k ), options )
break -- for k, v
end
end
end -- for k, v
if not r then
s = { }
for k, v in pairs( params ) do
s[ #s + 1 ] = k
end -- for k, v
options.optional = s
r = form( true, options )
end
if not r then
local errMiss, errValues, lack, rule
local targs = frame:getParent().args
options.optional = nil
if options.low then
targs = TemplatePar.downcase()
else
targs = frame:getParent().args
end
errMiss = false
errValues = false
for k, v in pairs( params ) do
options.say = k
errValue = false
s = targs[ k ]
if s then
if s == "" then
lack = true
else
lack = false
end
else
s = ""
lack = true
end
for r, rule in pairs( v ) do
options = figure( rule, options )
r = feasible( s, options, true )
if r then
if lack then
if errMiss then
errMiss = errMiss .. ", '" .. k .. "'"
else
errMiss = "'" .. k .. "'"
end
elseif not errMiss then
errValues = fault( errValues, r )
end
break -- for r, rule
end
end -- for s, rule
end -- for k, v
r = ( errMiss or errValues )
if r then
if errMiss then
r = failure( "undefined", errMiss, options )
else
r = failure( "invalid", errValues, options )
end
r = finalize( r, options )
end
end
return r or ""
end -- .match()