Anonymous
×
Create a new article
Write your page title here:
We currently have 15 articles on TwistedFates Database. Type your article name above or click on one of the titles below and start writing!



    TwistedFates Database
    15Articles

    Module:Loops: Difference between revisions

    m Protected "Module:Loops": Highly visible page or template: 5137 transclusions ([Edit=Allow only autoconfirmed users] (indefinite) [Move=Allow only autoconfirmed users] (indefinite))
     
    m 1 revision imported
     
    (No difference)

    Latest revision as of 02:10, 17 December 2023

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

    -- <nowiki>
    --------------------------------------------------------------------------------
    -- Lua module implementing features similar to [[mw:Extension:Loops]].
    --
    -- @module lööps
    -- @alias  loops
    -- @author [[User:ExE Boss]]
    -- @require [[Module:TableTools]]
    --------------------------------------------------------------------------------
    
    local libraryUtil = require("libraryUtil");
    local tableTools  = require("Module:TableTools");
    
    local checkType = libraryUtil.checkType;
    local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg;
    
    local ustring = mw.ustring;
    local loops = {};
    
    local function userError(message)
    	return '<strong class="error">' .. message .. '</strong>';
    end
    
    local function escapePattern(pattern)
    	return ustring.gsub(pattern, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1")
    end
    
    local function isFrame(frame)
    	return type(frame) == "table"
    		and type(frame.args) == "table"
    		and type(frame.getParent) == "function";
    end
    
    --------------------------------------------------------------------------------
    -- Preprocesses text escaped using the [[mw:Extension:DynamicPageList3]] method.
    --
    -- @function loops._preprocess
    -- @param {Frame} frame
    -- @param {string} msg
    -- @return {string}
    --------------------------------------------------------------------------------
    local function preprocess(frame, msg)
    	msg = ustring.gsub(msg, "«", "<");
    	msg = ustring.gsub(msg, "»", ">");
    	msg = ustring.gsub(msg, "¦", "|");
    	msg = ustring.gsub(msg, "²{", "{{");
    	msg = ustring.gsub(msg, "}²", "}}");
    	return frame:preprocess(msg);
    end
    loops._preprocess = preprocess;
    
    --------------------------------------------------------------------------------
    -- @param {Frame|table} args
    -- @return {number}
    -- @usage {{#invoke:Loops|numArgs}}
    --------------------------------------------------------------------------------
    function loops.numArgs(frame)
    	checkType("numArgs", 1, frame, "table");
    	local args;
    	if (isFrame(frame)) then
    		args = (frame:getParent() or frame).args;
    	else
    		args = frame;
    	end
    	return tableTools.length(args);
    end
    
    --------------------------------------------------------------------------------
    -- @param {Frame} args
    -- @return {string}
    --
    -- @usage {{#invoke:Loops|forNumArgs|template string}}
    -- @usage {{#invoke:Loops|forNumArgs|value pattern|template string}}
    -- @usage {{#invoke:Loops|forNumArgs|key pattern|value pattern|template string}}
    -- @usage
    --  {{#invoke:Loops|forNumArgs
    --  | template = template string
    --  }}
    -- @usage
    --  {{#invoke:Loops|forNumArgs
    --  | value    = value pattern
    --  | template = template string
    --  }}
    -- @usage
    --  {{#invoke:Loops|forNumArgs
    --  | key      = key pattern
    --  | template = template string
    --  }}
    -- @usage
    --  {{#invoke:Loops|forNumArgs
    --  | key      = key pattern
    --  | value    = value pattern
    --  | template = template string
    --  }}
    --------------------------------------------------------------------------------
    function loops.forNumArgs(frame)
    	local frameArgs, parentArgs;
    	checkType("numArgs", 1, frame, "table");
    	if (isFrame(frame)) then
    		frameArgs  = frame.args;
    		parentArgs = frame:getParent().args;
    	else
    		return error("forNumArgs only supports invocation");
    	end
    
    	local kPattern, vPattern, template;
    	local frameNumArgs = tableTools.length(frameArgs);
    	if (frameNumArgs >= 3) then
    		kPattern = frameArgs[1];
    		vPattern = frameArgs[2];
    		template = frameArgs[3];
    	elseif (frameNumArgs >= 2) then
    		vPattern = frameArgs[1];
    		template = frameArgs[2];
    	else
    		template = frameArgs[1];
    	end
    
    	kPattern = frameArgs.key      or kPattern;
    	vPattern = frameArgs.value    or vPattern;
    	template = frameArgs.template or template;
    
    	checkTypeForNamedArg("forNumArgs", "key",      kPattern, "string", true);
    	checkTypeForNamedArg("forNumArgs", "value",    vPattern, "string", true);
    	checkTypeForNamedArg("forNumArgs", "template", template, "string", true);
    
    	if (template == nil) then
    		return userError("Must supply template parameter to forNumArgs");
    	end
    
    	vPattern = vPattern or "$1";
    	if (kPattern ~= nil) then
    		if (#kPattern > 0) then
    			if (kPattern == vPattern) then
    				return userError("key pattern must be different from value pattern");
    			end
    			kPattern = escapePattern(kPattern);
    		else
    			kPattern = nil;
    		end
    	elseif (vPattern ~= "$2") then
    		kPattern = "%$2";
    	end
    	if (#vPattern == 0) then
    		vPattern = nil;
    	else
    		vPattern = escapePattern(vPattern);
    	end
    
    	local result = {};
    	local v, msg;
    	for k = 1, tableTools.length(parentArgs) do
    		v = parentArgs[k];
    		if (v ~= nil) then
    			msg = template;
    			if (kPattern) then
    				msg = ustring.gsub(msg, kPattern, (ustring.gsub(tostring(k), "%%", "%%%%")));
    			end
    			if (vPattern) then
    				msg = ustring.gsub(msg, vPattern, (ustring.gsub(tostring(v), "%%", "%%%%")));
    			end
    			result[#result + 1] = preprocess(frame, msg);
    		end
    	end
    
    	return table.concat(result);
    end
    
    --------------------------------------------------------------------------------
    -- Parses and prints wikitext markup N times
    --
    -- @param {Frame} args
    -- @param[opt] {string} args[1] Pattern. `$1` by default
    -- @param {number} args[2] Starting value
    -- @param {number} args[3] Number loops to be performed
    -- @param {string} args[4] Wikitext markup
    -- @return {string}
    --------------------------------------------------------------------------------
    function loops.loop(frame)
    	local frameArgs
    	checkType("numArgs", 1, frame, "table")
    	if (isFrame(frame)) then
    		frameArgs = (frame:getParent() or frame).args
    	else
    		return userError("loop only supports invocation")
    	end
    	
    	local pattern = frame.args[1] or "$1"
    	
    	local start = tonumber(frame.args[2])
    	local loopsPerformed = tonumber(frame.args[3])
    	-- {{#loop}} supports negative values for loopsPerformed
    	local fin = loopsPerformed < 0 and start + (loopsPerformed + 1) or (start - 1) + loopsPerformed
    	local step = loopsPerformed < 0 and -1 or 1
    	
    	local template = frame.args[4]
    	
    	local result = {}
    	local msg
    	for i = start, fin, step do
    		msg = ustring.gsub(template, pattern, i)
    		result[#result + 1] = msg
    	end
    	
    	return preprocess(frame, table.concat(result)) -- preprocess at the end
    end
    
    return loops;