Модуль:MetaCatDoc (Bk;rl,&MetaCatDoc)
Перейти к навигации
Перейти к поиску
Модуль для создания страницы документации шаблонов через Шаблон:MetaCatDoc, использующих модули
Модуль генерирует список категорий и список шаблонов. Используется в шаблонах {{year-doc}}, {{decade-doc}}, {{century-doc}} и {{country-doc}}.
Пример: {{#invoke:MetaCatDoc|main}}
в шаблоне «{{Архитектура по векам}}» покажет
Добавляет категории:
- Искусство <век> века
- Архитектура по векам
Добавляет шаблон:
- {{Родственные проекты|Портал=Архитектура}}
local p = {}
local currentTitle = mw.title.getCurrentTitle()
local getArgs = require('Module:Arguments').getArgs
local romanConverter = require('Module:Roman').convert
local format = string.format
local CATEGORIES = {
default = {
YearMetaCat2 = 'Категория:Шаблоны для категорий по годам',
DecadeMetaCat = 'Категория:Шаблоны для категорий по десятилетиям',
CenturyMetaCat = 'Категория:Шаблоны для категорий по векам'
},
withCountry = {
YearMetaCat2 = 'Категория:Шаблоны для категорий по странам и годам',
DecadeMetaCat = 'Категория:Шаблоны для категорий по странам и десятилетиям',
CenturyMetaCat = 'Категория:Шаблоны для категорий по странам и векам',
CountryMetaCat = 'Категория:Шаблоны для категорий по странам'
}
}
-- Переменные при использовании стран
local COUNTRY_PLACEHOLDERS = {
'<страна>', '<страны>', '<в стране>',
'<часть света>', '<части света>', '<в части света>',
'<государство>', '<государства>', '<в государстве>',
'<государство:[^>]+>', '<государства:[^>]+>', '<в государстве:[^>]+>'
}
-- Безопасно получает содержимое шаблона по его имени
local function safeGetTemplateContent(templateName)
if not templateName then error('Имя шаблона не может быть пустым') end
local title = mw.title.new(templateName, 10)
if not title then error(format('Невозможно создать объект заголовка для "%s"', templateName)) end
local content = title:getContent()
if not content then error(format('Не удалось получить содержимое шаблона "%s"', templateName)) end
return content
end
-- Очищает текст от служебных тегов и преобразует специальные конструкции
local function cleanText(text)
if not text then return '' end
return text:gsub('<noinclude>.-</noinclude>', ''):gsub('<!--.--->', ''):gsub('{{%s*([^|{}]-)%s*из заголовка[^}]*}}', '<%1>')
end
-- Определяет тип метакатегории на основе текста шаблона
local function detectMetaCategoryType(text)
if not text then error('Текст для определения типа метакатегории не может быть пустым') end
for _, type in ipairs({'YearMetaCat2', 'DecadeMetaCat', 'CenturyMetaCat', 'CountryMetaCat'}) do
if text:find(type) then return type end
end
error('Не найден модуль (YearMetaCat2/DecadeMetaCat/CenturyMetaCat/CountryMetaCat)')
end
-- Преобразует числовое значение века в римские цифры с указанием эры
local function safeCenturyConversion(century)
if not century then return nil end
local num = tonumber(century)
if not num then error(format('Неверный формат века: "%s"', century)) end
return format('%s века%s', romanConverter(math.abs(num)), num < 0 and ' до н. э.' or '')
end
-- Форматирует категорию с указанием временного диапазона веков
local function formatCentury(category, startCentury, endCentury)
if not category then error('Категория не может быть пустой') end
if not (startCentury or endCentury) then return category end
local parts = {}
if startCentury then table.insert(parts, 'с ' .. safeCenturyConversion(startCentury)) end
if endCentury then table.insert(parts, (startCentury and 'по' or 'до') .. ' ' .. safeCenturyConversion(endCentury)) end
return format('%s [%s]', category, table.concat(parts, ' '))
end
-- Извлекает список категорий из кода шаблона
local function extractCategories(text, metaType)
if not text or not metaType then return {} end
local categories = text:match('.-{{#invoke:'..metaType..'|main(.-)}}.*') or ''
local result = {}
for _, category in ipairs(mw.text.split(categories, '|', true)) do
if category ~= '' and not category:find('=') then
table.insert(result, category)
end
end
return result
end
-- Обрабатывает категории и формирует их описание
local function processCategories(text, metaType)
if not text or not metaType then error('Отсутствуют необходимые параметры для обработки категорий') end
local categories = extractCategories(text, metaType)
local result = {"'''Добавляет категории:'''"}
if #categories == 0 then
table.insert(result, '* Нет категорий')
return table.concat(result, '\n')
end
for _, category in ipairs(categories) do
local parts = mw.text.split(category, '!', true)
local mainCategory = mw.text.trim(parts[1])
if metaType == 'CenturyMetaCat' then
mainCategory = formatCentury(mainCategory, parts[3] and mw.text.trim(parts[3]), parts[4] and mw.text.trim(parts[4]))
end
table.insert(result, '* ' .. mainCategory)
end
return table.concat(result, '\n')
end
-- Извлекает параметры из вызовов модуля
local function extractParameters(text, metaType)
if not text or not metaType then return {} end
local params = {}
-- Ищем вызовы модулей #invoke с аргументами range, max, min
for invokeCall in text:gmatch('{{#invoke:'..metaType..'|main.-}}') do
local range = invokeCall:match('range%s*=%s*(%d+)')
local max = invokeCall:match('max%s*=%s*(%d+)')
local min = invokeCall:match('min%s*=%s*(%d+)')
if range or max or min then
table.insert(params, {
range = range,
max = max,
min = min
})
end
end
return params
end
-- Форматирует параметры для вывода
local function processParameters(text, metaType)
local params = extractParameters(text, metaType)
if #params == 0 then return nil end -- Возвращаем nil, если параметры отсутствуют
local result = {"'''Параметры:'''"}
for _, param in ipairs(params) do
-- Добавляем только существующие параметры
if param.range then
table.insert(result, format('* range: %s', param.range))
end
if param.min then
table.insert(result, format('* min: %s', param.min))
end
if param.max then
table.insert(result, format('* max: %s', param.max))
end
end
return table.concat(result, '\n')
end
-- Извлекает шаблоны из текста
local function extractTemplates(text, metaType)
if not text or not metaType then return {} end
local templates = {}
for template in text:gmatch('{{[^#].-}}') do
template = template:sub(3, -3):gsub('{{#invoke:'..metaType..'|expand|', '')
local name, args = template:match('^([^|]+)|?(.*)')
if name then
args = args ~= '' and ('|' .. args:gsub('{{#', '<nowiki>{{#</nowiki>'):gsub('}}', '<nowiki>}}</nowiki>')) or ''
table.insert(templates, {name = name, args = args})
else
table.insert(templates, {name = template, args = ''})
end
end
return templates
end
-- Обрабатывает шаблоны и формирует их описание
local function processTemplates(frame, text, metaType)
if not text or not metaType then error('Отсутствуют необходимые параметры для обработки шаблонов') end
local templates = extractTemplates(text, metaType)
if #templates == 0 then return '' end
local result = {format("'''Добавляет шаблон%s:'''", #templates > 1 and 'ы' or '')}
for _, template in ipairs(templates) do
local templateText = format('<nowiki>{{</nowiki>[[Ш:%s|%s]]%s<nowiki>}}</nowiki>',
template.name, template.name, template.args)
table.insert(result, '* ' .. templateText)
end
return table.concat(result, '\n')
end
-- Определяет категорию для шаблона
local function categorizeTemplate(text, metaType, args)
if not text or not metaType then error('Отсутствуют необходимые параметры для категоризации шаблона') end
if args and args.category then
return (args.category:match('^Категория:') and args.category or 'Категория:' .. args.category)
end
for _, placeholder in ipairs(COUNTRY_PLACEHOLDERS) do
if text:find(placeholder) then
return CATEGORIES.withCountry[metaType]
end
end
return CATEGORIES.default[metaType]
end
-- Возвращает категорию для шаблона
function p.getCategory(frame)
local args = getArgs(frame)
local templateName = currentTitle.text:gsub('/doc$', '')
local templateText = safeGetTemplateContent(templateName)
local metaType = detectMetaCategoryType(templateText)
local category = categorizeTemplate(templateText, metaType, args)
return category and ('[[' .. category .. ']]') or ''
end
-- Основная функция модуля, формирует документацию шаблона
function p.main(frame)
local args = getArgs(frame)
local templateName = (args['title'] or currentTitle.text):gsub('/doc$', '')
local templateText = cleanText(safeGetTemplateContent(templateName))
local metaType = detectMetaCategoryType(templateText)
local category = categorizeTemplate(templateText, metaType, args)
if category then
templateText = templateText .. '\n[[' .. category .. ']]'
end
local result = processCategories(templateText, metaType)
local templatesSection = processTemplates(frame, templateText, metaType)
local parametersSection = processParameters(templateText, metaType)
local output = {result}
if templatesSection ~= '' then
table.insert(output, templatesSection)
end
if parametersSection then
table.insert(output, parametersSection)
end
return frame:preprocess(table.concat(output, '\n\n'))
end
-- Определяет используемые Lua-модули в шаблоне
function p.detectLua(frame)
local templateName = (getArgs(frame)['title'] or currentTitle.text):gsub('/doc$', '')
local moduleSet = {}
for moduleName in safeGetTemplateContent(templateName):gmatch('{{#invoke:([^|}]+)') do
moduleSet[moduleName] = true
end
local modules = {}
for moduleName in pairs(moduleSet) do
table.insert(modules, moduleName)
end
if #modules == 0 then return '' end
local templateArgs = {
title = 'Lua'
}
for i, moduleName in ipairs(modules) do
if i == 1 then
templateArgs[1] = moduleName
else
templateArgs['module' .. i] = moduleName
end
end
templateArgs.nocat = '1'
return frame:expandTemplate{ title = 'Шаблон:Lua', args = templateArgs }
end
return p