Jump to content
Toggle menu
  • 8 articles
  • 75 files
  • 7 users
  • 37.8K edits
Neodyland Wiki
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:TemplatePar: Difference between revisions

From Neodyland Wiki
m Leyo moved page Module:Modul:TemplatePar to Module:TemplatePar without leaving a redirect: fix
mNo edit summary
Line 1: Line 1:
--[=[ TemplatePar 2013-07-09
--[=[ TemplatePar 2013-07-09Template parameter utility* assert* check* count
Template parameter utility
* countNotEmpty* downcase* match* valid* verify* TemplatePar()]=]
* assert
-- Module globalslocal TemplatePar = { }
* check
local messagePrefix = "lua-module-TemplatePar-"local l10nDef = {}
* count
* countNotEmpty
* downcase
* match
* valid
* verify
* TemplatePar()
]=]
 
 
 
-- Module globals
local TemplatePar = { }
local messagePrefix = "lua-module-TemplatePar-"
local l10nDef = {}
l10nDef[ "en" ] = {
l10nDef[ "en" ] = {
     badPattern  = "#invoke:TemplatePar pattern syntax error",
     badPattern  = "#invoke:TemplatePar pattern syntax error",
Line 33: Line 18:
     undefined  = "Error in template * mandatory parameter missing",
     undefined  = "Error in template * mandatory parameter missing",
     unknown    = "Error in template * unknown parameter name",
     unknown    = "Error in template * unknown parameter name",
     unknownRule = "#invoke:TemplatePar unknown rule"
     unknownRule = "#invoke:TemplatePar unknown rule"}l10nDef[ "de" ]  = {
}
l10nDef[ "de" ]  = {
     badPattern  = "#invoke:TemplatePar Syntaxfehler des pattern",
     badPattern  = "#invoke:TemplatePar Syntaxfehler des pattern",
     dupOpt      = "#invoke:TemplatePar Optionsparameter wiederholt",
     dupOpt      = "#invoke:TemplatePar Optionsparameter wiederholt",
Line 50: Line 33:
     undefined  = "Fehler bei Vorlage * Pflichtparameter fehlt",
     undefined  = "Fehler bei Vorlage * Pflichtparameter fehlt",
     unknown    = "Fehler bei Vorlage * Parametername unbekannt",
     unknown    = "Fehler bei Vorlage * Parametername unbekannt",
     unknownRule = "#invoke:TemplatePar Unbekannte Regel"
     unknownRule = "#invoke:TemplatePar Unbekannte Regel"}local Patterns = {
}
     [ "ASCII" ]  = "^[ -~]*$",   [ "ASCII+" ]  = "^[ -~]+$",
local Patterns = {
     [ "ASCII+1" ]  = "^[!-~]+$",   [ "n" ]        = "^%-?[0-9]*$",
     [ "ASCII" ]  = "^[ -~]*$",
    [ "ASCII+" ]  = "^[ -~]+$",
     [ "ASCII+1" ]  = "^[!-~]+$",
    [ "n" ]        = "^%-?[0-9]*$",
     [ "n>0" ]      = "^[0-9]*[1-9][0-9]*$",
     [ "n>0" ]      = "^[0-9]*[1-9][0-9]*$",
     [ "N+" ]      = "^%-?[1-9][0-9]*$",
     [ "N+" ]      = "^%-?[1-9][0-9]*$",   [ "N>0" ]      = "^[1-9][0-9]*$",
    [ "N>0" ]      = "^[1-9][0-9]*$",
     [ "x" ]        = "^[0-9A-Fa-f]*$",   [ "x+" ]      = "^[0-9A-Fa-f]+$",
     [ "x" ]        = "^[0-9A-Fa-f]*$",
     [ "X" ]        = "^[0-9A-F]*$",   [ "X+" ]      = "^[0-9A-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]+$",
Line 72: Line 48:
     [ ".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]*$",
     [ "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]+$",   [ "Abc" ]      = "^[A-Z]*[a-z]*$",
     [ "ABC+" ]    = "^[A-Z]+$",
     [ "Abc+" ]    = "^[A-Z][a-z]+$",   [ "abc" ]      = "^[a-z]*$",
    [ "Abc" ]      = "^[A-Z]*[a-z]*$",
     [ "abc+" ]    = "^[a-z]+$",   [ "aBc+" ]    = "^[a-z]+[A-Z][A-Za-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%+/]*$",
     [ "base64+" ]  = "^[A-Za-z0-9%+/]+$",
     [ "base64+" ]  = "^[A-Za-z0-9%+/]+$",   [ "aa" ]      = "[%a%a].*[%a%a]",
    [ "aa" ]      = "[%a%a].*[%a%a]",
     [ "pagename" ] = string.format( "^[^#<>%%[%%]|{}%s%-s%s]+$",
     [ "pagename" ] = string.format( "^[^#<>%%[%%]|{}%s%-s%s]+$",
                                     1, 31, 127 ),
                                     1, 31, 127 ),   [ "+" ]        = "%S"}
    [ "+" ]        = "%S"
local patternCJK = falselocal function containsCJK( s )
}
     -- Is any CJK character present?   -- Precondition:   --    s  -- string
local patternCJK = false
     -- Postcondition:   --    Return false iff no CJK present   -- Uses:
 
     --    >< patternCJK   --    mw.ustring.char()
 
     --    mw.ustring.match()   local r = false   if not patternCJK then
 
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,
         patternCJK = mw.ustring.char( 91,
                                       13312, 45,  40959,
                                       13312, 45,  40959,
                                       131072, 45, 178207,
                                       131072, 45, 178207,
                                       93 )
                                       93 )   end
    end
     if mw.ustring.match( s, patternCJK ) then       r = true   end   return r
     if mw.ustring.match( s, patternCJK ) then
end -- containsCJK()local function factory( say )
        r = true
     -- Retrieve localized message string in content language   -- Precondition:
    end
     --    say  -- string; message ID   -- Postcondition:
    return r
     --    Return some message string   -- Uses:   --    >  messagePrefix
end -- containsCJK()
     --    >  l10nDef   --    mw.language.getContentLanguage()
 
 
 
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()
     --    mw.message.new()
     local c = mw.language.getContentLanguage():getCode()
     local c = mw.language.getContentLanguage():getCode()
     local m = mw.message.new( messagePrefix .. say )
     local m = mw.message.new( messagePrefix .. say )   local r = false
    local r = false
     if m:isBlank() then       local l10n = l10nDef[ c ]       if not l10n then
     if m:isBlank() then
             l10n = l10nDef[ "en" ]       end       r = l10n[ say ]   else
        local l10n = l10nDef[ c ]
         m:inLanguage( c )       r = m:plain()   end   if not r then
        if not l10n then
         r = "(((".. say .. ")))"   end   return rend -- factory()
             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 )
local function failsafe( story, scan )
     -- Test for match (possibly user-defined with syntax error)
     -- Test for match (possibly user-defined with syntax error)
     -- Precondition:
     -- Precondition:   --    story  -- string; parameter value
    --    story  -- string; parameter value
     --    scan  -- string; pattern   -- Postcondition:
     --    scan  -- string; pattern
     --    Return nil, if not matching, else non-nil   -- Uses:
    -- Postcondition:
     --    mw.ustring.match()   return  mw.ustring.match( story, scan )
     --    Return nil, if not matching, else non-nil
end -- failsafe()local function failure( spec, suspect, options )
    -- Uses:
     -- Submit localized error message   -- Precondition:
     --    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
     --    spec    -- string; message ID
     --    suspect  -- string or nil; additional information
     --    suspect  -- string or nil; additional information
     --    options  -- table or nil; optional details
     --    options  -- table or nil; optional details
     --                options.template
     --                options.template   -- Postcondition:
    -- Postcondition:
     --    Return string   -- Uses:   --    factory()
     --    Return string
     local r = factory( spec )   if type( options ) == "table" then
    -- Uses:
    --    factory()
     local r = factory( spec )
    if type( options ) == "table" then
         if type( options.template ) == "string" then
         if type( options.template ) == "string" then
             if #options.template > 0 then
             if #options.template > 0 then
                 r = r .. " (" .. options.template .. ")"
                 r = r .. " (" .. options.template .. ")"           end
            end
         end   end   if suspect then       r = r .. ": " .. suspect   end
         end
     return rend -- failure()local function fault( store, key )
    end
     -- Add key to collection string and insert separator   -- Precondition:
    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
     --    store  -- string or nil or false; collection string
     --    key    -- string or number; to be appended
     --    key    -- string or number; to be appended   -- Postcondition:
    -- Postcondition:
     --    Return string; extended   local r   local s
     --    Return string; extended
     if type( key ) == "number" then       s = tostring( key )   else
    local r
         s = key   end   if store then       r = store .. "; " .. s   else
    local s
         r = s   end   return rend -- fault()
     if type( key ) == "number" then
local function feasible( analyze, options, abbr )   -- Check content of a value
        s = tostring( key )
     -- Precondition:   --    analyze  -- string to be analyzed
    else
         s = key
    end
    if store then
        r = store .. "; " .. s
    else
         r = s
    end
    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  -- table or nil; optional details
     --                options.pattern
     --                options.pattern   --                options.key
    --                options.key
     --                options.say
     --                options.say
     --    abbr    -- true: abbreviated error message
     --    abbr    -- true: abbreviated error message   -- Postcondition:
    -- Postcondition:
     --    Return string with error message as configured;
     --    Return string with error message as configured;
     --            false if valid or no answer permitted
     --            false if valid or no answer permitted   -- Uses:
    -- Uses:
     --    >  Patterns   --    failure()   --    mw.text.trim()
     --    >  Patterns
     --    failsafe()   --    containsCJK()   local r    = false
    --    failure()
     local s    = false   local show = nil   local scan = false
    --    mw.text.trim()
     if type( options.pattern ) == "string" then       if options.key then
     --    failsafe()
             r = failure( "dupRule", false, options )       else
    --    containsCJK()
             scan = options.pattern       end   else
    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
         if type( options.key ) == "string" then
             s = mw.text.trim( options.key )
             s = mw.text.trim( options.key )       else           s = "+"
        else
         end       if s ~= "*" then           scan = Patterns[ s ]       end
            s = "+"
         end
        if s ~= "*" then
            scan = Patterns[ s ]
        end
         if type( scan ) == "string" then
         if type( scan ) == "string" then
             if s == "n" or s == "0,0" or s == "0.0" then
             if s == "n" or s == "0,0" or s == "0.0" then
                 if not analyze:match( "[0-9]" ) then
                 if not analyze:match( "[0-9]" ) then
                     scan = false
                     scan = false                   if options.say then
                    if options.say then
                         show = "'" .. options.say .. "'"                   end
                         show = "'" .. options.say .. "'"
                     if abbr then                       r = show
                    end
                     if abbr then
                        r = show
                     else
                     else
                         r = failure( "invalid", show, options )
                         r = failure( "invalid", show, options )
                     end
                     end               end           end
                end
            end
         elseif s ~= "*" then
         elseif s ~= "*" then
             local op, n, plus = s:match( "([<!>]=?)([-0-9][%S]*)(+?)" )
             local op, n, plus = s:match( "([<!>]=?)([-0-9][%S]*)(+?)" )
             if op then
             if op then               n = tonumber( n )               if n then
                n = tonumber( n )
                     local i = tonumber( analyze )                   if i then
                if n then
                     local i = tonumber( analyze )
                    if i then
                         if op == "<" then
                         if op == "<" then
                             i = ( i < n )
                             i = ( i < n )
Line 280: Line 143:
                             i = ( i >= n )
                             i = ( i >= n )
                         elseif op == "!=" then
                         elseif op == "!=" then
                             i = ( i ~= n )
                             i = ( i ~= n )                       else
                        else
                             n = false                       end
                             n = false
                     end                   if not i then
                        end
                         r = "invalid"                   end
                     end
                 elseif plus then                   r = "undefined"
                    if not i then
                 end           end           if not n and not r then
                         r = "invalid"
                 r = "unknownRule"           end           if r then
                    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
                 if options.say then
                     show = "'" .. options.say .. "' " .. s
                     show = "'" .. options.say .. "' " .. s               else
                else
                     show = s               end               if abbr then
                     show = s
                     r = show               else
                end
                     r = failure( r, show, options )               end
                if abbr then
             end       end   end   if scan then
                     r = show
         local legal, got = pcall( failsafe, analyze, scan )       if legal then
                else
             if not got then               if s == "aa" then
                     r = failure( r, show, options )
                     got = containsCJK( analyze )               end
                end
                 if not got then                   if options.say then
             end
                         show = "'" .. options.say .. "'"                   end
        end
                     if abbr then                       r = show
    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
                     else
                         r = failure( "invalid", show, options )
                         r = failure( "invalid", show, options )
                     end
                     end               end           end       else
                end
            end
        else
             r = failure( "badPattern",
             r = failure( "badPattern",
                         scan .. " *** " .. got,
                         scan .. " *** " .. got,
                         options )
                         options )       end   end   return r
        end
end -- feasible()local function fed( haystack, needle )
    end
     -- Find needle in haystack map   -- Precondition:
    return r
end -- feasible()
 
 
 
local function fed( haystack, needle )
     -- Find needle in haystack map
    -- Precondition:
     --    haystack  -- table; map of key values
     --    haystack  -- table; map of key values
     --    needle    -- any; identifier
     --    needle    -- any; identifier   -- Postcondition:
    -- Postcondition:
     --    Return true iff found   local k, v
     --    Return true iff found
     for k, v in pairs( haystack ) do       if k == needle then
    local k, v
             return true       end   end -- for k, v   return false
     for k, v in pairs( haystack ) do
end -- fed()local function fetch( light, options )
        if k == needle then
     -- Return regular table with all parameters   -- Precondition:
             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
     --    light    -- true: template transclusion;  false: #invoke
     --    options  -- table; optional details
     --    options  -- table; optional details   --                options.low
    --                options.low
     -- Postcondition:   --    Return table; whitespace-only values as false
     -- Postcondition:
     -- Uses:   --    TemplatePar.downcase()   --    mw.getCurrentFrame()
    --    Return table; whitespace-only values as false
     --    frame:getParent()   local g, k, v   local r = { }
     -- Uses:
     if options.low then       g = TemplatePar.downcase( options )   else
    --    TemplatePar.downcase()
         g = mw.getCurrentFrame()       if light then
    --    mw.getCurrentFrame()
             g = g:getParent()       end       g = g.args   end
     --    frame:getParent()
     if type( g ) == "table"  then       r = { }
    local g, k, v
         for k, v in pairs( g ) do           if type( v ) == "string" then
    local r = { }
                 if v:match( "^%s*$" ) then                   v = false
     if options.low then
                 end           else               v = false           end
        g = TemplatePar.downcase( options )
             if type( k ) == "number" then               k = tostring( k )
    else
             end           r[ k ] = v       end -- for k, v   else
         g = mw.getCurrentFrame()
         r = g   end   return rend -- fetch()
        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 figure( append, options )
local function figure( append, options )
     -- Extend options by rule from #invoke strings
     -- Extend options by rule from #invoke strings   -- Precondition:
    -- Precondition:
     --    append  -- string or nil; requested rule
     --    append  -- string or nil; requested rule
     --    options  --  table; details
     --    options  --  table; details   --                  ++ .key
    --                  ++ .key
     --                  ++ .pattern   -- Postcondition:
     --                  ++ .pattern
     --    Return sequence table   local r = options
    -- Postcondition:
     --    Return sequence table
    local r = options
     if type( append ) == "string" then
     if type( append ) == "string" then
         local story = mw.text.trim( append )
         local story = mw.text.trim( append )
Line 419: Line 205:
             sub            = sub:gsub( "%%%(%(", "{{" )
             sub            = sub:gsub( "%%%(%(", "{{" )
             sub            = sub:gsub( "%%%)%)", "}}" )
             sub            = sub:gsub( "%%%)%)", "}}" )
             options.pattern = sub
             options.pattern = sub           options.key    = nil       else
            options.key    = nil
             options.key    = story           options.pattern = nil       end
        else
     end   return rend -- figure()local function fill( specified )
             options.key    = story
     -- Split requirement string separated by '='   -- Precondition:
            options.pattern = nil
        end
     end
    return r
end -- figure()
 
 
 
local function fill( specified )
     -- Split requirement string separated by '='
    -- Precondition:
     --    specified  -- string or nil; requested parameter set
     --    specified  -- string or nil; requested parameter set
     -- Postcondition:
     -- Postcondition:   --    Return sequence table   -- Uses:
    --    Return sequence table
     --    mw.text.split()   local r   if specified then       local i, s
    -- Uses:
         r = mw.text.split( specified, "%s*=%s*" )       for i = #r, 1, -1 do
     --    mw.text.split()
             s = r[ i ]           if #s == 0 then
    local r
                 table.remove( r, i )           end       end -- for i, -1
    if specified then
     else       r = { }   end   return rend -- fill()
        local i, s
local function finalize( submit, options )   -- Finalize message
         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:
     -- Precondition:
     --    submit  -- string or false or nil; non-empty error message
     --    submit  -- string or false or nil; non-empty error message
     --    options  -- table or nil; optional details
     --    options  -- table or nil; optional details
     --                options.noError
     --                options.noError   --                options.cat
    --                options.cat
     --                options.template   -- Postcondition:
     --                options.template
     --    Return string or false   -- Uses:   --    factory()
    -- Postcondition:
     local r = false   if submit then       local opt, s
     --    Return string or false
         if type( options ) == "table" then           opt = options       else
    -- Uses:
             opt = { }       end       if opt.noError then
    --    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
             if not opt.cat then
                 r = submit .. " " .. factory( "noErrorCat" )
                 r = submit .. " " .. factory( "noErrorCat" )           end
            end
         else           r = submit       end       if r then
         else
             r = "<span class='error'>" .. r .. "</span>"       end
            r = submit
         s = opt.cat       if type( s ) == "string" then
        end
             if not r then               r = ""           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 s:find( "@@@" ) then
                 if type( opt.template ) == "string" then
                 if type( opt.template ) == "string" then
                     s = s:gsub( "@@@", opt.template )
                     s = s:gsub( "@@@", opt.template )               end
                end
             end           r = r .. "[[Category:" .. s .. "]]"       end   end
             end
     return rend -- finalize()local function finder( haystack, needle )
            r = r .. "[[Category:" .. s .. "]]"
     -- Find needle in haystack sequence   -- Precondition:
        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
     --    haystack  -- table; sequence of key names, downcased if low
     --    needle    -- any; key name
     --    needle    -- any; key name   -- Postcondition:
    -- Postcondition:
     --    Return true iff found   local i   for i = 1, #haystack do
     --    Return true iff found
         if haystack[ i ] == needle then           return true       end
    local i
     end -- for i   return falseend -- finder()
    for i = 1, #haystack do
local function fix( valid, duty, got, options )   -- Perform parameter analysis
         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:
     -- Precondition:
     --    valid    -- table; unique sequence of known parameters
     --    valid    -- table; unique sequence of known parameters
     --    duty    -- table; sequence of mandatory parameters
     --    duty    -- table; sequence of mandatory parameters
     --    got      -- table; sequence of current parameters
     --    got      -- table; sequence of current parameters
     --    options  -- table or nil; optional details
     --    options  -- table or nil; optional details   -- Postcondition:
    -- Postcondition:
     --    Return string as configured; empty if valid   -- Uses:
     --    Return string as configured; empty if valid
     --    finder()   --    fault()   --    failure()   --    fed()
    -- Uses:
     local k, v   local r = false   for k, v in pairs( got ) do
     --    finder()
         if not finder( valid, k ) then           r = fault( r, k )       end
    --    fault()
     end -- for k, v   if r then
    --    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 )
         r = failure( "unknown",  "'" .. r .. "'",  options )
     else -- all names valid
     else -- all names valid       local i, s       for i = 1, #duty do
        local i, s
             s = duty[ i ]           if not fed( got, s ) then
        for i = 1, #duty do
                 r = fault( r, s )           end       end -- for i
             s = duty[ i ]
         if r then           r = failure( "undefined", r, options )
            if not fed( got, s ) then
         else -- all mandatory present           for i = 1, #duty do
                 r = fault( r, s )
                 s = duty[ i ]               if not got[ s ] then
            end
                     r = fault( r, s )               end           end -- for i
        end -- for i
             if r then               r = failure( "empty", r, options )
         if r then
             end       end   end   return rend -- fix()
            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 )
local function flat( collection, options )
     -- Return all table elements with downcased string
     -- Return all table elements with downcased string   -- Precondition:
    -- Precondition:
     --    collection  -- table; k=v pairs
     --    collection  -- table; k=v pairs
     --    options    -- table or nil; optional messaging details
     --    options    -- table or nil; optional messaging details
     -- Postcondition:
     -- Postcondition:
     --    Return table, may be empty; or string with error message.
     --    Return table, may be empty; or string with error message.   -- Uses:
    -- Uses:
     --    mw.ustring.lower()   --    fault()   --    failure()
     --    mw.ustring.lower()
     local k, v   local r = { }   local e = false
    --    fault()
     for k, v in pairs( collection ) do       if type ( k ) == "string" then
    --    failure()
             k = mw.ustring.lower( k )           if r[ k ] then
     local k, v
                 e = fault( e, k )           end       end       r[ k ] = v
    local r = { }
     end -- for k, v   if e then       r = failure( "multiSpell", e, options )
    local e = false
     end   return rend -- flat()local function fold( options )
     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
     -- Merge two tables, create new sequence if both not empty
     -- Precondition:
     -- Precondition:   --    options  -- table; details
    --    options  -- table; details
     --                options.mandatory  sequence to keep unchanged
     --                options.mandatory  sequence to keep unchanged
     --                options.optional    sequence to be appended
     --                options.optional    sequence to be appended
     --                options.low        downcased expected
     --                options.low        downcased expected
     -- Postcondition:
     -- Postcondition:   --    Return merged table, or message string if error
    --    Return merged table, or message string if error
     -- Uses:   --    finder()   --    fault()   --    failure()
     -- Uses:
     --    flat()   local i, e, r, s   local base  = options.mandatory
    --    finder()
     local extend = options.optional   if #base == 0 then
    --    fault()
         if #extend == 0 then           r = { }       else
    --    failure()
             r = extend       end   else       if #extend == 0 then
     --    flat()
             r = base       else           e = false
    local i, e, r, s
             for i = 1, #extend do               s = extend[ i ]
    local base  = options.mandatory
                 if finder( base, s ) then                   e = fault( e, s )
     local extend = options.optional
                 end           end -- for i           if e then
    if #base == 0 then
                 r = failure( "dupOpt", e, options )           else
         if #extend == 0 then
                 r = { }               for i = 1, #base do
            r = { }
                     table.insert( r, base[ i ] )               end -- for i
        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
                 for i = 1, #extend do
                     table.insert( r, extend[ i ] )
                     table.insert( r, extend[ i ] )               end -- for i
                end -- for i
             end       end   end
             end
     if options.low  and  type( r ) == "table" then       r = flat( r, options )
        end
     end   return rend -- fold()local function form( light, options )
    end
     -- Run parameter analysis on current environment   -- Precondition:
     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
     --    light    -- true: template transclusion;  false: #invoke
     --    options  -- table or nil; optional details
     --    options  -- table or nil; optional details
     --                options.mandatory
     --                options.mandatory   --                options.optional
    --                options.optional
     -- Postcondition:   --    Return string with error message as configured;
     -- Postcondition:
     --            false if valid   -- Uses:   --    fold()   --    fetch()
    --    Return string with error message as configured;
     --    fix()   --    finalize()   local duty, r
     --            false if valid
    -- Uses:
    --    fold()
    --    fetch()
     --    fix()
    --    finalize()
    local duty, r
     if type( options ) == "table" then
     if type( options ) == "table" then
         if type( options.mandatory ) ~= "table" then
         if type( options.mandatory ) ~= "table" then
             options.mandatory = { }
             options.mandatory = { }       end       duty = options.mandatory
        end
        duty = options.mandatory
         if type( options.optional ) ~= "table" then
         if type( options.optional ) ~= "table" then
             options.optional = { }
             options.optional = { }       end       r = fold( options )   else
        end
         options = { }       duty    = { }       r      = { }   end
        r = fold( options )
     if type( r ) == "table" then       local got = fetch( light, options )
    else
         options = { }
        duty    = { }
        r      = { }
    end
     if type( r ) == "table" then
        local got = fetch( light, options )
         if type( got ) == "table" then
         if type( got ) == "table" then
             r = fix( r, duty, got, options )
             r = fix( r, duty, got, options )       else           r = got
        else
         end   end   return finalize( r, options )end -- form()
            r = got
local function format( analyze, options )   -- Check validity of a value
         end
     -- Precondition:   --    analyze  -- string to be analyzed
    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  -- table or nil; optional details
     --                options.say
     --                options.say   --                options.min
    --                options.min
     --                options.max   -- Postcondition:
     --                options.max
    -- Postcondition:
     --    Return string with error message as configured;
     --    Return string with error message as configured;
     --            false if valid or no answer permitted
     --            false if valid or no answer permitted   -- Uses:
    -- Uses:
     --    feasible()   --    failure()
     --    feasible()
     local r    = feasible( analyze, options, false )   local show
    --    failure()
     local r    = feasible( analyze, options, false )
    local show
     if options.min  and  not r then
     if options.min  and  not r then
         if type( options.min ) == "number" then
         if type( options.min ) == "number" then
Line 726: Line 334:
                                 .. " > " ..
                                 .. " > " ..
                                 tostring( options.max ),
                                 tostring( options.max ),
                                 options )
                                 options )               end           end
                end
            end
             if #analyze < options.min  and  not r then
             if #analyze < options.min  and  not r then
                 show = " <" .. options.min
                 show = " <" .. options.min               if options.say then
                if options.say then
                     show = show .. " '" .. options.say .. "'"               end
                     show = show .. " '" .. options.say .. "'"
                 r = failure( "tooShort", show, options )           end
                end
         else           r = failure( "invalidPar", "min", options )       end
                 r = failure( "tooShort", show, options )
     end   if options.max  and  not r then
            end
         else
            r = failure( "invalidPar", "min", options )
        end
     end
    if options.max  and  not r then
         if type( options.max ) == "number" then
         if type( options.max ) == "number" then
             if #analyze > options.max then
             if #analyze > options.max then
                 show = " >" .. options.max
                 show = " >" .. options.max               if options.say then
                if options.say then
                     show = show .. " '" .. options.say .. "'"               end
                     show = show .. " '" .. options.say .. "'"
                 r = failure( "tooLong", show, options )           end
                end
         else           r = failure( "invalidPar", "max", options )       end
                 r = failure( "tooLong", show, options )
     end   return rend -- format()
            end
         else
            r = failure( "invalidPar", "max", options )
        end
     end
    return r
end -- format()
 
 
 
local function formatted( assignment, access, options )
local function formatted( assignment, access, options )
     -- Check validity of one particular parameter in a collection
     -- Check validity of one particular parameter in a collection
     -- Precondition:
     -- Precondition:   --    assignment  -- collection
    --    assignment  -- collection
     --    access      -- id of parameter in collection
     --    access      -- id of parameter in collection
     --    options    -- table or nil; optional details
     --    options    -- table or nil; optional details   -- Postcondition:
    -- Postcondition:
     --    Return string with error message as configured;
     --    Return string with error message as configured;
     --            false if valid or no answer permitted
     --            false if valid or no answer permitted   -- Uses:
    -- Uses:
     --    format()   --    failure()   local r = false
     --    format()
    --    failure()
    local r = false
     if type( assignment ) == "table" then
     if type( assignment ) == "table" then
         local story = assignment.args[ access ]
         local story = assignment.args[ access ]
         if type( story ) == "string" then
         if type( story ) == "string" then
             if type( options ) ~= "table" then
             if type( options ) ~= "table" then               options = { }
                options = { }
             end           options.say = access
             end
             r = format( story, options )       else
            options.say = access
             r = failure( "invalid", access, options )       end   end
             r = format( story, options )
     return rend -- formatted()local function furnish( frame, action )
        else
     -- Prepare #invoke evaluation of .assert() or .valid()   -- Precondition:
             r = failure( "invalid", access, options )
        end
    end
     return r
end -- formatted()
 
 
 
local function furnish( frame, action )
     -- Prepare #invoke evaluation of .assert() or .valid()
    -- Precondition:
     --    frame    -- object; #invoke environment
     --    frame    -- object; #invoke environment
     --    action  -- "assert" or "valid"
     --    action  -- "assert" or "valid"   -- Postcondition:
    -- Postcondition:
     --    Return string with error message or ""   -- Uses:   --    form()
     --    Return string with error message or ""
     --    mw.text.trim()   --    failure()   --    TemplatePar.assert()
    -- Uses:
     --    TemplatePar.valid()   local options = { mandatory = { "1" },
    --    form()
     --    mw.text.trim()
    --    failure()
    --    TemplatePar.assert()
     --    TemplatePar.valid()
    local options = { mandatory = { "1" },
                       optional  = { "2",
                       optional  = { "2",
                                     "cat",
                                     "cat",
Line 810: Line 378:
                                     "template" },
                                     "template" },
                       template  = "&#35;invoke:TemplatePar|".. action .. "|"
                       template  = "&#35;invoke:TemplatePar|".. action .. "|"
                     }
                     }   local r      = form( false, options )   if not r then
    local r      = form( false, options )
         local s       options = { cat      = frame.args.cat,
    if not r then
         local s
        options = { cat      = frame.args.cat,
                     low      = frame.args.low,
                     low      = frame.args.low,
                     noError  = frame.args.noError,
                     noError  = frame.args.noError,
                     template = frame.args.template
                     template = frame.args.template                 }
                  }
         options = figure( frame.args[ 2 ], options )
         options = figure( frame.args[ 2 ], options )
         if type( frame.args.min ) == "string" then
         if type( frame.args.min ) == "string" then
             s = frame.args.min:match( "^%s*([0-9]+)%s*$" )
             s = frame.args.min:match( "^%s*([0-9]+)%s*$" )           if s then
            if s then
                 options.min = tonumber( s )           else
                 options.min = tonumber( s )
            else
                 r = failure( "invalidPar",
                 r = failure( "invalidPar",
                             "min=" .. frame.args.min,
                             "min=" .. frame.args.min,
                             options )
                             options )           end       end
            end
        end
         if type( frame.args.max ) == "string" then
         if type( frame.args.max ) == "string" then
             s = frame.args.max:match( "^%s*([1-9][0-9]*)%s*$" )
             s = frame.args.max:match( "^%s*([1-9][0-9]*)%s*$" )
             if s then
             if s then               options.max = tonumber( s )           else
                options.max = tonumber( s )
            else
                 r = failure( "invalidPar",
                 r = failure( "invalidPar",
                             "max=" .. frame.args.max,
                             "max=" .. frame.args.max,
                             options )
                             options )           end       end
            end
         if r then           r = finalize( r, options )       else
        end
             s = frame.args[ 1 ] or ""           r = tonumber( s )
         if r then
             if ( r ) then               s = r           end
            r = finalize( r, options )
             r = TemplatePar[ action ]( s, options )       end   end
        else
     return r or ""end -- furnish()
             s = frame.args[ 1 ] or ""
            r = tonumber( s )
             if ( r ) then
                s = r
            end
             r = TemplatePar[ action ]( s, options )
        end
    end
     return r or ""
end -- furnish()
 
 
 
TemplatePar.assert = function ( analyze, append, options )
TemplatePar.assert = function ( analyze, append, options )
     -- Perform parameter analysis on a single string
     -- Perform parameter analysis on a single string   -- Precondition:
    -- Precondition:
     --    analyze  -- string to be analyzed
     --    analyze  -- string to be analyzed
     --    append  -- string: append error message, prepending <br />
     --    append  -- string: append error message, prepending <br />
     --                false or nil: throw error with message
     --                false or nil: throw error with message
     --    options  -- table; optional details
     --    options  -- table; optional details   -- Postcondition:
    -- Postcondition:
     --    Return string with error message as configured;
     --    Return string with error message as configured;
     --            false if valid
     --            false if valid   -- Uses:   --    format()
    -- Uses:
     local r = format( analyze, options )   if ( r ) then
    --    format()
     local r = format( analyze, options )
    if ( r ) then
         if ( type( append ) == "string" ) then
         if ( type( append ) == "string" ) then
             if ( append ~= "" ) then
             if ( append ~= "" ) then               r = append .. "<br />" .. r
                r = append .. "<br />" .. r
             end       else           error( r, 0 )       end   end
             end
     return rend -- TemplatePar.assert()TemplatePar.check = function ( options )
        else
            error( r, 0 )
        end
    end
     return r
end -- TemplatePar.assert()
 
 
 
TemplatePar.check = function ( options )
     -- Run parameter analysis on current template environment
     -- Run parameter analysis on current template environment
     -- Precondition:
     -- Precondition:   --    options  -- table or nil; optional details
    --    options  -- table or nil; optional details
     --                options.mandatory   --                options.optional
     --                options.mandatory
     -- Postcondition:   --    Return string with error message as configured;
    --                options.optional
     --            false if valid   -- Uses:   --    form()
     -- Postcondition:
     return form( true, options )end -- TemplatePar.check()
    --    Return string with error message as configured;
TemplatePar.count = function ()   -- Return number of template parameters
     --            false if valid
     -- Postcondition:   --    Return number, starting at 0   -- Uses:
    -- Uses:
     --    mw.getCurrentFrame()   --    frame:getParent()   local k, v
    --    form()
     local r = 0   local t = mw.getCurrentFrame():getParent()
     return form( true, options )
     local o = t.args   for k, v in pairs( o ) do       r = r + 1
end -- TemplatePar.check()
     end -- for k, v   return rend -- TemplatePar.count()
 
 
 
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 ()
TemplatePar.countNotEmpty = function ()
     -- Return number of template parameters with more than whitespace
     -- Return number of template parameters with more than whitespace
     -- Postcondition:
     -- Postcondition:   --    Return number, starting at 0   -- Uses:
    --    Return number, starting at 0
     --    mw.getCurrentFrame()   --    frame:getParent()   local k, v
    -- Uses:
     local r = 0   local t = mw.getCurrentFrame():getParent()
     --    mw.getCurrentFrame()
     local o = t.args   for k, v in pairs( o ) do
    --    frame:getParent()
         if not v:match( "^%s*$" ) then           r = r + 1       end
    local k, v
     end -- for k, v   return rend -- TemplatePar.countNotEmpty()
     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 )
TemplatePar.downcase = function ( options )
     -- Return all template parameters with downcased name
     -- Return all template parameters with downcased name   -- Precondition:
    -- Precondition:
     --    options  -- table or nil; optional messaging details
     --    options  -- table or nil; optional messaging details
     -- Postcondition:
     -- Postcondition:
     --    Return table, may be empty; or string with error message.
     --    Return table, may be empty; or string with error message.   -- Uses:
    -- Uses:
     --    mw.getCurrentFrame()   --    frame:getParent()   --    flat()
     --    mw.getCurrentFrame()
     local t = mw.getCurrentFrame():getParent()   return flat( t.args, options )
    --    frame:getParent()
end -- TemplatePar.downcase()TemplatePar.valid = function ( access, options )
    --    flat()
     -- Check validity of one particular template parameter   -- Precondition:
     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
     --    access  -- id of parameter in template transclusion
     --    options  -- table or nil; optional details
     --    options  -- table or nil; optional details   -- Postcondition:
    -- Postcondition:
     --    Return string with error message as configured;
     --    Return string with error message as configured;
     --            false if valid or no answer permitted
     --            false if valid or no answer permitted   -- Uses:
    -- Uses:
     --    mw.text.trim()   --    TemplatePar.downcase()
     --    mw.text.trim()
     --    mw.getCurrentFrame()   --    frame:getParent()
    --    TemplatePar.downcase()
     --    formatted()   --    failure()   --    finalize()   local r
     --    mw.getCurrentFrame()
     if type( access ) == "string" then       r = mw.text.trim( access )
    --    frame:getParent()
         if #r == 0 then           r = false       end   end   if r then
     --    formatted()
         local params       if type( options ) ~= "table" then
    --    failure()
             options = { }       end       if options.low then
    --    finalize()
             params = TemplatePar.downcase( options )       else
    local r
             params = mw.getCurrentFrame():getParent()       end
     if type( access ) == "string" then
         r = formatted( params, access, options )   else
        r = mw.text.trim( access )
         r = failure( "noname", false, options )   end
         if #r == 0 then
     return finalize( r, options )end -- TemplatePar.valid()
            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 )
TemplatePar.verify = function ( options )
     -- Perform #invoke parameter analysis
     -- Perform #invoke parameter analysis   -- Precondition:
    -- Precondition:
     --    options  -- table or nil; optional details   -- Postcondition:
     --    options  -- table or nil; optional details
    -- Postcondition:
     --    Return string with error message as configured;
     --    Return string with error message as configured;
     --            false if valid
     --            false if valid   -- Uses:   --    form()
    -- Uses:
     return form( false, options )end -- TemplatePar.verify()
    --    form()
-- Provide external accesslocal p = {}function p.assert( frame )
     return form( false, options )
     -- Perform parameter analysis on some single string   -- Precondition:
end -- TemplatePar.verify()
     --    frame  -- object; #invoke environment   -- Postcondition:
 
     --    Return string with error message or ""   -- Uses:
 
     --    furnish()   return furnish( frame, "assert" )end -- .assert()
 
function p.check( frame )   -- Check validity of template parameters
-- Provide external access
     -- Precondition:   --    frame  -- object; #invoke environment
local p = {}
     -- Postcondition:   --    Return string with error message or ""
 
     -- Uses:   --    form()   --    fill()
 
 
function p.assert( frame )
     -- Perform parameter analysis on some single string
    -- Precondition:
     --    frame  -- object; #invoke environment
    -- Postcondition:
     --    Return string with error message or ""
    -- Uses:
     --    furnish()
    return furnish( frame, "assert" )
end -- .assert()
 
 
 
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",
     local options = { optional  = { "all",
                                     "opt",
                                     "opt",
Line 1,045: Line 481:
                                     "template" },
                                     "template" },
                       template  = "&#35;invoke:TemplatePar|check|"
                       template  = "&#35;invoke:TemplatePar|check|"
                     }
                     }   local r = form( false, options )   if not r then
    local r = form( false, options )
    if not r then
         options = { mandatory = fill( frame.args.all ),
         options = { mandatory = fill( frame.args.all ),
                     optional  = fill( frame.args.opt ),
                     optional  = fill( frame.args.opt ),
Line 1,053: Line 487:
                     low      = frame.args.low,
                     low      = frame.args.low,
                     noError  = frame.args.noError,
                     noError  = frame.args.noError,
                     template  = frame.args.template
                     template  = frame.args.template                 }
                  }
         r      = form( true, options )   end   return r or ""end -- .check()
         r      = form( true, options )
function p.count( frame )   -- Count number of template parameters
    end
     -- Postcondition:   --    Return string with digits including "0"
    return r or ""
     -- Uses:   --    TemplatePar.count()
end -- .check()
     return tostring( TemplatePar.count() )end -- .count()
 
 
 
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 )
function p.countNotEmpty( frame )
     -- Count number of template parameters which are not empty
     -- Count number of template parameters which are not empty
     -- Postcondition:
     -- Postcondition:   --    Return string with digits including "0"
    --    Return string with digits including "0"
     -- Uses:   --    TemplatePar.countNotEmpty()
     -- Uses:
     return tostring( TemplatePar.countNotEmpty() )end -- .countNotEmpty()
    --    TemplatePar.countNotEmpty()
function p.match( frame )   -- Combined analysis of parameters and their values
     return tostring( TemplatePar.countNotEmpty() )
     -- Postcondition:   --    Return string with error message or ""
end -- .countNotEmpty()
     -- Uses:   --    mw.text.trim()   --    mw.ustring.lower()
 
     --    failure()   --    form()   --    TemplatePar.downcase()
 
     --    figure()   --    feasible()   --    fault()   --    finalize()
 
     local r = false   local options = { cat      = frame.args.cat,
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,
                       low      = frame.args.low,
                       noError  = frame.args.noError,
                       noError  = frame.args.noError,
                       template  = frame.args.template
                       template  = frame.args.template                   }
                    }
     local k, v, s   local params = { }   for k, v in pairs( frame.args ) do
     local k, v, s
    local params = { }
    for k, v in pairs( frame.args ) do
         if type( k ) == "number" then
         if type( k ) == "number" then
             s, v = v:match( "^ *([^=]+) *= *(%S.*%S*) *$" )
             s, v = v:match( "^ *([^=]+) *= *(%S.*%S*) *$" )           if s then
            if s then
                 s = mw.text.trim( s )               if s == "" then
                 s = mw.text.trim( s )
                     s = false               end           end
                if s == "" then
             if s then               if options.low then
                     s = false
                     s = mw.ustring.lower( s )               end
                end
                 if params[ s ] then                   s = params[ s ]
            end
                     s[ #s + 1 ] = v               else
             if s then
                     params[ s ] = { v }               end           else
                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 )
                 r = failure( "invalidPar",  tostring( k ),  options )
                 break -- for k, v
                 break -- for k, v           end       end   end -- for k, v
            end
     if not r then       s = { }       for k, v in pairs( params ) do
        end
             s[ #s + 1 ] = k       end -- for k, v       options.optional = s
    end -- for k, v
         r = form( true, options )   end   if not r then
     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 errMiss, errValues, lack, rule
         local targs = frame:getParent().args
         local targs = frame:getParent().args       options.optional = nil
        options.optional = nil
         if options.low then           targs = TemplatePar.downcase()
         if options.low then
         else           targs = frame:getParent().args       end
            targs = TemplatePar.downcase()
         errMiss  = false       errValues = false
         else
         for k, v in pairs( params ) do           options.say = k
            targs = frame:getParent().args
             errValue    = false           s = targs[ k ]           if s then
        end
                 if s == "" then                   lack = true
         errMiss  = false
                 else                   lack = false               end
        errValues = false
             else               s    = ""               lack = true
         for k, v in pairs( params ) do
             end           for r, rule in pairs( v ) 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 )
                 options = figure( rule, options )
                 r      = feasible( s, options, true )
                 r      = feasible( s, options, true )               if r then
                if r then
                     if lack then                       if errMiss then
                     if lack then
                        if errMiss then
                             errMiss = errMiss .. ", '" .. k .. "'"
                             errMiss = errMiss .. ", '" .. k .. "'"
                         else
                         else
                             errMiss = "'" .. k .. "'"
                             errMiss = "'" .. k .. "'"                       end
                        end
                     elseif not errMiss then
                     elseif not errMiss then
                         errValues = fault( errValues, r )
                         errValues = fault( errValues, r )                   end
                    end
                     break -- for r, rule               end
                     break -- for r, rule
             end -- for s, rule       end -- for k, v
                end
         r = ( errMiss or errValues )       if r then           if errMiss then
             end -- for s, rule
                 r = failure( "undefined", errMiss, options )           else
        end -- for k, v
                 r = failure( "invalid", errValues, options )           end
         r = ( errMiss or errValues )
             r = finalize( r, options )       end   end   return r or ""
        if r then
end -- .match()function p.valid( frame )
            if errMiss then
     -- Check validity of one particular template parameter   -- Precondition:
                 r = failure( "undefined", errMiss, options )
     --    frame  -- object; #invoke environment   -- Postcondition:
            else
     --    Return string with error message or ""   -- Uses:
                 r = failure( "invalid", errValues, options )
     --    furnish()   return furnish( frame, "valid" )end -- .valid()
            end
function p.TemplatePar()   -- Retrieve function access for modules
             r = finalize( r, options )
     -- Postcondition:   --    Return table with functions
        end
     return TemplateParend -- .TemplatePar()return p
    end
    return r or ""
end -- .match()
 
 
 
function p.valid( frame )
     -- Check validity of one particular template parameter
    -- Precondition:
     --    frame  -- object; #invoke environment
    -- Postcondition:
     --    Return string with error message or ""
    -- Uses:
     --    furnish()
    return furnish( frame, "valid" )
end -- .valid()
 
 
 
function p.TemplatePar()
    -- Retrieve function access for modules
     -- Postcondition:
    --    Return table with functions
     return TemplatePar
end -- .TemplatePar()
 
 
 
return p

Revision as of 08:40, 20 December 2013

Module documentation[ view · edit · history · purge ]
This documentation is transcluded from Module:TemplatePar/doc.

Script error: Lua error at line 68: '<eof>' expected near 'end'.

--[=[ TemplatePar 2013-07-09Template parameter utility* assert* check* count
* countNotEmpty* downcase* match* valid* verify* TemplatePar()]=]
-- Module globalslocal TemplatePar = { }
local messagePrefix = "lua-module-TemplatePar-"local l10nDef = {}
l10nDef[ "en" ] = {
    badPattern  = "&#35;invoke:TemplatePar pattern syntax error",
    dupOpt      = "&#35;invoke:TemplatePar repeated optional parameter",
    dupRule     = "&#35;invoke:TemplatePar conflict key/pattern",
    empty       = "Error in template * undefined value for mandatory",
    invalid     = "Error in template * invalid parameter",
    invalidPar  = "&#35;invoke:TemplatePar invalid parameter",
    minmax      = "&#35;invoke:TemplatePar min > max",
    multiSpell  = "Error in template * multiple spelling of parameter",
    noErrorCat  = "&#35;invoke:TemplatePar noError and missing category",
    noname      = "&#35;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 = "&#35;invoke:TemplatePar unknown rule"}l10nDef[ "de" ]  = {
    badPattern  = "&#35;invoke:TemplatePar Syntaxfehler des pattern",
    dupOpt      = "&#35;invoke:TemplatePar Optionsparameter wiederholt",
    dupRule     = "&#35;invoke:TemplatePar Konflikt key/pattern",
    empty       = "Fehler bei Vorlage * Pflichtparameter ohne Wert",
    invalid     = "Fehler bei Vorlage * Parameter ungültig",
    invalidPar  = "&#35;invoke:TemplatePar Ungültiger Parameter",
    minmax      = "&#35;invoke:TemplatePar min > max",
    multiSpell  = "Fehler bei Vorlage * Mehrere Parameter-Schreibweisen",
    noErrorCat  = "&#35;invoke:TemplatePar noError und keine Kategorie",
    noname      = "&#35;invoke:TemplatePar Parameter 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 = "&#35;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]",
    [ "pagename" ] = string.format( "^[^#<>%%[%%]|{}%s%-s%s]+$",
                                    1, 31, 127 ),    [ "+" ]        = "%S"}
local patternCJK = falselocal 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 rend -- 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 rend -- 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 rend -- 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()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 rend -- 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 rend -- figure()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 rend -- 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 rend -- 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 falseend -- 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 rend -- 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 rend -- 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 rend -- 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()    --     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.say    --                 options.min
    --                 options.max    -- Postcondition:
    --     Return string with error message as configured;
    --            false if valid or no answer permitted    -- Uses:
    --     feasible()    --     failure()
    local r    = feasible( analyze, options, false )    local show
    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 rend -- 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:
    --     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 rend -- formatted()local function furnish( frame, action )
    -- Prepare #invoke evaluation of .assert() or .valid()    -- Precondition:
    --     frame    -- object; #invoke environment
    --     action   -- "assert" or "valid"    -- Postcondition:
    --     Return string with error message or ""    -- Uses:    --     form()
    --     mw.text.trim()    --     failure()    --     TemplatePar.assert()
    --     TemplatePar.valid()    local options = { mandatory = { "1" },
                      optional  = { "2",
                                    "cat",
                                    "low",
                                    "max",
                                    "min",
                                    "noError",
                                    "template" },
                      template  = "&#35;invoke:TemplatePar|".. action .. "|"
                    }    local r       = form( false, options )    if not r then
        local s        options = { cat      = frame.args.cat,
                    low      = frame.args.low,
                    noError  = frame.args.noError,
                    template = frame.args.template                  }
        options = figure( frame.args[ 2 ], options )
        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[ action ]( s, options )        end    end
    return r or ""end -- furnish()
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 rend -- 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 rend -- 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 rend -- 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()    --     flat()
    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 accesslocal p = {}function p.assert( frame )
    -- Perform parameter analysis on some single string    -- Precondition:
    --     frame  -- object; #invoke environment    -- Postcondition:
    --     Return string with error message or ""    -- Uses:
    --     furnish()    return furnish( frame, "assert" )end -- .assert()
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  = "&#35;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.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()function p.valid( frame )
    -- Check validity of one particular template parameter    -- Precondition:
    --     frame  -- object; #invoke environment    -- Postcondition:
    --     Return string with error message or ""    -- Uses:
    --     furnish()    return furnish( frame, "valid" )end -- .valid()
function p.TemplatePar()    -- Retrieve function access for modules
    -- Postcondition:    --     Return table with functions
    return TemplateParend -- .TemplatePar()return p
Cookies help us deliver our services. By using our services, you agree to our use of cookies.