Модуль:SummaryII/args
Перейти к навигации
Перейти к поиску
Для документации этого модуля может быть создана страница Модуль:SummaryII/args/doc
-- Dependencies:
local lc, sub, gsub, find = mw.ustring.lower, mw.ustring.sub, mw.ustring.gsub, mw.ustring.find
local trim, split = mw.text.trim, mw.text.split
-- Service functions:
local function strip (name)
return gsub (lc (tostring(name)), '[%s%p]', '')
end -- local function strip (name)
local function subst (str, tbl)
local ret = str
for key, val in pairs (tbl) do
ret = gsub (ret, '\\' .. key, tostring (val))
end
return ret
end -- local function subst (str, tbl)
local function merge (...)
local res = {}
for _, tbl in ipairs {...} do
setmetatable (res, getmetatable (tbl))
for key, val in pairs (tbl) do
if type (key) == 'number' and res [key] ~= nil then
res [#res + 1] = val
else
res [key] = val
end
end
end -- for _, tbl in ipairs {...}
return res
end -- local function merge (...)
local function deep_table ()
return setmetatable ({}, {
__newindex = function (tbl, index, val)
local first = strip (table.remove (index, 1))
first = tonumber (first) or first
if #index == 0 then
rawset (tbl, first, tonumber (val) or val)
else
-- recursion:
rawset (tbl, first, tbl [first] or deep_table ())
tbl [first] [index] = val
end -- if #index == 0
end -- __newindex = function (tbl, index, val)
}) -- return setmetatable ({}, {...})
end -- local function deep_table ()
-- Get template or module arguments:
local function get_args (frame)
-- На случай вызова из шаблона и из модуля:
local args = frame:getParent () and mw.clone (frame:getParent ().args) or {}
-- Overrides:
for key, val in pairs (frame.args) do
args [key] = val
end
return args
end -- local function get_args (frame)
-- Interpret short syntax (key = val) of parsing rule:
local function interpret (key, val)
local key_filter, key_target, val_filter, val_target
if type (key) == 'number' then
-- key filter:
key_filter = val
elseif type (key) ~= 'table' then
-- key target = ...:
key_target = key
if type (val) ~= 'table' then
-- key target = key filter:
key_filter = val
else
-- key target = {value target = value filter}:
key_filter = key
val_target = next (val)
val_filter = val [val_target]
end
elseif type (key) == 'table' then
-- {key target = key filter} = ...:
key_target = next (key)
key_filter = key [key_target]
if type (val) ~= 'table' then
-- {key target = key filter} = value filter:
val_filter = val
else
-- {key target = key filter} = {value target = value filter}:
val_target = next (val)
val_filter = val [val_target]
end
end
return key_filter, key_target, val_filter, val_target
end -- local function interpret (rey, val)
local function test_rule (str, filter, full)
local success, captures = false, {}
if not filter then
-- no filter:
success, captures = true, {[full or 0] = str}
elseif type (filter) == 'string' then
-- plain filter:
success = str == filter
captures = {[full or 0] = str}
elseif sub (tostring (filter), 1, 14) == 'rex_pcre_regex' then
-- RCRE filter:
local start, finish
start, finish, captures = filter:tfind (str)
success = start ~= nil
if success then
captures [full or 0] = sub (str, start, finish - start + 1)
end
elseif lpeg.type (filter) == 'pattern' then
-- LPEG filter:
captures = {filter:match (tostring (str))}
success = next (captures) ~= nil
captures [full or 0] = str
else
-- unrecognised filter.
end
return success, captures
end -- local function test_rule (str, filter, full)
--[[
This function rearranges args according to rules and returns:
--]]
local function parse (args, rules)
local res = deep_table ()
local stripped = {}
for rule1, rule2 in pairs (rules) do
local key_filter, key_target, val_filter, val_target = interpret (rule1, rule2)
for key, val in pairs (args) do
-- Cache key brought to lower case and stripped of spaces and punctuation:
stripped [key] = stripped [key] or strip (key)
local stripped_key = stripped [key]
-- Parse key:
local key_fits, key_captures = test_rule (stripped_key, key_filter, '__key')
if key_fits then
-- Parse value:
local val_fits, val_captures = test_rule (val, val_filter)
if val_fits then
-- if both tables are not empty:
local captures = merge (key_captures, val_captures)
res [split (subst (key_target or stripped_key, captures), '/')]
= subst (val_target or val, captures)
end
end
end -- for key, val in pairs (args)
end -- for rule1, rule2 in pairs (rules)
return res
end -- local function parse (args, rules)
return {
get = get_args
, parse = parse
, test = function (no)
local regex = rex_pcre.new
local re = require 'Module:Re'.compile
local tests = {
{
rules = {
total = {['\\0'] = regex '^\\d+$'}
, [{['no / \\1'] = regex 'no(\\d+)'}] = regex '\\d+'
, [{['part / \\no'] = regex 'part(?<no>\\d+)'}] = regex '\\d+'
, ['free / \\1'] = regex 'free(\\d+)'
, title = regex '^название$'
} -- rules
, args = {
total = 120
, No_1 = 10
, no2 = 20
, no3 = 'Сапоги всмятку'
, free2 = 'Free 2'
, free_4 = 'Free 4'
, ['Free 5'] = 'Free 5'
, ['part 1'] = 1
, ['Название']= 'А вот и название'
}
}, {
rules = {
['part/\\1']= regex '^раздел(\\d+)$'
, nocontent = regex '^безсодержания$'
, current = regex '^раздел$'
, currentno = regex '^№раздела$'
} -- rules
, args = {
['раздел0'] = 'Введение'
, ['раздел 1'] = 'Глава I'
, ['раздел_2'] = 'Глава II'
, ['Раздел 3'] = 'Заключение'
, ['без содержания'] = 'да'
, ['Раздел'] = 'Глава II'
, ['№ раздела'] = 2
}
}
} -- local tests
local t = parse (tests [no].args, tests [no].rules)
return require 'Module:Test'.serialise (t)
end -- test = function (no)
}