विभाग:TemplatePar

--[=[ TemplatePar 2015-02-14Template 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",    missing     = "&#35;invoke:TemplatePar missing library",    multiSpell  = "Error in template * multiple spelling of parameter",    noMSGnoCAT  = "&#35;invoke:TemplatePar neither message nor category",    noname      = "&#35;invoke:TemplatePar missing parameter name",    notFound    = "Error in template * missing page",    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",    noMSGnoCAT  = "&#35;invoke:TemplatePar weder Meldung noch Kategorie",    noname      = "&#35;invoke:TemplatePar Parameter nicht angegeben",    notFound    = "Fehler bei Vorlage * Seite fehlt",    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]*$",    [ "w" ]        = "^%S*$",    [ "w+" ]       = "^%S+$",    [ "base64" ]   = "^[A-Za-z0-9%+/]*$",    [ "base64+" ]  = "^[A-Za-z0-9%+/]+$",    [ "aa" ]       = "[%a%a].*[%a%a]",    [ "pagename" ] = string.format( "^[^#<>%%[%%]|{}%c-%c%c]+$",                                    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 rend -- containsCJK()local function facility( accept, attempt )    -- Check string as possible file name or other source page    -- Precondition:    --     accept   -- string; requirement    --                         file    --                         file+    --                         file:    --                         file:+    --                         image    --                         image+    --                         image:    --                         image:+    --     attempt  -- string; to be tested    -- Postcondition:    --     Return error keyword, or false    -- Uses:    --     Module:FileMedia    --     FileMedia.isType()    local r    if attempt and attempt ~= "" then        local lucky, FileMedia = pcall( require, "Module:FileMedia" )        if type( FileMedia ) == "table" then            FileMedia = FileMedia.FileMedia()            local s, live = accept:match( "^([a-z]+)(:?)%+?$" )            if live then                if FileMedia.isType( attempt, s ) then                    if FileMedia.isFile( attempt ) then                        r = false                    else                        r = "notFound"                    end                else                    r = "invalid"                end            elseif FileMedia.isType( attempt, s ) then                r = false            else                r = "invalid"            end        else            r = "missing"        end    elseif accept:match( "%+$" ) then        r = "empty"    else        r = false    end    return rend -- facility()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 = string.format( "(((%s)))", 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 = string.format( "%s (%s)", r, options.template )            end        end    end    if suspect then        r = string.format( "%s: %s", 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 = string.format( "%s; %s", 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()    --     facility()    --     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]" )  and                   not analyze:match( "^%s*$" ) then                    scan = false                    if options.say then                        show = string.format( "'%s'", 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 )                        elseif op == "!=" then                            i = ( i ~= n )                        else                            n = false                        end                    end                    if not i then                        r = "invalid"                    end                elseif plus then                    r = "undefined"                end            elseif s:match( "^image%+?:?$" )  or                   s:match( "^file%+?:?$" ) then                r = facility( s, analyze )                n = true            elseif s:match( "langW?%+?" ) then                n = "lang"-- lang lang+-- langW langW+            end            if not n and not r then                r = "unknownRule"            end            if r then                if options.say then                    show = string.format( "'%s' %s", 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 = string.format( "'%s'", options.say )                    end                    if abbr then                        r = show                    else                        r = failure( "invalid", show, options )                    end                end            end        else            r = failure( "badPattern",                         string.format( "%s *** %s", scan, got ),                         options )        end    end    return rend -- 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 falseend -- 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, frame )    -- Finalize message    -- Precondition:    --     submit   -- string or false or nil; non-empty error message    --     options  -- table or nil; optional details    --                 options.format    --                 options.preview    --                 options.cat    --                 options.template    --     frame    -- object, or false    -- Postcondition:    --     Return string or false    -- Uses:    --     factory()    local r = false    if submit then        local opt, s        local lazy = false        local show = false        if type( options ) == "table" then            opt  = options            show = opt.format            lazy = ( show == ""  or  show == "0"  or  show == "-" )            s    = opt.preview            if type( s ) == "string"  and                s ~= ""  and  s ~= "0"  and  s ~= "-" then                if lazy then                    show = ""                    lazy = false                end                if not frame then                    frame = mw.getCurrentFrame()                end                if frame:preprocess( "{{REVISIONID}}" ) == "" then                    if s == "1" then                        show = "*"                    else                        show = s                    end                end            end        else            opt = { }        end        if lazy then            if not opt.cat then                r = string.format( "%s %s",                                   submit,  factory( "noMSGnoCAT" ) )            end        else            r = submit        end        if r  and  not lazy then            local i            if not show  or  show == "*" then                show = "<span class=\"error\">@@@</span>"            end            i = show:find( "@@@", 1, true )            if i then                -- No gsub() since r might contain "%3" (e.g. URL)                r = string.format( "%s%s%s",                                   show:sub( 1,  i - 1 ),                                   r,                                   show:sub( i + 3 ) )            else                r = show            end        end        s = opt.cat        if type( s ) == "string" then            if opt.errNS then                local ns = mw.title.getCurrentTitle().namespace                local st = type( opt.errNS )                if st == "string" then                    local space  = string.format( ".*%%s%d%%s.*", ns )                    local spaces = string.format( " %s ", opt.errNS )                    if spaces:match( space ) then                        opt.errNS = false                    end                elseif st == "table" then                    for i = 1, #opt.errNS do                        if opt.errNS[ i ] == ns then                            opt.errNS = false                            break    -- for i                        end                    end -- for i                end            end            if opt.errNS then                r = ""            else                if not r then                   r = ""                end                if s:find( "@@@" ) then                    if type( opt.template ) == "string" then                        s = s:gsub( "@@@", opt.template )                    end                end                local i                local cats = mw.text.split( s, "%s*#%s*" )                for i = 1, #cats do                    s = mw.text.trim( cats[ i ] )                    if #s > 0 then                        r = string.format( "%s[[Category:%s]]", r, s )                    end                end -- for i            end        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",                     string.format( "'%s'", 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, frame )    -- Run parameter analysis on current environment    -- Precondition:    --     light    -- true: template transclusion;  false: #invoke    --     options  -- table or nil; optional details    --                 options.mandatory    --                 options.optional    --     frame    -- object, or false    -- 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, frame )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",                                 string.format( "%d > %d",                                                options.min,                                                options.max ),                                 options )                end            end            if #analyze < options.min  and  not r then                show = " <" .. options.min                if options.say then                    show = string.format( "%s '%s'", 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 = string.format( "%s '%s'", 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:    --     mw.text.trim()     --     format()    --     failure()    local r = false    if type( assignment ) == "table" then        local story = assignment.args[ access ] or ""        if type( access ) == "number" then            story = mw.text.trim( story )         end        if type( options ) ~= "table" then            options = { }        end        options.say = access        r = format( story, options )    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()    --     failure()    --     finalize()    --     TemplatePar.valid()    --     TemplatePar.assert()    local options = { mandatory = { "1" },                      optional  = { "2",                                    "cat",                                    "errNS",                                    "low",                                    "max",                                    "min",                                    "format",                                    "preview",                                    "template" },                      template  = string.format( "&#35;invoke:%s|%s|",                                                 "TemplatePar",                                                 action )                    }    local r       = form( false, options, frame )    if not r then        local s        options = { cat      = frame.args.cat,                    errNS    = frame.args.errNS,                    low      = frame.args.low,                    format   = frame.args.format,                    preview  = frame.args.preview,                    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, frame )        else            s = frame.args[ 1 ] or ""            r = tonumber( s )            if ( r ) then                s = r            end            if action == "valid" then                r = TemplatePar.valid( s, options, frame )            elseif action == "assert" then                r = TemplatePar.assert( s, "", options )            end        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 = string.format( "%s<br />%s", append, 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, false )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, frame )    -- Check validity of one particular template parameter    -- Precondition:    --     access   -- id of parameter in template transclusion    --                 string or number    --     options  -- table or nil; optional details    --     frame    -- object; #invoke environment    -- Postcondition:    --     Return string with error message as configured;    --            false if valid or no answer permitted    -- Uses:    --     mw.text.trim()    --     TemplatePar.downcase()    --     frame:getParent()    --     formatted()    --     failure()    --     finalize()    local r = type( access )    if r == "string" then        r = mw.text.trim( access )        if #r == 0 then            r = false        end    elseif r == "number" then        r = access    else        r = false    end    if r then        local params        if type( options ) ~= "table" then            options = { }        end        if options.low then            params = TemplatePar.downcase( options )        else            params = frame:getParent()        end        r = formatted( params, access, options )    else        r = failure( "noname", false, options )    end    return finalize( r, options, frame )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, false )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",                                    "errNS",                                    "low",                                    "format",                                    "preview",                                    "template" },                      template  = "&#35;invoke:TemplatePar|check|"                    }    local r = form( false, options, frame )    if not r then        options = { mandatory = fill( frame.args.all ),                    optional  = fill( frame.args.opt ),                    cat       = frame.args.cat,                    errNS     = frame.args.errNS,                    low       = frame.args.low,                    format    = frame.args.format,                    preview   = frame.args.preview,                    template  = frame.args.template                  }        r       = form( true, options, frame )    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,                      errNS    = frame.args.errNS,                      low      = frame.args.low,                      format   = frame.args.format,                      preview  = frame.args.preview,                      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, frame )    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 = string.format( "%s, '%s'",                                                     errMiss, k )                        else                            errMiss = string.format( "'%s'", 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, frame )        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
🔥 Top keywords: क्लिओपात्राजिजाबाई शहाजी भोसलेमुखपृष्ठशिवाजी महाराजविशेष:शोधाईद-उल-अधारत्‍नागिरी जिल्हादिशागणपती स्तोत्रेनवग्रह स्तोत्रसंत तुकाराममुंजा (भूत)मुरलीकांत पेटकरज्ञानेश्वरजागतिक दिवसगोवा क्रांती दिनराणी लक्ष्मीबाईरायगड (किल्ला)बाबासाहेब आंबेडकरमहाराष्ट्ररत्‍नागिरीमहाराष्ट्रामधील जिल्हेभारताचे संविधानॐ नमः शिवायमटकास्वामी समर्थमहाराष्ट्रातील अनुसूचित जातींची यादीआंब्यांच्या जातींची यादीशिवाजी महाराजांची राजमुद्रापसायदानमहाराष्ट्र शासनसंभाजी भोसलेए.पी.जे. अब्दुल कलामवटपौर्णिमाज्योतिर्लिंगमराठी भाषाविनायक दामोदर सावरकरमहाराष्ट्रातील इतर मागास वर्गीय जातींची यादीभारत