Модуль:Песочница/Abiyoyo/Autosorting/ConfigProcessor
Документация
require( 'strict' )
local getArgs = require('Module:Arguments').getArgs
local DebugLog = require('Module:DebugLog')
local debLog = DebugLog:new()
local cp={}
-- for debug
cp.log = debLog
cp.log.enabled = true
-- Constructor
function cp:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
o.globals = {}
return o
end
--------------------------------------------------------------------------------
--- Filters
-- called from processFilters() as filterFunc(options, frameArgs)
--------------------------------------------------------------------------------
-- filter funcs declarations
local isEmptyParam, isNotEmptyParam, isEqParam, isNotEqParam, isNamespace
local isNotNamespace
cp.filters = {
['parameter-is-empty'] = isEmptyParam,
['parameter-not-empty'] = isNotEmptyParam,
['parameter-equals'] = isEqParam,
['parameter-not-equals'] = isNotEqParam,
['namespace-is'] = isNamespace,
['namespace-is-not'] = isNotNamespace,
default = function() return true end,
}
function cp.isEmptyParam(options, frameArgs)
debLog:write('invoked', 'isEmptyParam')
if not options then return true end
if type(options) ~= 'table' then return true end
if options.param == nil then return true end
if frameArgs[options.param] == nil or frameArgs[options.param] == '' then
return true
end
return false
end
function cp.isNotEmptyParam(options, frameArgs)
debLog:write('invoked', 'isNotEmptyParam')
return not isEmptyParam(options, frameArgs)
end
--- Nasmespace filter
function cp.isNamespace(options, frameArgs)
if not options then return true end
if type(options) ~= 'table' then
return globals.ignoreNSChecks or false
end
if options.namespaces == nil then return true end
local namespace = mw.title.getCurrentTitle().namespace
if hasValue(options.namespaces, namespace) then
return true
end
return globals.ignoreNSChecks or false
end
--- Not nasmespace filter
function cp.isNotNamespace(options, frameArgs)
if not options then return true end
if type(options) ~= 'table' then return true end
if options.namespaces == nil then return true end
local namespace = mw.title.getCurrentTitle().namespace
if hasValue( options.namespaces, namespace ) then
return globals.ignoreNSChecks or false
end
return true
end
--- Вызывает один за другим фильтры из массива filters
-- Если фильтров нет или что-то сконфигурировано неверно, возвращает true
-- Если хотя бы один из фильтров отработал и выдал false, возвращает false
-- Если все фильтры вернули true, возвращает true
-- @function processFilters
-- @param filtMap таблица-список фильтров вида {<filterID> = <func>, ...}
-- @param filters массив с фильтрами вида
-- { {name = <filterID>, options = {<opt1> = val1, ... } ... }
-- @param frameArgs таблица с параметрами фрейма
-- @return true если все фильтры вернули true или проблемы с параметрами
-- false если хотя бы один вернул false
function cp.processFilters(filtMap, filters, frameArgs)
debLog:write('invoked ', 'processFilters')
if type(filtMap) ~= 'table' then return true end
if type(filters) ~= 'table' then return true end
function cp.default() return true end
for i, filter in ipairs(filters) do
debLog:write('processing name: '.. tostring(filter.id), 'processFilters')
local filterFunc = filtMap[filter.id] or filtMap[default] or default
if not filterFunc(filter.options, frameArgs) then
return false
end
end
return true
end
--------------------------------------------------------------------------------
-- General processing
--------------------------------------------------------------------------------
--- Loads config from frame arguments or default
function cp:getConfig(configPath)
if configPath ~= nil and configPath ~= '' then
local success, result = pcall(mw.loadData, configPath)
if success then
self.config = result
else
debLog:write('Config load failed', 'getConfig', 'warn')
end
return success, result
end
return nil
end
--- Gets global options frome config node and sets them to global table
function cp:setGlobalOptions(node)
node = node or self.config.global
if type(node) ~= 'table' then return nil end
if type(node.global) ~= 'table' then return nil end
for k, option in pairs(node.global) do
if option == 'ignoreNSChecks' then
self.globals.ignoreNSChecks = self.globals.ignoreNSChecks or option
else
self.globals[k] = v
end
end
debLog:write('Globals set: '..mw.dumpObject(self.globals), 'setGlobalOptions')
return self.globals
end
--- Takes a named node in config with name 'name from node 'upNode'
-- and returns resulting table
-- @param upNode - previous node. e.g. 'a' for: a = { <name> = { } }
-- @param name string
-- @return table
function cp.getConfigNode(upNode, name)
if type(name) ~= 'string' or name == '' then
return nil, 'Name invalid'
end
if type(upNode) ~= 'table' then
return nil, 'upper node is not a table'
end
return upNode[name]
end
--- Takes a named node in config with name 'name from node 'upNode', adds
-- default values, defined on the same level, and returns resulting table
-- @param upNode - previous node. e.g. 'a' for: a = { <name> = { } }
-- @param name string
function cp.getConfigNodeWithDefaults(upNode, name)
local node = getConfigNode(upNode, name)
local default = upNode['default']
if type(node) == nil then return default end
if type(node) ~= 'table' then return node end
if type(default) ~= 'table' then return node end
local result = {}
for k, v in pairs(default) do
result[k] = v
end
for k, v in pairs(node) do
result[k] = v
end
return result
end
--- Gets filter table from table 'node'
-- @function getFilters
-- @param node
-- @return table or nil
function cp.getFilters(node)
local filters = cp.getConfigNode(node, 'filters')
if type(filters) ~= 'table' then return nil end
return filters
end
--- Gets preset 'name' from table 'node'
-- @function getPreset
-- @param node
-- @return table or nil
function cp.getPreset(node, name)
local preset = cp.getConfigNodeWithDefaults(node, name)
if type(preset) ~= 'table' then return nil end
return preset
end
--- Loads list of strings with rules' IDs from array 'node', and returns an
-- array with those of them, which are also exist as indexes in 'ruleMap'
-- @return array with valid rules
function cp.getRules(ruleMap, node)
local rules = getConfigNode(node, 'rules')
if type(rules) ~= 'table' then return nil end
local validRules = {}
local i = 1
for _, ruleName in ipairs(rules) do
if ruleMap[ruleName] then
validRules[i] = ruleName
i = i + 1
end
end
if next(validRules) == nil then
debLog:write('No valid rulenames found', 'getRules', 'warn')
return nil
end
debLog:write('Valid rules found: '.. mw.dumpObject(validRules), 'getRules')
return validRules
end
--- Executes a function, corresponding to rule with id 'ruleName'
--@param ruleName string with rule id
--@param node node with rule
--@param frameArgs table
--@param preset table with preset
--@return result of a called function or nil
function cp.processRule(node, frameArgs, preset)
local myname = 'processRule'
debLog:write('Invoked', myname)
-- check func name presence and validity
if type(p[node.func]) ~= 'function' then
debLog:write('Function does not exist: ' .. node.func, myname, 'warn')
return nil
end
-- function call
local funcResult = p[node.func](frameArgs, preset, node)
if funcResult == nil then
debLog:write(node.func .. '() returned nil', myname, 'warn')
return ''
end
debLog:write(node.func .. ' returned: '..mw.text.nowiki(funcResult), myname)
return funcResult
end
---Processes rules from array of IDs in ruleList
--@return concatenated result of rules
function cp.processRuleList(ruleList, node, frameArgs, preset)
local result = ''
for _, ruleName in ipairs(ruleList) do
local ruleResult = processRule(node[ruleName], frameArgs, preset)
if ruleResult == nil then
debLog:write('Rule returned nil', 'processRuleList', 'warn')
else
result = table.concat{result, ruleResult}
end
end
return result
end
--------------------------------------------------------------------------------
-- Методы
--------------------------------------------------------------------------------
-- временная обертка для старых методов, потом содержимое перенести в main
function cp.pcall_main(func, ...)
local success, mainstate, result = pcall(p._main, unpack(arg))
if not success then
debLog:write(mainstate, '_main', 'error')
return ''
elseif not mainstate then
debLog:write(result, '_main')
return ''
else
return result
end
end
local p = cp
return p