Модуль:Хронотоп
Для документации этого модуля может быть создана страница Модуль:Хронотоп/doc
local m = {}
local chronoData = {
-- API:
numberedArgs = {
['место'] = 'place', ['город'] = 'place',
['дата'] = 'time' , ['год'] = 'time', ['время'] = 'time',
['название'] = 'title',
['описание'] = 'descr',
['широта'] = 'lat' , ['lat'] = 'lat',
['долгота'] = 'lon' , ['lon'] = 'lon'
}
-- Экспортируемые функции:
, apiFunc = 'функция'
-- Ошибки:
, errorError = 'Ошибка'
, errorUnrecognised = 'Параметр %1% не известен'
}
local function formatChronoError (message, ...)
if select('#', ... ) > 0 then
message = mw.ustring.format (message, ...)
end
return '<span class="error">' .. message .. '</span>'
end
-- Функция, разделяющая имя параметра на нормализованную версию и номер:
local function convertParamName (key)
-- Сначала ненумеруемые:
for alias, converted in pairs (chronoData.unnumberedArgs) do
if alias == key then
return converted, nil
end
end
-- Потом нумеруемые:
for alias, converted in pairs (chronoData.numberedArgs) do
local matched = mw.ustring.gmatch (key, '^' .. alias .. '(%d*)$')
if matched then
if matched [1] ~= '' then
return converted, tonumber (matched [1])
else
return converted, 1 -- нет номера -- считать единицей.
end
end
end
-- Если управление дошло сюда, параметр не опознан:
return nil, nil
end
-- Функция, фильтрующая и разбивающая по наборам (кроме ненумеруемых) параметры:
local function sortParams (args)
local params = {}
for key, val in pairs (args) do
local converted, no = convertParamName (key)
if converted then
if no then
-- Нумерованный параметр:
params [no] = params [no] or {}
params [no] [converted] = val
else
-- Безномерной параметр:
params [converted] = val
end
else
-- Параметр не распознан:
return chronoData.errorUnrecognised
end
end
return nil, params
end
-- Функция «функция». Получает необработанные
-- (только отфильтрованные и разбитые по наборам) параметры:
local function showFunc (sets)
-- Дотянуть недостающие координаты. Для экономии запросов SMW, в одном цикле:
local unpositioned = {}
for i, set in ipairs (sets) do
if not (set.lat and set.lon) then
unpositioned [#unpositioned + 1] = set.place
end
end
local orlist = table.concat (unpositioned, '|')
local coords = mw.ext.smw.ask {
'[[' .. orlist .. ']]'
, '?Географическая широта#lat'
, '?Географическая долгота#lon'
, link = none
, limit = 500
}
for i, set in ipairs (sets) do
if not set.lat then
set.lat = coords [set.place].lat
end
if not set.lon then
set.lon = coords [set.place].lon
end
end
local places = {}
local times = {}
local items = {}
for i, set in ipairs (sets) do
-- Попробовать вынести в функции. Обернуть в условия по гл. параметрам:
-- Добавить к карте:
places [set.place] = places [set.place] or {}
places [set.place] [#places [set.place] + 1] = set
-- Добавить к хронологии:
times [set.time] = times [set.time] or {}
times [set.time] [#times [set.time] + 1] = set
-- Добавить к классификации (?):
items [set.title] = items [set.title] or {}
items [set.title] [#items [set.title] + 1] = set
end
-- Вывести:
return showMap (places) .. showChrono (times) .. showItems (items)
end
-- Регистрация эспортируемых функций:
-- «функция»:
m [chronoData.apiFunc] = function (frame)
-- Поверхностная обработка параметров (вызова или шаблона):
local args
local nextfunc, static, cur = pairs (frame.args)
if nextfunc (static, cur) == nil then
-- аргументы не переданы. Использовать аргументы шаблона:
args = frame:getParent ().args
else
-- переданы аргументы:
args = frame.args
end
-- Отфильтровать и сгруппировать параметры:
local params, err = sortParams (args)
if params then
-- Передать параметры функции-реализатору:
return showFunc (params)
else
-- Распознавание параметров не удалось:
return err
end
end
-- Последняя строка. Экспорт функций из модуля:
return m