Modul:TemplatePar: Unterschied zwischen den Versionen

Aus ÖsterreichWiki
Zur Navigation springen Zur Suche springen
wp>PerfektesChaos
(Setup)
(kein Unterschied)

Version vom 27. April 2013, 18:58 Uhr

Modul:Vorlage:LuaModuleDoc:142: attempt to index field 'wikibase' (a nil value)


--[=[ TemplatePar 2013-04-27
Template parameter utility
* check
* count
]=]



-- Module globals
local invokeFrame
local l10nDef = {}
l10nDef[ "en" ] = {
    dupOpt    = "TemplatePar#invoke: repeated optional parameter",
    empty     = "Error in template: undefined value for mandatory",
    undefined = "Error in template: mandatory parameter missing",
    unknown   = "Error in template: unknown parameter name"
}
l10nDef[ "de" ] = {
    dupOpt    = "TemplatePar#invoke: Wiederholter Optionsparameter",
    empty     = "Fehler bei Vorlage: Pflichtparameter ohne Wert",
    undefined = "Fehler bei Vorlage: fehlender Pflichtparameter",
    unknown   = "Fehler bei Vorlage: Unbekannter Parametername"
}



local function failed( spec, suspect )
    -- Submit error message
    -- Precondition:
    --     spec     -- string; message ID
    --     suspect  -- string or nil; additional information
    -- Postcondition:
    --     Return string
    -- Uses:
    --     >  invokeFrame
    --     >  l10nDef
    local r
    local show = invokeFrame.args[ "template" ]
    local l10n = mw.language.getContentLanguage()
    l10n = l10nDef[ l10n:getCode() ]
    if not l10n then
        l10n = l10nDef[ "en" ]
    end
    r = l10n[ spec ]
    if show then
        r = r .. " (" .. show .. ")"
    end
    if suspect then
        r = r .. " " .. suspect
    end
    return r
end -- failed()



local function fault( store, key )
    -- Add key to collection string and insert separator
    -- Precondition:
    --     store  -- string or nil or false; collection string
    --     key    -- string or number; to be appended
    -- Postcondition:
    --    Return string; extended
    local r
    local s
    if type( key ) == "number" then
        s = tostring( key )
    else
        s = key
    end
    if store then
        r = store .. "; " .. s
    else
        r = s
    end
    return r
end -- fault()



local function fed( haystack, needle )
    -- Find needle in haystack map
    -- Precondition:
    --     haystack  -- table; map of key values
    --     needle    -- any; identifier
    -- Postcondition:
    --    Return true iff found
    local k, v
    for k, v in pairs( haystack ) do
        if k == needle then
            return true
        end
    end -- for k, v
    return false
end -- fed()



local function fetch()
    -- Return regular table with template parameters
    -- Postcondition:
    --    Return table; whitespace-only values as false
    -- Uses:
    --     >  invokeFrame
    --     frame:getParent()
    local k, v
    local r = { }
    local t = invokeFrame:getParent()
    local o = t.args
    for k, v in pairs( o ) 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
    return r
end -- fetch()



local function fill( specified )
    -- Split requirement string separated by '='
    -- Precondition:
    --     specified  -- string or nil; requested parameter set
    -- Postcondition:
    --    Return sequence table
    local r
    if specified then
        local i, s
        r = mw.text.split( specified, "%s*=%s*" )
        for i = #r, 1, -1 do
            s = r[ i ]
            if #s == 0 then
                table.remove( r, i )
            end
        end -- for i, -1
    else
        r = { }
    end
    return r
end -- fill()



local function finder( haystack, needle )
    -- Find needle in haystack sequence
    -- Precondition:
    --     haystack  -- table; sequence of key names
    --     needle    -- any; key name
    -- Postcondition:
    --    Return true iff found
    local i
    for i = 1, #haystack do
        if haystack[ i ] == needle then
            return true
        end
    end -- for i
    return false
end -- finder()



local function fit( base, extend )
    -- Merge two tables, create new sequence if both not empty
    -- Precondition:
    --     base    -- table; sequence kept unchanged
    --     extend  -- table; sequence to be appended
    -- Postcondition:
    --     Return merged table, or message string if duplicated entries
    -- Uses:
    --     finder()
    --     fault()
    local r
    if #base == 0 then
        if #extend == 0 then
            r = { }
        else
            r = extend
        end
    else
        if #extend == 0 then
            r = base
        else
            local i, s
            r = false
            for i = 1, #extend do
                s = extend[ i ]
                if finder( base, s ) then
                    r = fault( r, s )
                end
            end -- for i
            if not r then
                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
    return r
end -- fit()



local function fix( valid, duty )
    -- Perform parameter analysis
    -- Precondition:
    --     valid  -- table; unique sequence of known parameters
    --     duty   -- table; sequence of mandatory parameters
    -- Postcondition:
    --     Return string as configured; empty if valid
    -- Uses:
    --     >  invokeFrame
    --     fetch()
    --     finder()
    --     fault()
    --     failed()
    --     fed()
    local k, v
    local r   = false
    local got = fetch()
    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 = failed( "unknown", r )
    else -- all names valid
        -- avoid confusing consecutive error messages
        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 = failed( "undefined", r )
        else
            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 = failed( "empty", r )
            end
        end
    end
    if r then
        if invokeFrame.args[ "noError" ] then
            r = ""
        else
            r = "<span class='error'>" .. r .. "</span>"
        end
        k = invokeFrame.args[ "cat" ]
        if k then
            if k:find( "@@@" ) then
                v = invokeFrame.args[ "template" ]
                if v then
                    k = k:gsub( "@@@", v )
                end
            end
            r = r .. "[[Category:" .. k .. "]]"
        end
    else
        r = ""
    end
    return r
end -- fix()



local function force()
    -- Initialize parameter analysis
    -- Postcondition:
    --     Return string as configured; empty if valid
    -- Uses:
    --     >  invokeFrame
    --     fill()
    --     fit()
    --     failed()
    --     fix()
    local duty    = fill( invokeFrame.args[ 1 ] )
    local options = fill( invokeFrame.args[ 2 ] )
    local r       = fit( duty, options )
    if type( r ) == "string" then
        r = failed( "dupOpt", r )
    else
        r = fix( r, duty )
    end
    return r
end -- force()



-- Provide template access

local p = {}

function p.check( frame )
    -- Check validity of template parameters
    -- Precondition:
    --     frame  -- object; #invoke environment
    -- Postcondition:
    --     Return string with error message or ""
    -- Uses:
    --     force()
    --      < invokeFrame
    invokeFrame = frame
    return force()
end -- .check()

function p.count( frame )
    -- Count number of template parameters
    -- Precondition:
    --     frame  -- object; #invoke environment
    -- Postcondition:
    --     Return string with digits including "0"
    -- Uses:
    --     fetch()
    --      < invokeFrame
    invokeFrame = frame
    local g = fetch()
    return tostring( #g )
end -- .count()

return p