Módulo:Testes/Gkiyoshinishimoto/Arguments

Origem: Wikipédia, a enciclopédia livre.
Documentação do módulo[ver] [editar] [histórico] [purgar]

Este módulo fornece processamento fácil de argumentos passados a partir de #invoke. Ele é um metamódulo, destinado ao uso por outros módulos, e não deve ser chamado diretamente a partir de #invoke (para um módulo que pode ser invocado diretamente por predefinições, você pode querer dar uma olhada em {{#invoke:Testes/Gkiyoshinishimoto/Params}}). Suas características incluem:

  • Corte fácil de argumentos e remoção de argumentos em branco.
  • Os argumentos podem ser passados pelo quadro atual e pelo quadro parental ao mesmo tempo. (Mais detalhes abaixo.)
  • Os argumentos podem ser passados diretamente a partir de outro módulo Lua ou a partur do console de depuração.
  • A maioria dos recursos pode ser personalizada.

Uso básico[editar código-fonte]

Primeiro, você precisa carregar o módulo. Ele contém uma função chamada getArgs.

local getArgs = require('Módulo:Testes/Gkiyoshinishimoto/Arguments').getArgs

No cenário mais básico, você pode usar "getArgs" dentro de sua função principal. A variável args é uma tabela contendo os argumentos a partir de "#invoke". (Veja abaixo para detalhes.)

local getArgs = require('Módulo:Testes/Gkiyoshinishimoto/Arguments').getArgs
local p = {}

function p.main(frame)
	local args = getArgs(frame)
	-- O código do módulo principal vai aqui.
end

return p

Prática recomendada[editar código-fonte]

No entanto, a prática recomendada é usar uma função apenas para processar argumentos a partir de #invoke. Isso significa que se alguém chamar seu módulo a partir de outro módulo Lua, você não precisa ter um objeto frame disponível, o que melhora o desempenho.

local getArgs = require('Módulo:Testes/Gkiyoshinishimoto/Arguments').getArgs
local p = {}

function p.main(frame)
	local args = getArgs(frame)
	return p._main(args)
end

function p._main(args)
	-- O código do módulo principal vai aqui.
end

return p

A maneira como isso é chamado a partir de uma predefinição é {{#invoke:Testes/Gkiyoshinishimoto/Exemplo|main}} (opcionalmente com alguns parâmetros como {{#invoke: Testes/Gkiyoshinishimoto/Exemplo|main|arg1=valor1|arg2=valor2}}), e a maneira como isso é chamado a partir de um módulo é require('Módulo:Testes/Gkiyoshinishimoto/Exemplo')._main ({arg1 = 'valor1', arg2 = valor2, 'arg3 espaçado' = 'valor3'}). O que este segundo faz é construir uma tabela com os argumentos nela, então dá essa tabela para a função p._main(args), que a usa nativamente.

Múltiplas funções[editar código-fonte]

Se você deseja que várias funções usem os argumentos e também deseja que eles sejam acessíveis a partir de "#invoke", você pode usar uma função "wrapper".

local getArgs = require('Módulo:Testes/Gkiyoshinishimoto/Arguments').getArgs

local p = {}

local function makeInvokeFunc(funcName)
	return function (frame)
		local args = getArgs(frame)
		return p[funcName](args)
	end
end

p.func1 = makeInvokeFunc('_func1')

function p._func1(args)
	-- O código para a primeira função vai aqui.
end

p.func2 = makeInvokeFunc('_func2')

function p._func2(args)
	-- O código para a segunda função vai aqui.
end

return p

Opções[editar código-fonte]

As seguintes opções estão disponíveis. Elas são explicadas nas seções abaixo.

local args = getArgs(frame, {
	trim = false,
	removeBlanks = false,
	valueFunc = function (key, value)
		-- Código para processar um argumento
	end,
	frameOnly = true,
	parentOnly = true,
	parentFirst = true,
	wrappers = {
		'Predefinição:Uma predefinição wrapper',
		'Predefinição:Outra predefinição wrapper'
	},
	readOnly = true,
	noOverwrite = true
})

Aparar e remover espaços em branco[editar código-fonte]

Os argumentos em branco geralmente atrapalham os codificadores novos na conversão de predefinições MediaWiki para Lua. Na sintaxe de predefinições, sequências[a] em branco e sequências[a] consistindo apenas em espaços em branco são consideradas falsas. No entanto, em Lua, sequências[a] em branco e sequências[a] consistindo em espaços em branco são consideradas verdadeiras. Isso significa que, se você não prestar atenção a esses argumentos ao escrever seus módulos Lua, poderá tratar algo como verdadeiro que na verdade deveria ser tratado como falso. Para evitar isso, por padrão, este módulo remove todos os argumentos em branco.

Da mesma forma, os espaços em branco podem causar problemas ao lidar com argumentos posicionais. Embora o espaço em branco seja cortado para argumentos nomeados provenientes de "#invoke", ele é preservado para argumentos posicionais. Na maioria das vezes, esse espaço em branco adicional não é desejado, portanto, esse módulo o elimina por padrão.

No entanto, às vezes você deseja usar argumentos em branco como entrada e, às vezes, deseja manter espaços em branco adicionais. Isso pode ser necessário para converter algumas predefinições exatamente como foram escritas. Se quiser fazer isso, você pode definir os argumentos trim e removeBlanks como false.

local args = getArgs(frame, {
	trim = false,
	removeBlanks = false
})

Formatação personalizada de argumentos[editar código-fonte]

Às vezes, você deseja remover alguns argumentos em branco, mas não outros, ou talvez queira colocar todos os argumentos posicionais em letras minúsculas. Para fazer coisas assim, você pode usar a opção valueFunc. A entrada para esta opção deve ser uma função que usa dois parâmetros, key e value, e retorna um único valor. Este valor é o que você obterá ao acessar o campo key na tabela args.


Exemplo 1: esta função preserva o espaço em branco para o valor do primeiro argumento posicional, mas corta o valor de todos os outros argumentos e remove todos os outros argumentos em branco.

local args = getArgs(frame, {
	valueFunc = function (key, value)
		if key == 1 then
			return value
		elseif value then
			value = mw.text.trim(value)
			if value ~= '' then
				return value
			end
		end
		return nil
	end
})

Exemplo 2: esta função remove os argumentos em branco e converte todos os valores dos argumentos em letras minúsculas, mas não elimina os espaços em branco dos parâmetros posicionais.

local args = getArgs(frame, {
	valueFunc = function (key, value)
		if not value then
			return nil
		end
		value = mw.ustring.lower(value)
		if mw.ustring.find(value, '%S') then
			return value
		end
		return nil
	end
})

Observação: as funções acima falharão se forem passadas entradas que não sejam do tipo string ou nil. Este pode ser o caso se você usar a função getArgs na função principal do seu módulo e essa função for chamada por outro módulo Lua. Neste caso, você precisará verificar o tipo de sua entrada. Isso não é um problema se você estiver usando uma função especialmente para argumentos a partir de "#invoke" (ou seja, você tem as funções p.main e p._main ou algo semelhante).

Exemplos 1 e 2 com verificação de tipo

Exemplo 1:

local args = getArgs(frame, {
	valueFunc = function (key, value)
		if key == 1 then
			return value
		elseif type(value) == 'string' then
			value = mw.text.trim(value)
			if value ~= '' then
				return value
			else
				return nil
			end
		else
			return value
		end
	end
})

Exemplo 2:

local args = getArgs(frame, {
	valueFunc = function (key, value)
		if type(value) == 'string' then
			value = mw.ustring.lower(value)
			if mw.ustring.find(value, '%S') then
				return value
			else
				return nil
			end
		else
			return value
		end
	end
})

Além disso, observe que a função valueFunc é chamada mais ou menos toda vez que um argumento é solicitado da tabela args, portanto, se você se preocupa com o desempenho, certifique-se de não está fazendo nada ineficiente com seu código.

Quadros e quadros parentais[editar código-fonte]

Os argumentos na tabela args podem ser passados do quadro atual ou de seu quadro parental ao mesmo tempo. Para entender o que isso significa, é mais fácil dar um exemplo. Digamos que temos um módulo chamado Módulo:Testes/Gkiyoshinishimoto/ExampleArgs. Este módulo imprime os dois primeiros argumentos posicionais que são passados.

Código de Módulo:Testes/Gkiyoshinishimoto/ExampleArgs
local getArgs = require('Módulo:Testes/Gkiyoshinishimoto/Arguments').getArgs
local p = {}

function p.main(frame)
	local args = getArgs(frame)
	return p._main(args)
end

function p._main(args)
	local first = args[1] or ''
	local second = args[2] or ''
	return first .. ' ' .. second
end

return p

Módulo:Testes/Gkiyoshinishimoto/ExampleArgs é então chamado por Predefinição:Teste/Gkiyoshinishimoto/ExampleArgs, que contém o código {{#invoke:Testes/Gkiyoshinishimoto/ExampleArgs|main|firstInvokeArg}}. Isso produz o resultado "firstInvokeArg"

Agora, se fôssemos chamar Predefinição:Teste/Gkiyoshinishimoto/ExampleArgs, aconteceria o seguinte:

Código Resultado
{{Teste/Gkiyoshinishimoto/ExampleArgs}} firstInvokeArg
{{Teste/Gkiyoshinishimoto/ExampleArgs|firstTemplateArg}} firstInvokeArg
{{Teste/Gkiyoshinishimoto/ExampleArgs|firstTemplateArg|secondTemplateArg}} firstInvokeArg secondTemplateArg

Existem três opções que você pode definir para alterar esse comportamento: frameOnly, parentOnly e parentFirst. Se você definir frameOnly, somente os argumentos passados do quadro atual serão aceitos; se você definir parentOnly, somente os argumentos passados do quadro parental serão aceitos; e se você definir parentFirst, os argumentos serão passados dos quadros atual e parental, mas o quadro parental terá prioridade sobre o quadro atual. Aqui estão os resultados em termos de Predefinição:Teste/Gkiyoshinishimoto/ExampleArgs:

frameOnly
Código Resultado
{{Teste/Gkiyoshinishimoto/ExampleArgs}} firstInvokeArg
{{Teste/Gkiyoshinishimoto/ExampleArgs|firstTemplateArg}} firstInvokeArg
{{Teste/Gkiyoshinishimoto/ExampleArgs|firstTemplateArg|secondTemplateArg}} firstInvokeArg
parentOnly
Código Resultado
{{Teste/Gkiyoshinishimoto/ExampleArgs}}
{{ExampleArgs|firstTemplateArg}} firstTemplateArg
{{Teste/Gkiyoshinishimoto/ExampleArgs|firstTemplateArg|secondTemplateArg}} firstTemplateArg secondTemplateArg
parentFirst
Código Resultado
{{Teste/Gkiyoshinishimoto/ExampleArgs}} firstInvokeArg
{{Teste/Gkiyoshinishimoto/ExampleArgs|firstTemplateArg}} firstTemplateArg
{{Teste/Gkiyoshinishimoto/ExampleArgs|firstTemplateArg|secondTemplateArg}} firstTemplateArg secondTemplateArg

Notas:

  1. Se você definir as opções frameOnly e parentOnly, o módulo não buscará nenhum argumento a partir de #invoke. Provavelmente não é isso que você deseja.
  2. Em algumas situações, um quadro parental pode não estar disponível, por exemplo: se "getArgs" for passado para o quadro parental em vez do quadro atual. Nesse caso, apenas os argumentos do quadro serão usados (a menos que "parentOnly" seja definido, caso em que nenhum argumento será usado) e as opções parentFirst e frameOnly não terão efeito .

Wrappers[editar código-fonte]

A opção "wrappers" é utilizada para especificar um número limitado de predefinições como "predefinições wrapper", ou seja, predefinições cujo único objetivo é chamar um módulo. Se o módulo detectar que está sendo chamado de uma predefinição "wrapper", ele verificará apenas os argumentos no quadro parental; caso não, ele verificará apenas os argumentos no quadro passado para "getArgs". Isso permite que os módulos sejam chamados por "#invoke" ou por meio de uma predefinição "wrapper" sem a perda de desempenho associada à verificação do quadro e do quadro parental para cada pesquisa de argumento.

Por exemplo, o único conteúdo de Predefinição:Teste/Gkiyoshinishimoto/Side box (excluindo o conteúdo em marcações[b] <noinclude>...</noinclude>) é {{#invoke:Testes/Gkiyoshinishimoto/Side box|main}}. Não faz sentido verificar os argumentos passados diretamente para a instrução "#invoke" para esta predefinição, pois nenhum argumento será especificado lá. Podemos evitar a verificação de argumentos passados para "#invoke" usando a opção "parentOnly", mas se fizermos isso, "#invoke" também não funcionará em outras páginas. Se for esse o caso, o |text=Algum texto no código {{#invoke:Testes/Gkiyoshinishimoto/Side box|main|text=Algum texto}} seria completamente ignorado, independentemente da página a partir da qual foi usado. Usando a opção wrappers para especificar 'Predefinição:Teste/Gkiyoshinishimoto/Side box' como um wrapper, podemos fazer com que {{#invoke:Testes/Gkiyoshinishimoto/Side box|main|text=Algum texto}} funcione na maioria das páginas, embora ainda não exija que o módulo verifique os argumentos na própria página Predefinição:Teste/Gkiyoshinishimoto/Side box.

Os wrappers podem ser especificados como uma sequência[a] ou como um arranjo de sequências[a].

local args = getArgs(frame, {
	wrappers = 'Predefinição:Predefinição wrapper'
})


local args = getArgs(frame, {
	wrappers = {
		'Predefinição:Predefinição wrapper 1',
		'Predefinição:Predefinição wrapper 2',
		-- Qualquer número de predefinições "wrapper" pode ser adicionado aqui.
	}
})

Notas:

  1. O módulo detectará automaticamente se está sendo chamado a partir da subpágina "/Testes" de uma predefinição "wrapper", portanto, não há necessidade de especificar páginas de testes explicitamente.
  2. A opção "wrappers" altera efetivamente o padrão das opções "frameOnly" e "parentOnly". Se, por exemplo, "parentOnly" for definida explicitamente como 0 com "wrappers" definida, as chamadas por meio de predefinições wrappers resultariam no carregamento de argumentos parentais e de quadro, embora as chamadas que não sejam por meio de predefinições wrappers resultariam apenas em argumentos de quadro sendo carregados.
  3. Se a opção "wrappers" estiver definida e nenhum quadro parental estiver disponível, o módulo sempre obterá os argumentos do quadro passado para getArgs.

Escrevendo na tabela "args"[editar código-fonte]

Algumas vezes pode ser útil escrever novos valores na tabela "args". Isso é possível com as configurações padrões deste módulo. (No entanto, tenha em mente que geralmente é melhor estilo de codificação criar uma nova tabela com seus novos valores e copiar argumentos da tabela "args" conforme necessário.)

args.foo = 'algum valor'

É possível alterar esse comportamento com as opções readOnly e noOverwrite. Se readOnly for definida, não será possível gravar nenhum valor na tabela "args". Se noOverwrite for definida, é possível adicionar novos valores à tabela, mas não é possível adicionar um valor se ele substituir quaisquer argumentos passados de "#invoke".

Marcações "ref"[editar código-fonte]

Este módulo usa metatabelas para buscar argumentos a partir de "#invoke". Isso permite acesso aos argumentos do quadro e aos argumentos do quadro parental sem usar a função pairs(). Isso pode ajudar se seu módulo pode ter passado marcações{{Nre|nome=tag}{<ref>...</ref> como entrada.

Assim que as marcações[b] <ref>...</ref> são acessadas a partir de Lua, elas são processadas pelo software MediaWiki e a referência aparecerá na lista de referências na parte inferior do artigo. Se o seu módulo continuar omitindo a marcação[b] de referência da saída, você terminará com uma referência fantasma – uma referência que aparece na lista de referência, mas sem nenhum número vinculado a ela. Este tem sido um problema com módulos que usam pairs() para detectar se devem usar os argumentos do quadro ou do quadro parental, já que esses módulos processam automaticamente todos os argumentos disponíveis.

Este módulo resolve este problema permitindo o acesso aos argumentos do quadro e do quadro parental, enquanto ainda busca esses argumentos apenas quando necessário. No entanto, o problema ainda ocorrerá se você usar pairs(args) em outro lugar em seu módulo.

Limitações conhecidas[editar código-fonte]

O uso de metatabelas também tem suas desvantagens. A maioria das ferramentas normais de tabelas Lua não funcionará corretamente na tabela "args", incluindo o operador #, a função next() e as funções na biblioteca de tabelas. Se o uso delas for importante para o seu módulo, você deve usar sua própria função de processamento de argumentos em vez deste módulo.

Notas[editar código-fonte]

  1. a b c d e f do inglês strings
  2. a b c do inglês tag

Ver também[editar código-fonte]

-- Este módulo fornece processamento fácil de argumentos passados para a Scribunto a partir de
-- #invoke. Ele destina-se ao uso por outros módulos Lua e não deve ser 
-- chamado diretamente  a partir de #invoke.

local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType

local arguments = {}

-- Gera quatro funções "tidyVal" diferentes, para que não tenhamos que verificar as
-- opções toda vez que a chamamos.

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

local function matchesTitle(given, title)
	local tp = type( given )
	return (tp == 'string' or tp == 'number') and mw.title.new( given ).prefixedText == title
end

local translate_mt = { __index = function(t, k) return k end }

function arguments.getArgs(frame, options)
	checkType('getArgs', 1, frame, 'table', true)
	checkType('getArgs', 2, options, 'table', true)
	frame = frame or {}
	options = options or {}

	--[[
	-- Define a tradução de argumentos.
	--]]
	options.translate = options.translate or {}
	if getmetatable(options.translate) == nil then
		setmetatable(options.translate, translate_mt)
	end
	if options.backtranslate == nil then
		options.backtranslate = {}
		for k,v in pairs(options.translate) do
			options.backtranslate[v] = k
		end
	end
	if options.backtranslate and getmetatable(options.backtranslate) == nil then
		setmetatable(options.backtranslate, {
			__index = function(t, k)
				if options.translate[k] ~= k then
					return nil
				else
					return k
				end
			end
		})
	end

	--[[
	-- Obtém as tabelas de argumentos. Se nos foi passado um objeto de quadro válido, obtemos os 
	-- argumentos do quadro (fargs) e os argumentos do quadro parental (pargs), dependendo
	-- das opções definidas e da disponibilidade do quadro pai. Se não nos foi
	-- passado um objeto de quadro válido, estamos sendo chamados de outro módulo Lua
	-- ou do console de depuração, então assume que nos foi passado uma tabela de argumentos
	-- diretamente e a atribui a uma nova variável ("luaArgs").
	--]]
	local fargs, pargs, luaArgs
	if type(frame.args) == 'table' and type(frame.getParent) == 'function' then
		if options.wrappers then
			--[[
			-- A opção "wrappers" faz o Módulo:Testes/Gkiyoshinishimoto/Arguments procurar argumentos na 
			-- tabela de argumentos do quadro ou na tabela de argumentos parental, mas
			-- mas não em ambos. Isso significa que os usuários podem usar a sintaxe "#invoke"
			-- ou uma predefinição "wrapper" sem a perda de desempenho associada
			-- à procura de argumentos no quadro e no quadro parental.
			-- O Módulo:Testes/Gkiyoshinishimoto/Arguments procurará argumentos no quadro parental
			-- se encontrar o título do quadro parental em "options.wrapper";
			-- caso não, ele procurará argumentos no objeto de quadro passado
			-- para "getArgs".
			--]]
			local parent = frame:getParent()
			if not parent then
				fargs = frame.args
			else
				local title = parent:getTitle():gsub('/Testes$', '')
				local found = false
				if matchesTitle(options.wrappers, title) then
					found = true
				elseif type(options.wrappers) == 'table' then
					for _,v in pairs(options.wrappers) do
						if matchesTitle(v, title) then
							found = true
							break
						end
					end
				end

				-- Nós testamos "false" especificamente aqui para que "nil" (o padrão) aja como "true".
				if found or options.frameOnly == false then
					pargs = parent.args
				end
				if not found or options.parentOnly == false then
					fargs = frame.args
				end
			end
		else
			-- "options.wrapper" não está definido, portanto verifica as outras opções.
			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
		end
		if options.parentFirst then
			fargs, pargs = pargs, fargs
		end
	else
		luaArgs = frame
	end

	-- Define a ordem de precedência das tabelas de argumentos. Se as variáveis forem
	-- "nil", nada será adicionado à tabela, que é como evitamos confrontos
	-- entre os argumentos do quadro/parental e os argumentos Lua.
	local argTables = {fargs}
	argTables[#argTables + 1] = pargs
	argTables[#argTables + 1] = luaArgs

	--[[
	-- Gere a função "tidyVal". Se tiver sido especificado pelo usuário, nós
	-- usamos isso; caso contrário, escolhemos uma das quatro funções dependendo das
	-- opções escolhidas. Isso é para que não tenhamos que chamar a tabela de opções
	-- toda vez que a função for chamada.
	--]]
	local tidyVal = options.valueFunc
	if tidyVal then
		if type(tidyVal) ~= 'function' then
			error(
				"valor inválido atribuído à opção 'valueFunc'"
					.. '(função esperada, obteve '
					.. 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

	--[[
	-- Define as tabelas “args”, “metaArgs” e “nilArgs”. "args" será a única
	-- acessada a partir de funções e "metaArgs" manterá os argumentos reais. Os argumentos 
	-- nulos são memorizados em "nilArgs" e a metatabela conecta todos eles
	-- juntos.
	--]]
	local args, metaArgs, nilArgs, metatable = {}, {}, {}, {}
	setmetatable(args, metatable)

	local function mergeArgs(tables)
		--[[
		-- Aceita várias tabelas como entrada e mescla suas chaves e valores
		-- em uma tabela. Se um valor já estiver presente, ele não será substituído;
		-- as tabelas listadas anteriormente têm precedência. Também estamos memorizando valores nulos,
		--  que podem ser sobrescritos se forem "s" ('soft').
		--]]
		for _, t in ipairs(tables) do
			for key, val in pairs(t) do
				if metaArgs[key] == nil and nilArgs[key] ~= 'h' then
					local tidiedVal = tidyVal(key, val)
					if tidiedVal == nil then
						nilArgs[key] = 's'
					else
						metaArgs[key] = tidiedVal
					end
				end
			end
		end
	end

	--[[
	-- Define o comportamento da metatabela. Os argumentos são memorizados na tabela "metaArgs",
	-- e são buscados apenas uma vez nas tabelas de argumentos. Obter os argumentos
	-- a partir das tabelas de argumentos é o passo mais intensiva em recursos neste
	-- módulo, então tentamos evitá-lo sempre que possível. Por este motivo, os argumentos nulos
	-- também são memorizados, na tabela "nilArgs". Além disso, mantemos um registro
	-- na metatabela de quando "pairs" e "ipairs" foram chamadas, então nós não 
	-- executamos "pairs" e "ipairs" nas tabelas de argumentos mais de uma vez. Nós também  
	-- não executamos "ipairs" em "fargs" e "pargs" se "pairs" já tiver sido executada, pois todos
	-- os argumentos já terão sido copiados.
	--]]

	metatable.__index = function (t, key)
		--[[
		-- Busca um argumento quando a tabela "args" é indexada. Primeiro nós verificamos
		-- para ver se o valor está memorizado e, caso não, tentamos buscá-lo a partir 
		-- das tabelas de argumentos. Quando nós verificamos a memorização, nós precisamos verificar
		-- "metaArgs" antes de "nilArgs", pois ambas podem não ser nulas ('nil') ao mesmo tempo.
		-- Se o argumento não estiver presente em "metaArgs", nós também verificamos se
		-- "pairs" já foi executada. Se "pairs" já tiver sido executada, retornamos "nil" (nulo).
		-- Isso ocorre porque todos os argumentos já terão sido copiados para
		-- "metaArgs" pela função "mergeArgs", significando que quaisquer outros argumentos
		-- devem ser "nil" (nulos).
		--]]
		if type(key) == 'string' then
			key = options.translate[key]
		end
		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
				metaArgs[key] = argTableVal
				return argTableVal
			end
		end
		nilArgs[key] = 'h'
		return nil
	end

	metatable.__newindex = function (t, key, val)
		-- Esta função é chamada quando um módulo tenta adicionar um novo valor à 
		-- tabela "args" ou tenta alterar um valor existente.
		if type(key) == 'string' then
			key = options.translate[key]
		end
		if options.readOnly then
			error(
				'não foi possível gravar na chave da tabela de argumentos "'
					.. tostring(key)
					.. '"; a tabela é somente leitura',
				2
			)
		elseif options.noOverwrite and args[key] ~= nil then
			error(
				'não foi possível gravar na chave da tabela de argumentos "'
					.. tostring(key)
					.. '"; sobrescrever argumentos existentes não é permitido',
				2
			)
		elseif val == nil then
			--[[
			-- Se o argumento for substituído por "nil", nós precisamos apagar
			-- o valor em "metaArgs", para que "__index", "__pairs" e "__ipairs" 
			-- não usem um valor existente anterior, se presente; e nós também precisamos
			-- memorizar "nil" (nulo) em "nilArgs", para que o valor não seja procurado
			-- nas tabelas de argumentos se for acessado novamente.
			--]]
			metaArgs[key] = nil
			nilArgs[key] = 'h'
		else
			metaArgs[key] = val
		end
	end

	local function translatenext(invariant)
		local k, v = next(invariant.t, invariant.k)
		invariant.k = k
		if k == nil then
			return nil
		elseif type(k) ~= 'string' or not options.backtranslate then
			return k, v
		else
			local backtranslate = options.backtranslate[k]
			if backtranslate == nil then
				-- Ignora este. Esta é uma chamada final, então isso não causará estouro de pilha
				return translatenext(invariant)
			else
				return backtranslate, v
			end
		end
	end

	metatable.__pairs = function ()
		-- Chamada quando "pairs" é executada na tabela "args".
		if not metatable.donePairs then
			mergeArgs(argTables)
			metatable.donePairs = true
		end
		return translatenext, { t = metaArgs }
	end

	local function inext(t, i)
		-- Isso usa nosso metamétodo "__index"
		local v = t[i + 1]
		if v ~= nil then
			return i + 1, v
		end
	end

	metatable.__ipairs = function (t)
		-- Chamada quando "ipairs" é executada na tabela "args".
		return inext, t, 0
	end

	return args
end

return arguments