Módulo:parámetros
La documentación para este módulo puede ser creada en Módulo:parámetros/doc
--versión modificada de https://en.wiktionary.org/wiki/Module:parameters
local export = {}
local no_permitido = "[#\\<\\>\\[\\]\\{\\}\\|=]"
local traza = require("Módulo:traza")
local escapar = require("Módulo:String/escapar")
local tobool = require("Módulo:sí-no")
local function generar_traza(err)
traza("parámetros/"..err)
end
local function buscar_huecos(arr)
local highest = 1
for num, _ in pairs(arr) do
if type(num) == "number" and num > 0 and num < math.huge and math.floor(num) == num then
highest = math.max(highest, num)
end
end
for i = 1, highest-1 do --reviso que no hayan huecos en los valores anteriores al máximo
if ((type(arr[i]) == "table") and buscar_huecos(arr[i])) or arr[i] == nil then
return true
end
end
return false
end
function export.obtener_parametros(args, params)
local args_new = {}
local requerido = {}
local patron_lista = {}
local patron_lista_doble = {}
--Procesamos los parámetros buscando propiedades específicas
for nombre, propiedades in pairs(params) do
if type(nombre) == "string" and string.find(nombre, no_permitido) then
error("Los parámetros no pueden tener los caracteres #<>[]{}|=")
end
if type(nombre) == "number" and (propiedades.lista or propiedades.lista_doble) then
error("Los parámetros posicionales son listas simples. No se puede especificar que sea una lista simple o una lista doble.")
end
local es_alias = false
if propiedades.alias_de then
es_alias = true
if #propiedades > 1 then
error("Un parámetro que es alias de otro no puede tener más propiedades especificadas")
end
if not params[propiedades.alias_de] then
error("El parámetro "..nombre.." es alias de un parámetro que no existe ("..propiedades.alias_de..")")
end
propiedades = params[propiedades.alias_de]
else
if propiedades.requerido then
requerido[nombre] = true --Lo compruebo sólo en parámetros que no son alias para no contar doble
end
end
if propiedades.lista and propiedades.lista_doble then
error("Un parámetro no puede ser \"lista\" y \"lista doble\" a la vez")
end
if propiedades.lista then --si es lista, proceso los items que pueda llegar a tener
args_new[nombre] = {maxindex = 0}
--Si el parámetro tiene nombre quiere decir que es el prefijo de los items
--Ej: si lista = "par", entonces deberíamos esperar par1=algo, par2=algo, par3=algo, ...
if type(nombre) == "string" then
patron_lista[nombre] = "^" .. escapar(nombre) .. "(%d*)$"
elseif not es_alias then
error("Se esperaba que el parámetro solicitado (lista) fuese string")
end
end
if propiedades.lista_doble then
args_new[nombre] = {maxindex = 0}
if type(nombre) == "string" then
patron_lista_doble[nombre] = "^(%d*)" .. escapar(nombre) .. "(%d*)$"
elseif not es_alias then
error("Se esperaba que el parámetro solicitado (lista doble) fuesee string")
end
--En un futuro debería ser así:
--elseif type(nombre) == "number" then
-- error("Las listas dobles no pueden estar indexadas")
--else
-- error("Se esperaba que el parámetro solicitado fuese string")
--end
end
end
if not params[1] then
params[1] = {}
end
-- Proceso los argumentos (lo que recibí de la invocación)
local max_index
--Para debug, se imprimen los argumentos recibidos
--str = ""
--for name, val in pairs(args) do
-- str = str..";"..tostring(name).."-"..tostring(val)
--end
--error(str)
for name, val in pairs(args) do
local index = nil
local index1 = nil
local index2 = nil
local param = nil
local destino = nil
if type(name) == "number" then
if not params[1].alias_de then
index = name
param = params[1]
destino = name
else
----
--- PArche temporal para el módulo pron-graf: la plantilla se llama con parámetros indexados
-- Pero "fone" es lista doble, por lo tanto complicaría las cosas permitir índices superiores a uno
-- Por lo tanto, si se quiere acceder a un índice superior a uno y no existe, entonces forzamos a
-- que sea uno
---
destino = params[1].alias_de
param = params[destino]
index = 1
index1 = 1
index2 = 1
end
else --Sino,
if params[name] then
destino = params[name].alias_de or name
param = params[destino]
index = 1
index1 = 1
index2 = 1
else
-- Sino, si coincide con alguno de los patrones que guardé antes
-- busco el número y lo guardo en el índice y actualizo el nombre del parámetro
for pname, pattern in pairs(patron_lista) do
local _,_,a = string.find(name, pattern)
if a then
index = tonumber(a)
if index > 99 then
error("Desborde de lista")
end
destino = params[pname].alias_de or pname
param = params[destino]
break
end
end
if not destino then
for pname, pattern in pairs(patron_lista_doble) do
local _,_,a,b = string.find(name, pattern)
if a and b then
index1 = tonumber(a == "" and "1" or a)
index2 = tonumber(b == "" and "1" or b)
if index1 > 99 or index2 > 99 then
error("desborde de lista")
end
index = index2
destino = params[pname].alias_de or pname
param = params[destino]
break
end
end
end
end
end
-- Si el argumento no está en la lista de parámetros, se arrojaba un error.
-- Para mí es muy riesgoso hacerlo, sobre todo si queremos implementar estas cosas
-- en páginas viejas en las que no sabemos con qué nos podremos encontrar...
-- Si destino=nil, salteo la iteración
if destino then
--Saco los espacios de más
val = mw.text.trim(val)
if val == "" then
val = nil
end
if param.obs then
generar_traza("obs")
end
-- Convert to proper type if necessary.
if (param.tipo == "binario" or param.tipo == "bool" or param.tipo == "boolean" or param.tipo == "booleano") and val ~= nil then
val = tobool(val, false)
elseif (param.tipo == "num" or param.tipo == "núm" or param.tipo == "number" or param.tipo == "número") and val ~= nil then
val = tonumber(val)
assert(type(val) == "number", "Parámetro \""..name.."\": debe especificar un número")
end
-- Can't use "if val" alone, because val may be a boolean false.
if val ~= nil then
requerido[destino] = nil --sacamos el parámetro de la lista de requeridos
-- Store the argument value.
if param.lista then
if args_new[destino][index] ~= nil then
generar_traza("parámetro repetido")
end
args_new[destino][index] = val
args_new[destino].maxindex = math.max(index, args_new[destino].maxindex)
elseif param.lista_doble then
if args_new[destino][index1] == nil then
args_new[destino][index1] = {}
end
if args_new[destino][index1][index2] ~= nil then
generar_traza("parámetro repetido")
end
args_new[destino][index1][index2] = val
args_new[destino].maxindex = math.max(index1, index2, args_new[destino].maxindex)
else
if args_new[destino] ~= nil then
generar_traza("parámetro repetido")
end
args_new[destino] = val
end
end
end
end
-- Reemplazo los 'nil' por los valores predeterminados
for name, param in pairs(params) do
if param.por_defecto ~= nil then
if type(args_new[name]) == "table" then
if args_new[name][1] == nil then
args_new[name][1] = param.por_defecto
end
elseif args_new[name] == nil then
args_new[name] = param.por_defecto
end
requerido[name] = nil
end
end
--Si quedan valores no nulos en requerido, lanzo error a menos que esté en el espacio de plantillas
if mw.title.getCurrentTitle().namespace ~= 10 then
local lista = {}
for name, param in pairs(requerido) do
table.insert(lista, name)
end
if #lista > 0 then
error('Faltan parámetros requeridos: "' .. mw.text.listToText(lista, '", "', '" y "'), 2)
end
end
-- Chequeo huecos en listas
for name, val in pairs(args_new) do
if type(val) == "table" and buscar_huecos(val) then
generar_traza("lista con huecos")
end
end
return args_new
end
return export