Модуль:YearMetaCat/песочница

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
Документация
local p = {}

local cc = nil --required when needed
local roman = nil --required when needed
local roman_to_int = nil --required when needed

local YEAR_PLACEHOLDER = '<год>'
local COUNTRY_NOM_PLACEHOLDER = '<страна>'
local CENTURY_NOM_PLACEHOLDER = '<век>'
local COUNTRY_GEN_PLACEHOLDER = '<страны>'
local CENTURY_GEN_PLACEHOLDER = '<века>'
local COUNTRY_LOC_PLACEHOLDER = '<в стране>'
local CENTURY_PREP_PLACEHOLDER = '<в веке>'
local LAST_DIGIT_PLACEHOLDER = '<последняя_цифра>'
local DECADE_PLACEHOLDER = '<десятилетие>'

local function pattern_from_title(pattern)
	local title = mw.title.getCurrentTitle().text
	for t in mw.ustring.gmatch(title, pattern) do
		return t
	end
	return nil
end

-- простой аналог [[Модуль:Math/tonumber#year]] без дат до нашей эры и обработки других чисел
local function year_from_title()
	return pattern_from_title('[0-9]+')
end

local function roman_from_title()
	return pattern_from_title('[IVLCXDM]+')
end

local function error_string(s)
	return '<span class="error">' .. s .. '</span>'
end

local function get_year(args)
	return tonumber(args['year']) or tonumber(args['год']) or tonumber(year_from_title())
end

local function get_century(args)
	return args['century'] or args['век'] or roman_from_title()
end

local function subst_country(frame, cat_pattern, country)
	if cat_pattern:find(COUNTRY_NOM_PLACEHOLDER) then
		cat_pattern = mw.ustring.gsub(cat_pattern, COUNTRY_NOM_PLACEHOLDER, country)
	end
	if cat_pattern:find(COUNTRY_GEN_PLACEHOLDER) then
		if cc == nil then cc = require('Module:CountryCases') end
		cat_pattern = mw.ustring.gsub(cat_pattern, COUNTRY_GEN_PLACEHOLDER, cc._genitive(frame, country))
	end
	if cat_pattern:find(COUNTRY_LOC_PLACEHOLDER) then
		if cc == nil then cc = require('Module:CountryCases') end
		cat_pattern = mw.ustring.gsub(cat_pattern, COUNTRY_LOC_PLACEHOLDER, cc._locative(frame, country))
	end
	return cat_pattern
end

function p.theme(frame)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
	local args = getArgs(frame)
	local year = get_year(args)
	if year == nil then
		return error_string('Ошибка: не указан год')
	end
	local wt = mw.html.create('table'):addClass('standard'):attr('align', 'center')
	local row = wt:tag('tr')
	local range = tonumber(args['range']) or tonumber(args['диапазон']) or 5
	local country = args['страна'] or args['country']
	local cat_pattern = args[1]
	cat_pattern = subst_country(frame, cat_pattern, country)

	local year_cat = function(y)
		return '[[:К:' .. mw.ustring.gsub(cat_pattern, YEAR_PLACEHOLDER, tostring(y)) .. '|' .. tostring(y) .. ']]'
	end

	local start_year
	local min_year = tonumber(args['min']) or tonumber(args['мин'])
	if min_year then
		start_year = math.max(min_year, year - range)
		if year < start_year then
			return error_string('Год не попадает в диапазон: меньше минимального значения ' .. tostring(min_year))
		end
	else
		start_year = year - range
	end
	for y = start_year, year -1 do
		row:tag('td'):wikitext(year_cat(y))
	end
	row:tag('th'):wikitext(tostring(year))
	local end_year
	local max_year = tonumber(args['max']) or tonumber(args['макс'])
	if max_year then
		end_year = math.min(max_year, year + range)
		if year > end_year then
			return error_string('Год не попадает в диапазон: больше максимального значения ' .. tostring(max_year))
		end
	else
		end_year = year + range
	end
	for y = year +1, end_year do
		row:tag('td'):wikitext(year_cat(y))
	end
	return tostring(wt)
end

local function deexclamatecat(pat)
	local split = mw.text.split(pat, '!', true)
	if split == nil or #split == 0 then
		return ''
	end
	return '[[К:' .. split[1] .. (split[2] and ('|' .. split[2]) or '') .. ']]'
end

local function century_num(year)
	return math.floor((year-1) /100 +1 )
end

local function get_roman_century(frame, year)
	if roman == nil then
		roman = require('Module:Roman').convert
	end
	return year and roman(century_num(year)) or error_string('Укажите год')
end

local function guess_in(rc)
	if rc == 'II' then
		return 'во '
	end
	return 'в '
end

function p.cats(frame)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
	local tt = require('Module:TableTools')
	local args = getArgs(frame)
	local year = get_year(args)
	local country = args['страна'] or args['country']
	local ret = ''
	for _, pat in tt.sparseIpairs(args) do
		ret = ret .. deexclamatecat(pat) .. '\n'
	end
	ret = subst_country(frame, ret, country)
	if ret:find(YEAR_PLACEHOLDER) then
		ret = mw.ustring.gsub(ret, YEAR_PLACEHOLDER, tostring(year))
	end
	local roman_century = get_century(args)
	if ret:find(CENTURY_NOM_PLACEHOLDER) then
		roman_century = roman_century or get_roman_century(frame, year)
		ret = mw.ustring.gsub(ret, CENTURY_NOM_PLACEHOLDER, roman_century .. ' век')
	end
	if ret:find(CENTURY_GEN_PLACEHOLDER) then
		roman_century = roman_century or get_roman_century(frame, year)
		ret = mw.ustring.gsub(ret, CENTURY_GEN_PLACEHOLDER, roman_century .. ' века')
	end
	if ret:find(CENTURY_PREP_PLACEHOLDER) then
		roman_century = roman_century or get_roman_century(frame, year)
		local _in_ = guess_in(roman_century)
		ret = mw.ustring.gsub(ret, CENTURY_GEN_PLACEHOLDER, _in_ .. roman_century .. ' веке')
	end
	if ret:find(LAST_DIGIT_PLACEHOLDER) then
		ret = mw.ustring.gsub(ret, LAST_DIGIT_PLACEHOLDER, tostring(year % 10))
	end
	if ret:find(DECADE_PLACEHOLDER) then
		ret = mw.ustring.gsub(ret, DECADE_PLACEHOLDER, tostring(year - (year % 10)) .. '-е')
	end
	if args['demo'] then --для документации
		return frame:extensionTag('pre', ret)
	else
		return ret
	end
end

function p.decade_theme(frame)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
	local args = getArgs(frame)
	local year = get_year(args)
	if year == nil then
		return error_string('Ошибка: не указан год')
	end
	if year % 10 ~= 0 then
		return error_string('Ошибка: должно использоваться только на страницах десятилетий')
	end
	
	local wt = mw.html.create('table'):addClass('standard'):attr('align', 'center')
	local row = wt:tag('tr')
	local range = tonumber(args['range']) or tonumber(args['диапазон']) or 5
	local country = args['страна'] or args['country']
	local cat_pattern = args[1]
	cat_pattern = subst_country(frame, cat_pattern, country)

	local year_cat = function(y)
		return '[[:К:' .. mw.ustring.gsub(cat_pattern, DECADE_PLACEHOLDER, tostring(y) .. '-е годы') .. '|' .. tostring(y) .. '-е]]'
	end

	local start_year
	local min_year = tonumber(args['min']) or tonumber(args['мин'])
	if min_year then
		if min_year % 10 ~= 0 then
			return error_string('Ошибка: заданный минимальный год не является границей десятилетия')
		end
		start_year = math.max(min_year, year - range * 10)
		if year < start_year then
			return error_string('Год не попадает в диапазон: меньше минимального значения ' .. tostring(min_year))
		end
	else
		start_year = year - range * 10
	end
	for y = start_year, year - 10, 10 do
		row:tag('td'):wikitext(year_cat(y))
	end
	row:tag('th'):wikitext(tostring(year) .. '-е')
	local end_year
	local max_year = tonumber(args['max']) or tonumber(args['макс']) or 2020 -- в будущее сильно уходить не надо, на 10 лет хватит
	if max_year then
		if max_year % 10 ~= 0 then
			return error_string('Ошибка: заданный максимальный год не является границей десятилетия')
		end
		end_year = math.min(max_year, year + range * 10)
		if year > end_year then
			return error_string('Год не попадает в диапазон: больше максимального значения ' .. tostring(max_year))
		end
	end
	for y = year + 10, end_year, 10 do
		row:tag('td'):wikitext(year_cat(y))
	end
	return tostring(wt)
end

function p.century_theme(frame)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
	local args = getArgs(frame)
	local century = get_century(args)
	if century == nil then
		return error_string('Ошибка: не указан век')
	end
	if roman_to_int == nil then
		roman_to_int = require('Module:Roman/песочница')._roman_to_int
	end
	local century_num = roman_to_int(century)
	local wt = mw.html.create('table'):addClass('standard'):attr('align', 'center')
	local row = wt:tag('tr')
	local country = args['страна'] or args['country']
	local cat_pattern = args[1]
	cat_pattern = subst_country(frame, cat_pattern, country)

	local century_cat = function(cn)
		if roman == nil then
			roman = require('Module:Roman').convert
		end
		local r = roman(cn)
		local cat = cat_pattern
		if cat:find(CENTURY_NOM_PLACEHOLDER) then
			cat = mw.ustring.gsub(cat, CENTURY_NOM_PLACEHOLDER, r .. ' век')
		end
		if cat:find(CENTURY_GEN_PLACEHOLDER) then
			cat = mw.ustring.gsub(cat, CENTURY_GEN_PLACEHOLDER, r .. ' века')
		end
		if cat:find(CENTURY_PREP_PLACEHOLDER) then
			local _in_ = guess_in(r)
			cat = mw.ustring.gsub(cat, CENTURY_PREP_PLACEHOLDER, _in_ .. r .. ' веке')
		end
		return '[[:К:' .. cat .. '|' .. r .. ']]'
	end

	local min_century = tonumber(args['min']) or tonumber(args['мин'])
	if min_century == nil or min_century <= century_num - 1 then
		row:tag('td'):wikitext(century_cat(century_num - 1))
	end
	row:tag('th'):wikitext(century)
	
	local end_year
	local max_century = tonumber(args['max']) or tonumber(args['макс']) or 21
	if century_num +1 <= max_century then
		row:tag('td'):wikitext(century_cat(century_num +1))
	end
	return tostring(wt)
end

return p