Модуль:parameters

Материал из Викисловаря
Документация

Модуль предоставляет функции проверки и обработки аргументов шаблонов

обработка

process(args, params, return_unknown) Обрабатывает аргументы с заданным списком параметров и возвращает таблицу, содержащую обработанные аргументы. Параметр args определяет аргументы, которые будут обработаны; это аргументы, которые вы могли бы извлечь из frame:getParent().args. Параметр params определяет список допустимых параметров, и состоит из таблицы. Если аргумент не встречается в таблице параметров, возвращается ошибка.

Таблица параметров должна иметь имена параметров в качестве индексов, и (возможно, пустую) таблицу параметров тэгов в качестве значения. Пустая таблица в качестве значения лишь констатирует, что параметр существует, но не должен принимать какие-либо специальную обработку. Возможные тэги параметров перечислены ниже. Пример таблицы параметров (из Module:translations):

{
	[1] = {required = true, default = "und"},
	[2] = {},
	[3] = {list = true},
	["alt"] = {},
	["sc"] = {},
	["tr"] = {},
}

Параметр return_unknown, если установлено значение true предотвращает функцию от включения ошибки, когда функция проходит через аргумент с несуществующим именем. Вместо этого возвращаемое значение будет пара значений: первое, обычно обработанные аргументы, второе содержит все нераспознанные аргументы, которые были оставлены необработанными. Это позволяет выполнять многоступенчатую обработку, где весь набор аргументов, которые шаблон должен принимать заранее не известен. Например, таблица интонаций может сделать некоторую общую обработку над некоторыми аргументами, но затем отложить обработку остатка функции, которая обрабатывает конкретный тип интонации.

Тэги параметров

required=true
Обязательный параметр, если отсутствует, возвращается ошибка. Исключение страница шаблона сама по себе; здесь ошибка не возращается.
allow_empty=true
Если аргумент-пустое значение строки, аргумент не преобразуется в nil, а остается как есть.
type=
Определяет в какой тип данных преобразуется значение аргумента. По умолчанию, значение остается в виде текстовой строки. Альтернативы:
type="boolean"
Значение рассматривается как логическое значение, либо "истина"(true), либо "ложь"(false). Без значения, пустая строка, и строки "0", "no", "n" и "false" рассматриваются как "ложь"(false), все остальные значения считаются "истина"(true).
type="number"
Значение преобразуется в число, если только оно не равно нулю.
alias_of=
Рассматривает параметр как псевдоним другого. Когда для данного параметра указаны аргументы, то аргументы автоматически будут переименованы и сохранены под псевдонимом. Это позволяет параметрам с несколькими альтернативными именами, в то же время, рассматривать их как если бы они имели только одно имя. Это возможно даже для alias_of= иметь имя, которое не является параметром самим по себе.
list=

Рассматривает параметр список значений, каждый из которых имеет свое собственное имя параметра, а не одно значение. Параметры будут иметь номер в конце, за исключением первого. Например, list=true в параметре с именем "head" будет включать параметры head=, head2=, head3= и т.д. Если имя параметра является числом, другое число не добавляется, но подсчет просто продолжается, например, для параметра 3, последовательность 3=, 4=, 5= и т.д. Параметры списка возвращаются в виде нумерованных списков, поэтому для шаблона, который задается параметрами head=a|head2=b|head3=c, обработанные значения параметра head будут {"a", "b", "c"}.

Значение для list= также может быть строкой. Это говорит модулю, что параметры, кроме первого, должны иметь другое имя, которое используется, когда первый параметр в списке-число, а остальные именованы. Примером могут быть данные полов: list="g" в параметре с именем 1 будет иметь параметры 1=, g2=, g3= etc. Если номер не находится в конце, он может быть указан, постановкой знака равенства "=" в номере позиции. Например, параметры "f1accel", "f2accel", ... могут быть захвачены использованием имени параметра "f=accel", как в Module:headword/templates.
allow_holes=true
Это используется в сочетании с параметрами списочного типа. По умолчанию значения плотно упакованы в результирующий список. Это означает, что если, например, запись указана head=a|head3=c но не head2=, возвращенный список будет {"a", "c"}, со значениями, сохраненными как индексы 1 and 2, not 1 and 3. Если желательно сохранить нумерацию нетронутой, например, если число нескольких параметров списка коррелируют друг с другом, то этот тег может быть определен.
Если allow_holes=true определен, могут быть значения nil между двумя вещественными значениями, что сделает так, что многие из функций обработки таблиц Lua больше не будут работать, подобно # или ipairs. Чтобы решить эту проблему, результирующая таблица будет содержать дополнительное именованное значение, maxindex, которое скажет вам самый высокий числовой индекс, который присутствует в таблице. В приведенном выше примере, в результирующей таблице будет теперь {"a", nil, "c", maxindex=3}. Таким образом, вы можете перебирать значения от 1 до maxindex, в то же время пропустив значения nil между ними.
default=
Задает значение по умолчанию для параметра, если он отсутствует или пустой. При использовании на список параметров, указывает значение по умолчанию только для первого элемента в списке. Обратите внимание, что не представляется возможным, сгенерировать значение по умолчанию, которое зависит от значения других параметров.
Если используется вместе с required=true, умолчание применяется только к самой странице шаблона. Это может быть использовано, чтобы показать пример текста.
local export = {}

-- A helper function to escape magic characters in a string
-- Magic characters: ^$()%.[]*+-?
local function plain(text)
	return mw.ustring.gsub(text, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1")
end

-- A helper function that removes empty numeric indexes in a table,
-- so that the values are tightly packed like in a normal Lua table.
function export.remove_holes(list)
	local new_list = {}
	
	for i = 1, list.maxindex do
		table.insert(new_list, list[i])
	end
	
	return new_list
end

function export.process(args, params, return_unknown)
	local args_new = {}
	
	-- Process parameters for specific properties
	local required = {}
	local patterns = {}
	local list_from_index = nil
	
	for name, param in pairs(params) do
		if param.required then
			required[name] = true
		end
		
		if param.list then
			if param.default ~= nil then
				args_new[type(name) == "string" and mw.ustring.gsub(name, "=", "") or name] = {param.default, maxindex = 1}
			else
				args_new[type(name) == "string" and mw.ustring.gsub(name, "=", "") or name] = {maxindex = 0}
			end
			
			if type(param.list) == "string" then
				-- If the list property is a string, then it represents the name
				-- to be used as the prefix for list items. This is for use with lists
				-- where the first item is a numbered parameter and the
				-- subsequent ones are named, such as 1, pl2, pl3.
				if mw.ustring.match(param.list, "=") then
					patterns["^" .. mw.ustring.gsub(plain(param.list), "=", "(%d+)") .. "$"] = name
				else
					patterns["^" .. plain(param.list) .. "(%d+)$"] = name
				end
			elseif type(name) == "number" then
				-- If the name is a number, then all indexed parameters from
				-- this number onwards go in the list.
				list_from_index = name
			else
				if mw.ustring.match(name, "=") then
					patterns["^" .. mw.ustring.gsub(plain(name), "=", "(%d+)") .. "$"] = mw.ustring.gsub(name, "=", "")
				else
					patterns["^" .. plain(name) .. "(%d+)$"] = mw.ustring.gsub(name, "=", "")
				end
			end
			
			if mw.ustring.match(name, "=") then
				params[mw.ustring.gsub(name, "=", "")] = params[name]
				params[name] = nil
			end
		elseif param.default ~= nil then
			args_new[name] = param.default
		end
	end
	
	-- Process the arguments
	local args_unknown = {}
	
	for name, val in pairs(args) do
		local index = nil
		
		if type(name) == "number" then
			if list_from_index ~= nil and name >= list_from_index then
				index = name - list_from_index + 1
				name = list_from_index
			end
		else
			-- Does this argument name match a pattern?
			for pattern, pname in pairs(patterns) do
				index = mw.ustring.match(name, pattern)
				
				-- It matches, so store the parameter name and the
				-- numeric index extracted from the argument name.
				if index then
					index = tonumber(index)
					name = pname
					break
				end
			end
		end
		
		-- If no index was found, use 1 as the default index.
		-- This makes list parameters like g, g2, g3 put g at index 1.
		index = index or 1
		
		local param = params[name]
		
		-- If the argument is not in the list of parameters, trigger an error.
		-- return_unknown suppresses the error, and stores it in a separate list instead.
		if not param then
			if return_unknown then
				args_unknown[name] = val
			else
				error("The parameter \"" .. name .. "\" is not used by this template.")
			end
		else
			-- Remove leading and trailing whitespace
			val = mw.text.trim(val)
			
			-- Empty string is equivalent to nil unless allow_empty is true.
			if val == "" and not param.allow_empty then
				val = nil
			end
			
			-- Convert to proper type if necessary.
			if param.type == "boolean" then
				val = not (not val or val == "" or val == "0" or val == "no" or val == "n" or val == "false")
			elseif param.type == "number" and val ~= nil then
				val = tonumber(val)
			end
			
			-- Can't use "if val" alone, because val may be a boolean false.
			if val ~= nil then
				-- Mark it as no longer required, as it is present.
				required[name] = nil
				
				-- Store the argument value.
				if param.list then
					-- If the parameter is an alias of another, store it as the original,
					-- but avoid overwriting it; the original takes precedence.
					if not param.alias_of then
						args_new[name][index] = val
						
						-- Store the highest index we find.
						args_new[name].maxindex = math.max(index, args_new[name].maxindex)
					elseif args[param.alias_of] == nil then
						if params[param.alias_of] and params[param.alias_of].list then
							args_new[param.alias_of][index] = val
							
							-- Store the highest index we find.
							args_new[param.alias_of].maxindex = math.max(1, args_new[param.alias_of].maxindex)
						else
							args_new[param.alias_of] = val
						end
					end
				else
					-- If the parameter is an alias of another, store it as the original,
					-- but avoid overwriting it; the original takes precedence.
					if not param.alias_of then
						args_new[name] = val
					elseif args[param.alias_of] == nil then
						if params[param.alias_of] and params[param.alias_of].list then
							args_new[param.alias_of][1] = val
							
							-- Store the highest index we find.
							args_new[param.alias_of].maxindex = math.max(1, args_new[param.alias_of].maxindex)
						else
							args_new[param.alias_of] = val
						end
					end
				end
			end
		end
	end
	
	-- The required table should now be empty.
	-- If any entry remains, trigger an error, unless we're in the template namespace.
	if mw.title.getCurrentTitle().nsText ~= "Template" then
		for name, param in pairs(required) do
			error("The parameter \"" .. name .. "\" is required.")
		end
	end
	
	-- Remove holes in any list parameters if needed.
	for name, val in pairs(args_new) do
		if type(val) == "table" and not params[name].allow_holes then
			args_new[name] = export.remove_holes(val)
		end
	end
	
	if return_unknown then
		return args_new, args_unknown
	else
		return args_new
	end
end

return export