Modul:TemplatePar: Unterschied zwischen den Versionen

6.055 Bytes hinzugefügt ,  10. Juli 2013
updates + match
wp>PerfektesChaos
(+pagename)
wp>PerfektesChaos
(updates + match)
Zeile 1: Zeile 1:
--[=[ TemplatePar 2013-06-28
--[=[ TemplatePar 2013-07-09
Template parameter utility
Template parameter utility
* assert
* assert
Zeile 6: Zeile 6:
* countNotEmpty
* countNotEmpty
* downcase
* downcase
* match
* valid
* valid
* verify
* verify
Zeile 18: Zeile 19:
local l10nDef = {}
local l10nDef = {}
l10nDef[ "en" ] = {
l10nDef[ "en" ] = {
     badPattern  = "#invoke:TemplatePar * pattern syntax error",
     badPattern  = "#invoke:TemplatePar pattern syntax error",
     dupOpt      = "#invoke:TemplatePar * repeated optional parameter",
     dupOpt      = "#invoke:TemplatePar repeated optional parameter",
     dupRule    = "#invoke:TemplatePar * parameter conflict key/pattern",
     dupRule    = "#invoke:TemplatePar conflict key/pattern",
     empty      = "Error in template * undefined value for mandatory",
     empty      = "Error in template * undefined value for mandatory",
     invalid    = "Error in template * invalid parameter",
     invalid    = "Error in template * invalid parameter",
     invalidPar  = "#invoke:TemplatePar * invalid parameter",
     invalidPar  = "#invoke:TemplatePar invalid parameter",
     minmax      = "#invoke:TemplatePar * min > max",
     minmax      = "#invoke:TemplatePar min > max",
     multiSpell  = "Error in template * multiple spelling of parameter",
     multiSpell  = "Error in template * multiple spelling of parameter",
     noErrorCat  = "#invoke:TemplatePar * noError and missing category",
     noErrorCat  = "#invoke:TemplatePar noError and missing category",
     noname      = "#invoke:TemplatePar * missing parameter name",
     noname      = "#invoke:TemplatePar missing parameter name",
     tooLong    = "Error in template * parameter too long",
     tooLong    = "Error in template * parameter too long",
     tooShort    = "Error in template * parameter too short",
     tooShort    = "Error in template * parameter too short",
     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",
     dupRule    = "#invoke:TemplatePar * Parameterkonflikt key/pattern",
     dupRule    = "#invoke:TemplatePar Konflikt key/pattern",
     empty      = "Fehler bei Vorlage * Pflichtparameter ohne Wert",
     empty      = "Fehler bei Vorlage * Pflichtparameter ohne Wert",
     invalid    = "Fehler bei Vorlage * Parameter ungültig",
     invalid    = "Fehler bei Vorlage * Parameter ungültig",
     invalidPar  = "#invoke:TemplatePar * Ungültiger Parameter",
     invalidPar  = "#invoke:TemplatePar Ungültiger Parameter",
     minmax      = "#invoke:TemplatePar * min > max",
     minmax      = "#invoke:TemplatePar min > max",
     multiSpell  = "Fehler bei Vorlage * Mehrere Parameter-Schreibweisen",
     multiSpell  = "Fehler bei Vorlage * Mehrere Parameter-Schreibweisen",
     noErrorCat  = "#invoke:TemplatePar * noError und keine Kategorie",
     noErrorCat  = "#invoke:TemplatePar noError und keine Kategorie",
     noname      = "#invoke:TemplatePar * Parametername nicht angegeben",
     noname      = "#invoke:TemplatePar Parameter nicht angegeben",
     tooLong    = "Fehler bei Vorlage * Parameter zu lang",
     tooLong    = "Fehler bei Vorlage * Parameter zu lang",
     tooShort    = "Fehler bei Vorlage * Parameter zu kurz",
     tooShort    = "Fehler bei Vorlage * Parameter zu kurz",
     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 = {
local Patterns = {
Zeile 209: Zeile 210:
     return r
     return r
end -- fault()
end -- fault()
local function feasible( analyze, options, abbr )
    -- Check content of a value
    -- Precondition:
    --    analyze  -- string to be analyzed
    --    options  -- table or nil; optional details
    --                options.pattern
    --                options.key
    --                options.say
    --    abbr    -- true: abbreviated error message
    -- Postcondition:
    --    Return string with error message as configured;
    --            false if valid or no answer permitted
    -- Uses:
    --    >  Patterns
    --    failure()
    --    mw.text.trim()
    --    failsafe()
    --    containsCJK()
    local r    = false
    local s    = false
    local show = nil
    local scan = false
    if type( options.pattern ) == "string" then
        if options.key then
            r = failure( "dupRule", false, options )
        else
            scan = options.pattern
        end
    else
        if type( options.key ) == "string" then
            s = mw.text.trim( options.key )
        else
            s = "+"
        end
        if s ~= "*" then
            scan = Patterns[ s ]
        end
        if type( scan ) == "string" then
            if s == "n" or s == "0,0" or s == "0.0" then
                if not analyze:match( "[0-9]" ) then
                    scan = false
                    if options.say then
                        show = "'" .. options.say .. "'"
                    end
                    if abbr then
                        r = show
                    else
                        r = failure( "invalid", show, options )
                    end
                end
            end
        elseif s ~= "*" then
            local op, n, plus = s:match( "([<!>]=?)([-0-9][%S]*)(+?)" )
            if op then
                n = tonumber( n )
                if n then
                    local i = tonumber( analyze )
                    if i then
                        if op == "<" then
                            i = ( i < n )
                        elseif op == "<=" then
                            i = ( i <= n )
                        elseif op == ">" then
                            i = ( i > n )
                        elseif op == ">=" then
                            i = ( i >= n )
                        elseif op == "!=" then
                            i = ( i ~= n )
                        else
                            n = false
                        end
                    end
                    if not i then
                        r = "invalid"
                    end
                elseif plus then
                    r = "undefined"
                end
            end
            if not n and not r then
                r = "unknownRule"
            end
            if r then
                if options.say then
                    show = "'" .. options.say .. "' " .. s
                else
                    show = s
                end
                if abbr then
                    r = show
                else
                    r = failure( r, show, options )
                end
            end
        end
    end
    if scan then
        local legal, got = pcall( failsafe, analyze, scan )
        if legal then
            if not got then
                if s == "aa" then
                    got = containsCJK( analyze )
                end
                if not got then
                    if options.say then
                        show = "'" .. options.say .. "'"
                    end
                    if abbr then
                        r = show
                    else
                        r = failure( "invalid", show, options )
                    end
                end
            end
        else
            r = failure( "badPattern",
                        scan .. " *** " .. got,
                        options )
        end
    end
    return r
end -- feasible()




Zeile 273: Zeile 399:
     return r
     return r
end -- fetch()
end -- fetch()
local function figure( append, options )
    -- Extend options by rule from #invoke strings
    -- Precondition:
    --    append  -- string or nil; requested rule
    --    options  --  table; details
    --                  ++ .key
    --                  ++ .pattern
    -- Postcondition:
    --    Return sequence table
    local r = options
    if type( append ) == "string" then
        local story = mw.text.trim( append )
        local sub  = story:match( "^/(.*%S)/$" )
        if type( sub ) == "string" then
            sub            = sub:gsub( "%%!", "|" )
            sub            = sub:gsub( "%%%(%(", "{{" )
            sub            = sub:gsub( "%%%)%)", "}}" )
            options.pattern = sub
            options.key    = nil
        else
            options.key    = story
            options.pattern = nil
        end
    end
    return r
end -- figure()




Zeile 390: Zeile 545:
     end -- for k, v
     end -- for k, v
     if r then
     if r then
         r = failure( "unknown", r, options )
         r = failure( "unknown", "'" .. r .. "'", options )
     else -- all names valid
     else -- all names valid
         local i, s
         local i, s
Zeile 516: Zeile 671:
     -- Uses:
     -- Uses:
     --    fold()
     --    fold()
    --    failure()
     --    fetch()
     --    fetch()
     --    fix()
     --    fix()
Zeile 553: Zeile 707:
     --    analyze  -- string to be analyzed
     --    analyze  -- string to be analyzed
     --    options  -- table or nil; optional details
     --    options  -- table or nil; optional details
    --                options.pattern
    --                options.key
     --                options.say
     --                options.say
     --                options.min
     --                options.min
Zeile 562: Zeile 714:
     --            false if valid or no answer permitted
     --            false if valid or no answer permitted
     -- Uses:
     -- Uses:
     --    >  Patterns
     --    feasible()
     --    failure()
     --    failure()
    --    mw.text.trim()
     local r    = feasible( analyze, options, false )
    --    failsafe()
     local show
    --    containsCJK()
     local r    = false
    local s    = false
    local show = nil
    local scan = false
    if type( options.pattern ) == "string" then
        if options.key then
            r = failure( "dupRule", false, options )
        else
            scan = options.pattern
        end
    else
        if type( options.key ) == "string" then
            s = mw.text.trim( options.key )
        else
            s = "+"
        end
        scan = Patterns[ s ]
        if type( scan ) == "string" then
            if s == "n" or s == "0,0" or s == "0.0" then
                if not analyze:match( "[0-9]" ) then
                    scan = false
                    if options.say then
                        show = "'" .. options.say .. "'"
                    end
                    r = failure( "invalid", show, options )
                end
            end
        else
            r = failure( "unknownRule", s, options )
        end
     end
    if scan then
        local legal, got = pcall( failsafe, analyze, scan )
        if legal then
            if not got then
                if s == "aa" then
                    got = containsCJK( analyze )
                end
                if not got then
                    if options.say then
                        show = "'" .. options.say .. "'"
                    end
                    r = failure( "invalid", show, options )
                end
            end
        else
            r = failure( "badPattern",
                        scan .. " *** " .. got,
                        options )
        end
    end
     if options.min  and  not r then
     if options.min  and  not r then
         if type( options.min ) == "number" then
         if type( options.min ) == "number" then
Zeile 668: Zeile 768:
     --            false if valid or no answer permitted
     --            false if valid or no answer permitted
     -- Uses:
     -- Uses:
    --    >  Patterns
    --    failure()
    --    mw.text.trim()
     --    format()
     --    format()
     --    failure()
     --    failure()
Zeile 688: Zeile 785:
     return r
     return r
end -- formatted()
end -- formatted()




Zeile 702: Zeile 798:
     --    form()
     --    form()
     --    mw.text.trim()
     --    mw.text.trim()
    --    failure()
     --    TemplatePar.assert()
     --    TemplatePar.assert()
     --    TemplatePar.valid()
     --    TemplatePar.valid()
Zeile 712: Zeile 809:
                                     "noError",
                                     "noError",
                                     "template" },
                                     "template" },
                       template  = "#invoke:TemplatePar|".. action .. "|"
                       template  = "&#35;invoke:TemplatePar|".. action .. "|"
                     }
                     }
     local r      = form( false, options )
     local r      = form( false, options )
     if not r then
     if not r then
         local s = mw.text.trim( frame.args[ 2 ] )
         local s
         options = { cat      = frame.args.cat,
         options = { cat      = frame.args.cat,
                     low      = frame.args.low,
                     low      = frame.args.low,
Zeile 722: Zeile 819:
                     template = frame.args.template
                     template = frame.args.template
                   }
                   }
         if type( s ) == "string" then
         options = figure( frame.args[ 2 ], options )
            local sub = s:match( "^/(.*%S)/$" )
            if type( sub ) == "string" then
                sub = sub:gsub( "%%!", "|" )
                sub = sub:gsub( "%%%(%(", "{{" )
                sub = sub:gsub( "%%%)%)", "}}" )
                options.pattern = sub
            else
                options.key = s
            end
        end
         if type( frame.args.min ) == "string" then
         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*$" )
Zeile 861: Zeile 948:
     --    mw.getCurrentFrame()
     --    mw.getCurrentFrame()
     --    frame:getParent()
     --    frame:getParent()
     --    mw.ustring.lower()
     --    flat()
    --    fault()
    --    failure()
     local t = mw.getCurrentFrame():getParent()
     local t = mw.getCurrentFrame():getParent()
     return flat( t.args, options )
     return flat( t.args, options )
Zeile 959: Zeile 1.044:
                                     "noError",
                                     "noError",
                                     "template" },
                                     "template" },
                       template  = "#invoke:TemplatePar|check|"
                       template  = "&#35;invoke:TemplatePar|check|"
                     }
                     }
     local r = form( false, options )
     local r = form( false, options )
Zeile 996: Zeile 1.081:
     return tostring( TemplatePar.countNotEmpty() )
     return tostring( TemplatePar.countNotEmpty() )
end -- .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()




Anonymer Benutzer