Jump to content

Module:Loops

From SPS Wiki

Loops support module. It is intended for use by other Lua modules, and should not be called from an invocation (#invoke) directly.

This is an experimental module meant to be a drop-in replacement for Extension:Loops for some of its use cases.

See Module:Loops for original source.


local p = {};
local getArgs = require("Module:Arguments").getArgs;

-- Note to dev wiki editors: this function is copied from Module:Example.
-- Changes to this function should be synced with the source.
local function unescape(text)
	if not text:match("UNIQ") then
		return text;
	end
	local unescaped = mw.text.unstripNoWiki(text);
	local text = unescaped:gsub('&lt;', '<')
			:gsub('&gt;', '>')
			:gsub('&quot;', '"')
			-- Taken from Wikipedia's Module:Demo
			:gsub('&#125;%-', '}-')
			:gsub('%-&#123;', '-{')
			:gsub("<//nowiki>", "</nowiki>");
	return text;
end

-- This feature is experimental and therefore undocumented.
function formatConcat(result, args)
	local outputFormat = args['format'] or '';
	local ret;
	if outputFormat == "custom" then
		ret = unescape(args['intro'] or '') .. table.concat(result, unescape(args['delimiter'] or '')) .. unescape(args['outro'] or '');
	else
		ret = table.concat(result, "");
	end
	if args['debug'] then
		mw.log("Before preproces:");
		mw.log(ret);
	end
	return ret;
end

function getMarkup(arg, args)
	local markup = unescape(arg);
	if args['debug'] then
		mw.log("Unescaped string:");
		mw.log(markup);
	end
	return markup;
end
	

function p.loop(frame)
	local args = getArgs(frame);
	local variableName = args[1];
	local startingValue = tonumber(args[2]) or 1;
	local loopNum = tonumber(args[3]) or 0;
	local markup = getMarkup(args[4], args);
	local result = {};
	for i = startingValue, startingValue + loopNum - 1 do
		local s = markup:gsub(variableName, tostring(i));
		table.insert(result, s);
	end
	return frame:getParent():preprocess(formatConcat(result, args));
end

function p.fornumargs(frame)
	local args = getArgs(frame, { removeBlanks = false });
	local keyName = args['key'] or "DNE";
	local valueName = args['value'] or "DNE";
	local markup = getMarkup(args['pattern'], args);
	
	local keys = {};
	for k, v in pairs(args) do
		if type(k) == "number" then
			table.insert(keys, k);
		end
	end
	table.sort(keys);
	
	local result = {};
	for _, key in ipairs(keys) do
		local value = args[key];
		local s = markup:gsub(keyName, key):gsub(valueName, value);
		table.insert(result, s);
	end
	return frame:getParent():preprocess(formatConcat(result, args));
end

function p.forargs(frame)
	local args = getArgs(frame, { removeBlanks = false });
	local prefix = args[1] or "";
	local keyName = args[2] or "DNE";
	local valueName = args[3] or "DNE";
	local markup = getMarkup(args[4], args);
	for i = 1, 4 do
		table.remove(args, i);
	end
	
	local keys = {};
	for k, v in pairs(args) do
		if type(k) == "string" then
			i, j = k:find(prefix);
			if i ~= nil and i == 1 then
				k = k:sub(j + 1)
				if tonumber(k) ~= nil then
					k = tonumber(k)
				end
				table.insert(keys, k);
			end
		end
	end
	table.sort(keys, function(a, b)
	    local ta, tb = type(a), type(b)
	    if ta ~= tb then
	    	-- Number before string
	        return ta == "number"
	    end
	    -- Same type. Compare normally.
	    return a < b
	end);
	
	local result = {};
	for _, key in ipairs(keys) do
		local value = args[prefix .. key];
		local s = markup:gsub(keyName, key):gsub(valueName, value);
		table.insert(result, s);
	end
	return frame:getParent():preprocess(formatConcat(result, args));
end

return p;