Modul:TemplatePar

Aus FreeWiki
Version vom 28. April 2013, 14:37 Uhr von te>PerfektesChaos (update)
Zur Navigation springen Zur Suche springen

--[=[ TemplatePar 2013-04-28 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 figure()

   -- Return number of template parameters
   -- Postcondition:
   --    Return number, starting at 0
   -- Uses:
   --     >  invokeFrame
   --     frame:getParent()
   local k, v
   local r = 0
   local t = invokeFrame:getParent()
   local o = t.args
   for k, v in pairs( o ) do
       r = r + 1
   end -- for k, v
   return r

end -- figure()


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 = "" .. r .. ""
       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 .. ""
       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:
   --     figure()
   --      < invokeFrame
   invokeFrame = frame
   return tostring( figure() )

end -- .count()

function p.valid( frame )

   -- Check validity of one template parameter
   -- Precondition:
   --     frame  -- object; #invoke environment
   -- Postcondition:
   --     Return string with error message or ""
   -- Uses:
   --      < invokeFrame
   invokeFrame = frame
   return "#invoke:TemplatePar|valid| Not yet available"

end -- .valid()

return p