Module:Arguments and Module:Check for unknown parameters: Difference between pages

From Frontierpedia, the Microsoft Agent encyclopedia
(Difference between pages)
en>Mr. Stradivarius
m (Protected Module:Arguments: High-risk Lua module ([Edit=Allow only autoconfirmed users] (indefinite) [Move=Allow only autoconfirmed users] (indefinite)))
 
en>Frietjes
No edit summary
 
Line 1: Line 1:
-- This module provides easy processing of arguments passed to Scribunto from #invoke.
-- This module may be used to compare the arguments passed to the parent
-- It is intended for use by other Lua modules, and should not be called from #invoke directly.
-- with a list of arguments, returning a specified result if an argument is
-- not on the list
local p = {}


local arguments = {}
local function trim(s)
return s:match('^%s*(.-)%s*$')
end


function arguments.getArgs(frame, options)
local function isnotempty(s)
options = type(options) == 'table' and options or {}
return s and trim(s) ~= ''
end


-- Get the arguments from the frame object if available. If the frame object is not available, we are being called
function p.check (frame)
-- from another Lua module or from the debug console, so put the args in a special table so we can differentiate them.
local args = frame.args
local fargs, pargs, luaArgs
local pargs = frame:getParent().args
if frame == mw.getCurrentFrame() then
local ignoreblank = isnotempty(frame.args['ignoreblank'])
fargs = frame.args
local checkpos = isnotempty(frame.args['checkpositional'])
pargs = frame:getParent().args
local knownargs = {}
else
local unknown = frame.args['unknown'] or 'Found _VALUE_, '
luaArgs = type(frame) == 'table' and frame or {}
local preview = frame.args['preview'] or unknown
end


-- Set up the args and metaArgs tables. args will be the one accessed from functions, and metaArgs will hold the actual arguments.
local res = {}
-- The metatable connects the two together.
local regexps = {}
local args, metaArgs, metatable = {}, {}, {}
local comments = {}
setmetatable(args, metatable)
local commentstr = ''
local ispreview = frame:preprocess( "{{REVISIONID}}" ) == "" and 1 or 0


local function tidyVal(key, val)
-- create the list of known args, regular expressions, and the return string
-- Processes a value according to the options given to getArguments. Can trim whitespace and remove blanks.
for k, v in pairs(args) do
-- Keys are not used here, but they can be used by user-generated functions, so defining it here to avoid breakage.
if type(k) == 'number' then
if type(val) == 'string' then
v = trim(v)
if options.trim ~= false then
knownargs[v] = 1
val = mw.text.trim(val)
elseif k:find('^regexp[1-9][0-9]*$') then
end
table.insert(regexps, '^' .. v .. '$')
if options.removeBlanks == false or mw.ustring.find(val, '%S') then
return val
end
else
return val
end
end
end
end
 
if isnotempty(frame.args['preview']) then
-- Use a user-generated function to tidy the values if specified.
preview = '<div class="hatnote" style="color:red"><strong>Warning:</strong> ' .. frame.args['preview'] .. ' (this message is shown only in preview).</div>'
local valueFunc = options.valueFunc
elseif frame.args['preview'] then
if valueFunc then
preview = frame.args['preview']
local valueFuncType = type(valueFunc)
else
if valueFuncType == 'function' then
preview = unknown
tidyVal = valueFunc
end
else
if ispreview == 1 then unknown = preview end
error('type error in option "valueFunc": expected function, got ' .. valueFuncType, 2)
-- adds one result to the output tables
local function addresult(k)
if k == '' then
-- Fix odd bug for | = which gets stripped to the empty string and
-- breaks category links
k = ' '
end
end
local r = unknown:gsub('_VALUE_', k)
table.insert(res, r)
table.insert(comments, '"' .. k .. '"')
end
end


local function mergeArgs(iterator, tables)
-- loop over the parent args, and make sure they are on the list
-- Accepts multiple tables as input and merges their keys and values into one table using the specified iterator.
for k, v in pairs(pargs) do
-- If a value is already present it is not overwritten; tables listed earlier have precendence.
if type(k) == 'string' and knownargs[k] == nil then
for _, t in ipairs(tables) do
local knownflag = false
for key, val in iterator(t) do
for i, regexp in ipairs(regexps) do
if metaArgs[key] == nil then
if mw.ustring.match(k, regexp) then
metaArgs[key] = tidyVal(key, val)
knownflag = true
break
end
end
end
end
end
if (not knownflag) and ispreview or ( (not ignoreblank) and (not isnotempty(v)) ) then
end
k = mw.ustring.gsub(k, '[^%w\-_ ]', '?')
 
addresult(k)
-- 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.frameOnly then
table.insert(argTables, fargs)
elseif options.parentOnly then
table.insert(argTables, pargs)
elseif 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(key, argTable[key])
if argTableVal ~= nil then
metaArgs[key] = argTableVal
return argTableVal
end
end
end
elseif checkpos and
type(k) == 'number' and
knownargs[tostring(k)] == nil and
( not ignoreblank or isnotempty(v) )
then
addresult(k)
end
end
end
end


metatable.__newindex = function (t, key, val)
if #comments > 0 then
if not options.readOnly and (not options.noOverwrite or args[key] == nil) then
commentstr = '<!-- Module:Check for unknown parameters results: ' ..
metaArgs[key] = val
table.concat(comments, ', ') .. '-->'
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
end
 
return args
return table.concat(res) .. commentstr
end
end


return arguments
return p

Revision as of 20:10, 7 February 2016

Documentation for this module may be created at Module:Check for unknown parameters/doc

-- This module may be used to compare the arguments passed to the parent
-- with a list of arguments, returning a specified result if an argument is
-- not on the list
local p = {}

local function trim(s)
	return s:match('^%s*(.-)%s*$')
end

local function isnotempty(s)
	return s and trim(s) ~= ''
end

function p.check (frame)
	local args = frame.args
	local pargs = frame:getParent().args
	local ignoreblank = isnotempty(frame.args['ignoreblank'])
	local checkpos = isnotempty(frame.args['checkpositional'])
	local knownargs = {}
	local unknown = frame.args['unknown'] or 'Found _VALUE_, '
	local preview = frame.args['preview'] or unknown

	local res = {}
	local regexps = {}
	local comments = {}
	local commentstr = ''
	
	local ispreview = frame:preprocess( "{{REVISIONID}}" ) == "" and 1 or 0

	-- create the list of known args, regular expressions, and the return string
	for k, v in pairs(args) do
		if type(k) == 'number' then
			v = trim(v)
			knownargs[v] = 1
		elseif k:find('^regexp[1-9][0-9]*$') then
			table.insert(regexps, '^' .. v .. '$')
		end
	end
	if isnotempty(frame.args['preview']) then 
		preview = '<div class="hatnote" style="color:red"><strong>Warning:</strong> ' .. frame.args['preview'] .. ' (this message is shown only in preview).</div>'
	elseif frame.args['preview'] then
		preview = frame.args['preview']
	else
		preview = unknown
	end
	if ispreview == 1 then unknown = preview end
	
	-- adds one result to the output tables
	local function addresult(k)
		if k == '' then
			-- Fix odd bug for | = which gets stripped to the empty string and
			-- breaks category links
			k = ' '
		end
		local r = unknown:gsub('_VALUE_', k)
		table.insert(res, r)
		table.insert(comments, '"' .. k .. '"')
	end

	-- loop over the parent args, and make sure they are on the list
	for k, v in pairs(pargs) do
		if type(k) == 'string' and knownargs[k] == nil then
			local knownflag = false
			for i, regexp in ipairs(regexps) do
				if mw.ustring.match(k, regexp) then
					knownflag = true
					break
				end
			end
			if (not knownflag) and ispreview or ( (not ignoreblank) and (not isnotempty(v)) )  then
				k = mw.ustring.gsub(k, '[^%w\-_ ]', '?')
				addresult(k)
			end
		elseif checkpos and
			type(k) == 'number' and 
			knownargs[tostring(k)] == nil and
			( not ignoreblank or isnotempty(v) )
		then
			addresult(k)
		end
	end

	if #comments > 0 then
		commentstr = '<!-- Module:Check for unknown parameters results: ' ..
			table.concat(comments, ', ') .. '-->'
	end
	
	return table.concat(res) .. commentstr
end

return p