Модуль:Хронотоп

Для документации этого модуля может быть создана страница Модуль:Хронотоп/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