| Contenidos de Wikipedia en español bajo licencia CC BY-SA 4.0 ⇔ Mapas de OpenStreetMap bajo licencia ODbL |
Diferencia entre revisiones de «Módulo:Argumentos»
imported>Juan Mayordomo Página creada con «local argumentos = {} function argumentos.obtenerArgumentos(frame) if frame.args[1] then return frame.args end return frame:getParent().args end return argumentos» |
imported>Juan Mayordomo Sin resumen de edición |
||
| Línea 1: | Línea 1: | ||
-- This module provides easy processing of argumentos passed to Scribunto from | |||
-- #invoke. It is intended for use by other Lua modules, and should not be | |||
-- called from #invoke directly. | |||
local libraryUtil = require('libraryUtil') | |||
local checkType = libraryUtil.checkType | |||
local argumentos = {} | local argumentos = {} | ||
function argumentos.obtenerArgumentos(frame) | -- Generate four different tidyVal functions, so that we don't have to check the | ||
if frame.args[1] then | -- options every time we call it. | ||
local function tidyValDefault(key, val) | |||
if type(val) == 'string' then | |||
val = val:match('^%s*(.-)%s*$') | |||
if val == '' then | |||
return nil | |||
else | |||
return val | |||
end | |||
else | |||
return val | |||
end | |||
end | |||
local function tidyValTrimOnly(key, val) | |||
if type(val) == 'string' then | |||
return val:match('^%s*(.-)%s*$') | |||
else | |||
return val | |||
end | |||
end | |||
local function tidyValRemoveBlanksOnly(key, val) | |||
if type(val) == 'string' then | |||
if val:find('%S') then | |||
return val | |||
else | |||
return nil | |||
end | |||
else | |||
return val | |||
end | |||
end | |||
local function tidyValNoChange(key, val) | |||
return val | |||
end | |||
function argumentos.obtenerArgumentos(frame, options) | |||
checkType('obtenerArgumentos', 1, frame, 'table', true) | |||
checkType('obtenerArgumentos', 2, options, 'table', true) | |||
frame = frame or {} | |||
options = options or {} | |||
--[[ | |||
-- Get the argument tables. If we were passed a valid frame object, get the | |||
-- frame argumentos (fargs) and the parent frame argumentos (pargs), depending | |||
-- on the options set and on the parent frame's availability. If we weren't | |||
-- passed a valid frame object, we are being called from another Lua module | |||
-- or from the debug console, so assume that we were passed a table of args | |||
-- directly, and assign it to a new variable (luaArgs). | |||
--]] | |||
local fargs, pargs, luaArgs | |||
if type(frame.args) == 'table' and type(frame.getParent) == 'function' then | |||
if options.wrappers then | |||
--[[ | |||
-- The wrappers option makes Module:argumentos look up argumentos in | |||
-- either the frame argument table or the parent argument table, but | |||
-- not both. This means that users can use either the #invoke syntax | |||
-- or a wrapper template without the loss of performance associated | |||
-- with looking argumentos up in both the frame and the parent frame. | |||
-- Module:argumentos will look up argumentos in the parent frame | |||
-- if it finds the parent frame's title in options.wrapper; | |||
-- otherwise it will look up argumentos in the frame object passed | |||
-- to obtenerArgumentos. | |||
--]] | |||
local parent = frame:getParent() | |||
if not parent then | |||
fargs = frame.args | |||
else | |||
local title = parent:getTitle():gsub('/sandbox$', '') | |||
local found = false | |||
if type(options.wrappers) == 'table' then | |||
for _,v in pairs(options.wrappers) do | |||
if v == title then | |||
found = true | |||
break | |||
end | |||
end | |||
elseif options.wrappers == title then | |||
found = true | |||
end | |||
if found then | |||
pargs = parent.args | |||
else | |||
fargs = frame.args | |||
end | |||
end | |||
else | |||
-- options.wrapper isn't set, so check the other options. | |||
if not options.parentOnly then | |||
fargs = frame.args | |||
end | |||
if not options.frameOnly then | |||
local parent = frame:getParent() | |||
pargs = parent and parent.args or nil | |||
end | |||
if options.parentFirst then | |||
fargs, pargs = pargs, fargs | |||
end | |||
end | |||
else | |||
luaArgs = frame | |||
end | |||
-- Set the order of precedence of the argument tables. If the variables are | |||
-- nil, nothing will be added to the table, which is how we avoid clashes | |||
-- between the frame/parent args and the Lua args. | |||
local argTables = {fargs} | |||
argTables[#argTables + 1] = pargs | |||
argTables[#argTables + 1] = luaArgs | |||
--[[ | |||
-- Generate the tidyVal function. If it has been specified by the user, we | |||
-- use that; if not, we choose one of four functions depending on the | |||
-- options chosen. This is so that we don't have to call the options table | |||
-- every time the function is called. | |||
--]] | |||
local tidyVal = options.valueFunc | |||
if tidyVal then | |||
if type(tidyVal) ~= 'function' then | |||
error( | |||
"bad value assigned to option 'valueFunc'" | |||
.. '(function expected, got ' | |||
.. type(tidyVal) | |||
.. ')', | |||
2 | |||
) | |||
end | |||
elseif options.trim ~= false then | |||
if options.removeBlanks ~= false then | |||
tidyVal = tidyValDefault | |||
else | |||
tidyVal = tidyValTrimOnly | |||
end | |||
else | |||
if options.removeBlanks ~= false then | |||
tidyVal = tidyValRemoveBlanksOnly | |||
else | |||
tidyVal = tidyValNoChange | |||
end | |||
end | |||
--[[ | |||
-- Set up the args, metaArgs and nilArgs tables. args will be the one | |||
-- accessed from functions, and metaArgs will hold the actual argumentos. Nil | |||
-- argumentos are memoized in nilArgs, and the metatable connects all of them | |||
-- together. | |||
--]] | |||
local args, metaArgs, nilArgs, metatable = {}, {}, {}, {} | |||
setmetatable(args, metatable) | |||
local function mergeArgs(iterator, tables) | |||
--[[ | |||
-- Accepts multiple tables as input and merges their keys and values | |||
-- into one table using the specified iterator. If a value is already | |||
-- present it is not overwritten; tables listed earlier have precedence. | |||
-- We are also memoizing nil values, but those values can be | |||
-- overwritten. | |||
--]] | |||
for _, t in ipairs(tables) do | |||
for key, val in iterator(t) do | |||
if metaArgs[key] == nil then | |||
local tidiedVal = tidyVal(key, val) | |||
if tidiedVal == nil then | |||
nilArgs[key] = true | |||
else | |||
metaArgs[key] = tidiedVal | |||
end | |||
end | |||
end | |||
end | |||
end | end | ||
return | --[[ | ||
-- Define metatable behaviour. argumentos are memoized in the metaArgs table, | |||
-- and are only fetched from the argument tables once. Fetching argumentos | |||
-- from the argument tables is the most resource-intensive step in this | |||
-- module, so we try and avoid it where possible. For this reason, nil | |||
-- argumentos are also memoized, in the nilArgs table. Also, we keep a record | |||
-- in the metatable of when pairs and ipairs have been called, so we do not | |||
-- run pairs and ipairs on the argument tables more than once. We also do | |||
-- not run ipairs on fargs and pargs if pairs has already been run, as all | |||
-- the argumentos will already have been copied over. | |||
--]] | |||
metatable.__index = function (t, key) | |||
--[[ | |||
-- Fetches an argument when the args table is indexed. First we check | |||
-- to see if the value is memoized, and if not we try and fetch it from | |||
-- the argument tables. When we check memoization, we need to check | |||
-- metaArgs before nilArgs, as both can be non-nil at the same time. | |||
-- If the argument is not present in metaArgs, we also check whether | |||
-- pairs has been run yet. If pairs has already been run, we return nil. | |||
-- This is because all the argumentos will have already been copied into | |||
-- metaArgs by the mergeArgs function, meaning that any other argumentos | |||
-- must be nil. | |||
--]] | |||
local val = metaArgs[key] | |||
if val ~= nil then | |||
return val | |||
elseif metatable.donePairs or nilArgs[key] then | |||
return nil | |||
end | |||
for _, argTable in ipairs(argTables) do | |||
local argTableVal = tidyVal(key, argTable[key]) | |||
if argTableVal == nil then | |||
nilArgs[key] = true | |||
else | |||
metaArgs[key] = argTableVal | |||
return argTableVal | |||
end | |||
end | |||
return nil | |||
end | |||
metatable.__newindex = function (t, key, val) | |||
-- This function is called when a module tries to add a new value to the | |||
-- args table, or tries to change an existing value. | |||
if options.readOnly then | |||
error( | |||
'could not write to argument table key "' | |||
.. tostring(key) | |||
.. '"; the table is read-only', | |||
2 | |||
) | |||
elseif options.noOverwrite and args[key] ~= nil then | |||
error( | |||
'could not write to argument table key "' | |||
.. tostring(key) | |||
.. '"; overwriting existing argumentos is not permitted', | |||
2 | |||
) | |||
elseif val == nil then | |||
--[[ | |||
-- If the argument is to be overwritten with nil, we need to erase | |||
-- the value in metaArgs, so that __index, __pairs and __ipairs do | |||
-- not use a previous existing value, if present; and we also need | |||
-- to memoize the nil in nilArgs, so that the value isn't looked | |||
-- up in the argument tables if it is accessed again. | |||
--]] | |||
metaArgs[key] = nil | |||
nilArgs[key] = true | |||
else | |||
metaArgs[key] = val | |||
end | |||
end | |||
metatable.__pairs = function () | |||
-- Called when pairs is run on the args table. | |||
if not metatable.donePairs then | |||
mergeArgs(pairs, argTables) | |||
metatable.donePairs = true | |||
metatable.doneIpairs = true | |||
end | |||
return pairs(metaArgs) | |||
end | |||
metatable.__ipairs = function () | |||
-- Called when ipairs is run on the args table. | |||
if not metatable.doneIpairs then | |||
mergeArgs(ipairs, argTables) | |||
metatable.doneIpairs = true | |||
end | |||
return ipairs(metaArgs) | |||
end | |||
return args | |||
end | end | ||
return argumentos | return argumentos | ||
Revisión del 18:01 15 jun 2014
Este módulo provee un procesamiento fácil a los argumentos que pasan de #invoke. Es un metamódulo, pensado para ser usado por otros módulos, y no debería ser llamado directamente desde #invoke. Entre sus características se incluyen:
- Eliminar espacios en blanco al principio y final de los valores (no implementado todavía)
- Eliminar parámetros vacíos (no implementado todavía)
- Los argumentos pueden ser pasados por el marco actual y el marco padre a la vez (no implementado todavía)
- Los argumentos pueden ser pasados por otro módulo Lua o desde la consola de depuración.
- La mayoría de las características pueden ser personalizadas.
Uso básico
Para empezar, se debe cargar el módulo. Contiene una función, llamada obtenerArgumentos.
local dameArgs = require('Módulo:Argumentos').obtenerArgumentos
En el escenario más básico, se puede usar obtenerArgumentos dentro de la función principal (usualmente main).
La variable args es una tabla que contiene los argumentos de #invoke.
local dameArgs = require('Módulo:Argumentos').obtenerArgumentos
local p = {}
function p.main(marco)
local args = dameArgs(marco)
-- El código principal del módulo vas acá
end
return p
Sin embargo, se recomienda usar una función solo para procesar los argumentos de #invoke. Esto significa que si se llama al módulo desde otro módulo Lua, no es necesario tener un objeto marco disponible, mejorando el rendimiento.
local dameArgs = require('Módulo:Argumentos').obtenerArgumentos
local p = {}
function p.main(marco)
local args = dameArgs(marco)
return p._main(args)
end
function p._main(args)
-- El código principal del módulo vas acá
end
return p
Si se quiere múltiples funciones que usen los argumentos, y que también sean accesibles desde #invoke, puede usarse una función envolvente.
local dameArgs = require('Módulo:Argumentos').obtenerArgumentos
local function hazFuncInvoke(fn)
return function (marco)
local args = dameArgs(marco)
return p[fn](args)
end
end
local p = {}
p.func1 = hazFuncInvoke('_func1')
function p._func1(args)
-- El código de la primera función va acá
end
p.func2 = hazFuncInvoke('_func2')
function p._func2(args)
-- El código de la segunda función va acá
end
return p
Opciones
Las siguientes opciones están disponible, y son explicadas en las secciones de abajo.
local args = dameArgs(marco, {
limpiarEspacios = false,
removerVacios = false,
fnValores = function (clave, valor)
-- Código para procesar un argumento
end,
soloMarco = true,
soloPadre = true,
padrePrimero = true,
envolventes = {
'Plantilla:Una plantilla envolvente',
'Plantilla:Otra plantilla envolvente'
},
soloLectura = true,
noSobreescribir = true
})
Eliminar espacios y vacios
local args = dameArgs(marco, {
limpiarEspacios = false,
removerVacios = false
})
Personalización del formato de los argumentos
Algunas veces se desea remover algunos argumentos en blanco pero no otros, o tal vez poner todos los argumentos posicionales en minúscula. Para hacer cosas como estas, se usa la opción fnValores. La entrada a esta opción debe ser una función que toma dos parámetros, clave and value, y devuelve un valor sencillo. Este valor es lo que se obtiene cuando acceda al campo clave en la tabla de args
Ejemplo 1: esta función preserva los espacio en blanco para el primer argumento posicional, pero los elimina de los otros argumentos, y los elimina si quedan vacíos:
local args = dameArgs(marco, {
fnValores = function (clave, valor)
if 1 == clave then
return valor
elseif valor then
valor = mw.text.trim(valor) -- Elimina los espacios al comienzo y final del valor
if '' ~= valor then -- Si el valor no quedó vacío
return valor -- Lo devuelve
end
end
return nil -- En otros casos, devuelve el valor nulo (es decir, no incluir el valor)
end
})
Ejemplo 2: esta función elimina los argumentos vacíos y convierte todos los argumentos a minúsculas, pero no elimina los espacios del comienzo y final de los parámetros posicionales.
local args = dameArgs(marco, {
fnValores = function (clave, valor)
if not valor then
return nil
end
value = mw.ustring.lower(valor)
if mw.ustring.find(valor, '%S') then
return valor
end
return nil
end
})
Nota: las funciones de arriba fallarán si se les pasa una entrada que no sea de tipo string or nil. Esto puede suceder si se usa la función dametArgs en la función principal del módulo, y esa función es llamada desde otro módulo Lua. En este caso, es necesario comprobar el tipo de la entrada. Esto no es un problema cuando se usa una función específicamente para obtener los argumentos de #invoke; por ejemplo, cuando se usa una función para ese caso (usualmente p.main) y otra ser usada por otros módulos (usualmente p._main).
También, es importante destacar que la función fnValores es llamada aproximadamente cada vez que se pide un argumento de la tabla args. Por lo tanto, si se quiere mejorar el rendimiento debería verificarse no estar haciando nada ineficiente en ese código.
Marcos y marcos padre
Los argumentos de la tabla args pueden ser pasados desde el marco actual o del marco padre a la vez. Para enteder qué significa esto, es más fácil dar un ejemplo. Digamos que tenemos un módulo llamado Módulo:EjemploArgs, qu eimprime los primeros dos parámetros posicionales que se le pasen:
Envolventes
La opción envolventes se usa para indicar un número limitado de plantillas que funcionan como envolentes; es decir, cuyo único propósito es llamar al módulo. Si el módulo detecta que es llamado desde una de estas plantillas, solo comprobará los argumentos del marco padre; de lo contrario solo lo hará con el marco pasado a dameArgs. Esto le permite al módulo ser llamado tanto desde #invoke como desde una envolvente sin la pérdida de rendimiento asociada a tener que comprobar ambos marcos (el actual y el padre) por cada argumento.
Escribiendo en la tabla args
Etiquetas ref
Limitaciones conocidas
-- This module provides easy processing of argumentos passed to Scribunto from
-- #invoke. It is intended for use by other Lua modules, and should not be
-- called from #invoke directly.
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local argumentos = {}
-- Generate four different tidyVal functions, so that we don't have to check the
-- options every time we call it.
local function tidyValDefault(key, val)
if type(val) == 'string' then
val = val:match('^%s*(.-)%s*$')
if val == '' then
return nil
else
return val
end
else
return val
end
end
local function tidyValTrimOnly(key, val)
if type(val) == 'string' then
return val:match('^%s*(.-)%s*$')
else
return val
end
end
local function tidyValRemoveBlanksOnly(key, val)
if type(val) == 'string' then
if val:find('%S') then
return val
else
return nil
end
else
return val
end
end
local function tidyValNoChange(key, val)
return val
end
function argumentos.obtenerArgumentos(frame, options)
checkType('obtenerArgumentos', 1, frame, 'table', true)
checkType('obtenerArgumentos', 2, options, 'table', true)
frame = frame or {}
options = options or {}
--[[
-- Get the argument tables. If we were passed a valid frame object, get the
-- frame argumentos (fargs) and the parent frame argumentos (pargs), depending
-- on the options set and on the parent frame's availability. If we weren't
-- passed a valid frame object, we are being called from another Lua module
-- or from the debug console, so assume that we were passed a table of args
-- directly, and assign it to a new variable (luaArgs).
--]]
local fargs, pargs, luaArgs
if type(frame.args) == 'table' and type(frame.getParent) == 'function' then
if options.wrappers then
--[[
-- The wrappers option makes Module:argumentos look up argumentos in
-- either the frame argument table or the parent argument table, but
-- not both. This means that users can use either the #invoke syntax
-- or a wrapper template without the loss of performance associated
-- with looking argumentos up in both the frame and the parent frame.
-- Module:argumentos will look up argumentos in the parent frame
-- if it finds the parent frame's title in options.wrapper;
-- otherwise it will look up argumentos in the frame object passed
-- to obtenerArgumentos.
--]]
local parent = frame:getParent()
if not parent then
fargs = frame.args
else
local title = parent:getTitle():gsub('/sandbox$', '')
local found = false
if type(options.wrappers) == 'table' then
for _,v in pairs(options.wrappers) do
if v == title then
found = true
break
end
end
elseif options.wrappers == title then
found = true
end
if found then
pargs = parent.args
else
fargs = frame.args
end
end
else
-- options.wrapper isn't set, so check the other options.
if not options.parentOnly then
fargs = frame.args
end
if not options.frameOnly then
local parent = frame:getParent()
pargs = parent and parent.args or nil
end
if options.parentFirst then
fargs, pargs = pargs, fargs
end
end
else
luaArgs = frame
end
-- Set the order of precedence of the argument tables. If the variables are
-- nil, nothing will be added to the table, which is how we avoid clashes
-- between the frame/parent args and the Lua args.
local argTables = {fargs}
argTables[#argTables + 1] = pargs
argTables[#argTables + 1] = luaArgs
--[[
-- Generate the tidyVal function. If it has been specified by the user, we
-- use that; if not, we choose one of four functions depending on the
-- options chosen. This is so that we don't have to call the options table
-- every time the function is called.
--]]
local tidyVal = options.valueFunc
if tidyVal then
if type(tidyVal) ~= 'function' then
error(
"bad value assigned to option 'valueFunc'"
.. '(function expected, got '
.. type(tidyVal)
.. ')',
2
)
end
elseif options.trim ~= false then
if options.removeBlanks ~= false then
tidyVal = tidyValDefault
else
tidyVal = tidyValTrimOnly
end
else
if options.removeBlanks ~= false then
tidyVal = tidyValRemoveBlanksOnly
else
tidyVal = tidyValNoChange
end
end
--[[
-- Set up the args, metaArgs and nilArgs tables. args will be the one
-- accessed from functions, and metaArgs will hold the actual argumentos. Nil
-- argumentos are memoized in nilArgs, and the metatable connects all of them
-- together.
--]]
local args, metaArgs, nilArgs, metatable = {}, {}, {}, {}
setmetatable(args, metatable)
local function mergeArgs(iterator, tables)
--[[
-- Accepts multiple tables as input and merges their keys and values
-- into one table using the specified iterator. If a value is already
-- present it is not overwritten; tables listed earlier have precedence.
-- We are also memoizing nil values, but those values can be
-- overwritten.
--]]
for _, t in ipairs(tables) do
for key, val in iterator(t) do
if metaArgs[key] == nil then
local tidiedVal = tidyVal(key, val)
if tidiedVal == nil then
nilArgs[key] = true
else
metaArgs[key] = tidiedVal
end
end
end
end
end
--[[
-- Define metatable behaviour. argumentos are memoized in the metaArgs table,
-- and are only fetched from the argument tables once. Fetching argumentos
-- from the argument tables is the most resource-intensive step in this
-- module, so we try and avoid it where possible. For this reason, nil
-- argumentos are also memoized, in the nilArgs table. Also, we keep a record
-- in the metatable of when pairs and ipairs have been called, so we do not
-- run pairs and ipairs on the argument tables more than once. We also do
-- not run ipairs on fargs and pargs if pairs has already been run, as all
-- the argumentos will already have been copied over.
--]]
metatable.__index = function (t, key)
--[[
-- Fetches an argument when the args table is indexed. First we check
-- to see if the value is memoized, and if not we try and fetch it from
-- the argument tables. When we check memoization, we need to check
-- metaArgs before nilArgs, as both can be non-nil at the same time.
-- If the argument is not present in metaArgs, we also check whether
-- pairs has been run yet. If pairs has already been run, we return nil.
-- This is because all the argumentos will have already been copied into
-- metaArgs by the mergeArgs function, meaning that any other argumentos
-- must be nil.
--]]
local val = metaArgs[key]
if val ~= nil then
return val
elseif metatable.donePairs or nilArgs[key] then
return nil
end
for _, argTable in ipairs(argTables) do
local argTableVal = tidyVal(key, argTable[key])
if argTableVal == nil then
nilArgs[key] = true
else
metaArgs[key] = argTableVal
return argTableVal
end
end
return nil
end
metatable.__newindex = function (t, key, val)
-- This function is called when a module tries to add a new value to the
-- args table, or tries to change an existing value.
if options.readOnly then
error(
'could not write to argument table key "'
.. tostring(key)
.. '"; the table is read-only',
2
)
elseif options.noOverwrite and args[key] ~= nil then
error(
'could not write to argument table key "'
.. tostring(key)
.. '"; overwriting existing argumentos is not permitted',
2
)
elseif val == nil then
--[[
-- If the argument is to be overwritten with nil, we need to erase
-- the value in metaArgs, so that __index, __pairs and __ipairs do
-- not use a previous existing value, if present; and we also need
-- to memoize the nil in nilArgs, so that the value isn't looked
-- up in the argument tables if it is accessed again.
--]]
metaArgs[key] = nil
nilArgs[key] = true
else
metaArgs[key] = val
end
end
metatable.__pairs = function ()
-- Called when pairs is run on the args table.
if not metatable.donePairs then
mergeArgs(pairs, argTables)
metatable.donePairs = true
metatable.doneIpairs = true
end
return pairs(metaArgs)
end
metatable.__ipairs = function ()
-- Called when ipairs is run on the args table.
if not metatable.doneIpairs then
mergeArgs(ipairs, argTables)
metatable.doneIpairs = true
end
return ipairs(metaArgs)
end
return args
end
return argumentos