Module:Loops
Jump to navigation
Jump to search
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;