Module:Template invoke

From para.wiki
Jump to navigation Jump to search

Allow for easy invocation of utility modules via templates, which is a surprisingly difficult task. Invoke with {{#invoke:template invoke|exec|<module name>}} and it will call that module using the arguments passed to the template. The first argument is the function to invoke, the rest are passed to that function.


local p = {}

function p.exec(frame)
	parent = frame:getParent()
	local mname = frame.args['1'] -- Module name passed via invocation
	local m = require("Module:" .. mname)
	
	local fname = parent.args['1'] -- All else is implicit
	if fname == nil then
		error("No " .. mname .. " method provided")
	end
	
	local fn = m[fname]
	if fn == nil then
		error("No such method " .. fname .. " in Module:" .. mname)
	end
	
	-- Move all the arguments, MW uses string indices
	--  so table.remove doesn't work
	local nargs = {}
	for k, v in pairs(parent.args) do
		local n = tonumber(k)
		if n == nil then
			nargs[k] = v
		elseif n == 1 then
			-- Do nothing, equivalent to nargs[k] = nil
		else
			nargs[(n - 1) .. ""] = v
		end
	end
	-- frame.arg has a metatable which is just a cache without reference to
	--  the underlying table, but it also performs key type coercion so we
	--  need to replicate that
	setmetatable(nargs, {
		__index = function(obj, name)
			return rawget(obj, name .. "")
		end
	})
	parent.args = nargs
	
	return fn(parent)
end

return p