Module:Arguments: Difference between revisions

Jump to navigation Jump to search
(check fargs and pargs before writing new values to args if options.noOverwrite is set)
(use an array to hold argument tables rather than firstArgs and secondArgs variables)
Line 8: Line 8:


-- Get the arguments from the frame object if available. If the frame object is not available, we are being called
-- Get the arguments from the frame object if available. If the frame object is not available, we are being called
-- from another Lua module or from the debug console, so assume arguments are passed directly in.
-- from another Lua module or from the debug console, so put the args in a special table so we can differentiate them.
local fargs, pargs
local fargs, pargs, luaArgs
if frame == mw.getCurrentFrame() then
if frame == mw.getCurrentFrame() then
fargs = frame.args
fargs = frame.args
pargs = frame:getParent().args
pargs = frame:getParent().args
else
else
fargs = type(frame) == 'table' and frame or {}
luaArgs = type(frame) == 'table' and frame or {}
pargs = {}
end
end


-- Set up the args and metaArgs tables. args will be the one accessed from functions, and metaArgs will hold the actual arguments.
-- The metatable connects the two together.
local args, metaArgs, metatable = {}, {}, {}
local args, metaArgs, metatable = {}, {}, {}
setmetatable(args, metatable)
setmetatable(args, metatable)
Line 36: Line 37:
end
end


-- Use a user-generated functions to tidy the values if specified.
-- Use a user-generated function to tidy the values if specified.
local valueFunc = options.valueFunc
local valueFunc = options.valueFunc
if valueFunc then
if valueFunc then
Line 47: Line 48:
end
end


local function mergeArgs(iterator, ...)
local function mergeArgs(iterator, tables)
-- Accepts multiple tables as input and merges their keys and values into one table using the specified iterator.
-- 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 precendence.
-- If a value is already present it is not overwritten; tables listed earlier have precendence.
local tables = {...}
for _, t in ipairs(tables) do
for _, t in ipairs(tables) do
for key, val in iterator(t) do
for key, val in iterator(t) do
Line 60: Line 60:
end
end


-- Set the order of precedence of frame args and parent args.
-- Set the order of precedence of the argument tables. If the variables are nil, nothing will be added to the table,
local firstArgs, secondArgs = fargs, pargs
-- which is how we avoid clashes between the frame/parent args and the Lua args.
local argTables = {}
if options.parentFirst then
if options.parentFirst then
firstArgs, secondArgs = pargs, fargs
table.insert(argTables, pargs)
table.insert(argTables, fargs)
else
table.insert(argTables, fargs)
table.insert(argTables, pargs)
end
end
table.insert(argTables, luaArgs)


--[[
--[[
-- Define metatable behaviour. Arguments are stored in the metaArgs table, and are only fetched from the
-- Define metatable behaviour. Arguments are stored in the metaArgs table, and are only fetched from the
-- fargs and pargs tables once. Also, we keep a record in the metatable of when pairs and ipairs have
-- argument tables once. Also, we keep a record in the metatable of when pairs and ipairs have been called,
-- been called, so we do not run pairs and ipairs on fargs and pargs more than once. We also do not run
-- so we do not run pairs and ipairs on fargs and pargs more than once. We also do not run ipairs on fargs
-- ipairs on fargs and pargs if pairs has already been run, as all the arguments will already have been
-- and pargs if pairs has already been run, as all the arguments will already have been copied over.
-- copied over.
--]]
--]]
metatable.__index = function (t, key)
metatable.__index = function (t, key)
Line 78: Line 83:
return val
return val
else
else
local firstVal = tidyVal(key, firstArgs[key])
for i, argTable in ipairs(argTables) do
if firstVal ~= nil then
local argTableVal = tidyVal(argTable[key])
return firstVal
if argTableVal ~= nil then
else
metaArgs[key] = argTableVal
return tidyVal(key, secondArgs[key])
return argTableVal
end
end
end
end
end
Line 95: Line 101:
metatable.__pairs = function ()
metatable.__pairs = function ()
if not metatable.donePairs then
if not metatable.donePairs then
mergeArgs(pairs, firstArgs, secondArgs)
mergeArgs(pairs, argTables)
metatable.donePairs = true
metatable.donePairs = true
metatable.doneIpairs = true
metatable.doneIpairs = true
Line 104: Line 110:
metatable.__ipairs = function ()
metatable.__ipairs = function ()
if not metatable.doneIpairs then
if not metatable.doneIpairs then
mergeArgs(ipairs, firstArgs, secondArgs)
mergeArgs(ipairs, argTables)
metatable.doneIpairs = true
metatable.doneIpairs = true
end
end

Revision as of 12:03, 9 December 2013

Documentation for this module may be created at Module:Arguments/doc

-- This module provides easy processing of arguments passed to Scribunto from #invoke.
-- It is intended for use by other Lua modules, and should not be called from #invoke directly.

local arguments = {}

function arguments.getArgs(frame, options)
	options = type(options) == 'table' and options or {}

	-- Get the arguments from the frame object if available. If the frame object is not available, we are being called
	-- from another Lua module or from the debug console, so put the args in a special table so we can differentiate them.
	local fargs, pargs, luaArgs
	if frame == mw.getCurrentFrame() then
		fargs = frame.args
		pargs = frame:getParent().args
	else
		luaArgs = type(frame) == 'table' and frame or {}
	end

	-- Set up the args and metaArgs tables. args will be the one accessed from functions, and metaArgs will hold the actual arguments.
	-- The metatable connects the two together.
	local args, metaArgs, metatable = {}, {}, {}
	setmetatable(args, metatable)

	local function tidyVal(key, val)
		-- Processes a value according to the options given to getArguments. Can trim whitespace and remove blanks.
		-- Keys are not used here, but they can be used by user-generated functions, so defining it here to avoid breakage.
		if type(val) == 'string' then
			if options.trim ~= false then
				val = mw.text.trim(val)
			end
			if options.removeBlanks == false or mw.ustring.find(val, '%S') then
				return val
			end
		else
			return val
		end
	end

	-- Use a user-generated function to tidy the values if specified.
	local valueFunc = options.valueFunc
	if valueFunc then
		local valueFuncType = type(valueFunc)
		if valueFuncType == 'function' then
			tidyVal = valueFunc
		else
			error('type error in option "valueFunc": expected function, got ' .. valueFuncType, 2)
		end
	end

	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 precendence.
		for _, t in ipairs(tables) do
			for key, val in iterator(t) do
				if metaArgs[key] == nil then
					metaArgs[key] = tidyVal(key, val)
				end
			end
		end
	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 = {}
	if options.parentFirst then
		table.insert(argTables, pargs)
		table.insert(argTables, fargs)
	else
		table.insert(argTables, fargs)
		table.insert(argTables, pargs)
	end
	table.insert(argTables, luaArgs)

	--[[
	-- Define metatable behaviour. Arguments are stored in the metaArgs table, and are only fetched from the
	-- argument tables once. 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 fargs and pargs more than once. We also do not run ipairs on fargs
	-- and pargs if pairs has already been run, as all the arguments will already have been copied over.
	--]]
	metatable.__index = function (t, key)
		local val = metaArgs[key]
		if val ~= nil then
			return val
		else
			for i, argTable in ipairs(argTables) do
				local argTableVal = tidyVal(argTable[key])
				if argTableVal ~= nil then
					metaArgs[key] = argTableVal
					return argTableVal
				end
			end
		end
	end

	metatable.__newindex = function (t, key, val)
		if not options.readOnly and (not options.noOverwrite or args[key] == nil) then
			metaArgs[key] = val
		end
	end

	metatable.__pairs = function ()
		if not metatable.donePairs then
			mergeArgs(pairs, argTables)
			metatable.donePairs = true
			metatable.doneIpairs = true
		end
		return pairs(metaArgs)
	end

	metatable.__ipairs = function ()
		if not metatable.doneIpairs then
			mergeArgs(ipairs, argTables)
			metatable.doneIpairs = true
		end
		return ipairs(metaArgs)
	end
	
	return args
end

return arguments