https://en.wikipedia.org/w/index.php?action=history&feed=atom&title=Module%3AArguments_with_aliases Module:Arguments with aliases - Revision history 2025-05-26T02:13:07Z Revision history for this page on the wiki MediaWiki 1.45.0-wmf.2 https://en.wikipedia.org/w/index.php?title=Module:Arguments_with_aliases&diff=1259641346&oldid=prev حبيشان: forkd from module:Arguments to work with aliases 2024-11-26T07:37:49Z <p>forkd from <a href="/wiki/Module:Arguments" title="Module:Arguments">module:Arguments</a> to work with aliases</p> <p><b>New page</b></p><div>-- This module is forked from [[:en:Module:Arguments]] to support aliases<br /> -- main idea of aliases is from [[:en:Citaion/CS1]]<br /> <br /> -- This module provides easy processing of arguments passed to Scribunto from<br /> -- #invoke. It is intended for use by other Lua modules, and should not be<br /> -- called from #invoke directly.<br /> <br /> local libraryUtil = require(&#039;libraryUtil&#039;)<br /> local checkType = libraryUtil.checkType<br /> <br /> local arguments = {}<br /> <br /> -- Generate four different tidyVal functions, so that we don&#039;t have to check the<br /> -- options every time we call it.<br /> <br /> local function tidyValDefault(key, val)<br /> if type(val) == &#039;string&#039; then<br /> val = mw.ustring.match(val, &#039;^%s*(.-)%s*$&#039;)<br /> if val == &#039;&#039; then<br /> return nil<br /> else<br /> return val<br /> end<br /> else<br /> return val<br /> end<br /> end<br /> <br /> local function tidyValTrimOnly(key, val)<br /> if type(val) == &#039;string&#039; then<br /> return mw.ustring.match(val, &#039;^%s*(.-)%s*$&#039;)<br /> else<br /> return val<br /> end<br /> end<br /> <br /> local function tidyValRemoveBlanksOnly(key, val)<br /> if type(val) == &#039;string&#039; then<br /> if mw.ustring.find(val, &#039;%S&#039;) then<br /> return val<br /> else<br /> return nil<br /> end<br /> else<br /> return val<br /> end<br /> end<br /> <br /> local function tidyValNoChange(key, val)<br /> return val<br /> end<br /> <br /> local function matchesTitle(given, title)<br /> local tp = type( given )<br /> return (tp == &#039;string&#039; or tp == &#039;number&#039;) and mw.title.new( given ).prefixedText == title<br /> end<br /> <br /> local function tableClone(t)<br /> checkType(&#039;tableClone&#039;, 1, t, &#039;table&#039;)<br /> if getmetatable(t) and getmetatable(t).mw_loadData then<br /> local ret = {}<br /> for k, v in pairs(t) do<br /> ret[k] = v<br /> end<br /> return ret<br /> else<br /> return t<br /> end<br /> end<br /> <br /> function arguments.getArgs(frame, options)<br /> checkType(&#039;getArgs&#039;, 1, frame, &#039;table&#039;, true)<br /> checkType(&#039;getArgs&#039;, 2, options, &#039;table&#039;, true)<br /> frame = frame or {}<br /> options = options or {}<br /> local aliases = options.aliases and tableClone(options.aliases) or {}<br /> local numbered_aliases = options.numbered_aliases and tableClone(options.numbered_aliases) or nil<br /> local backtranslate = options.backtranslate and tableClone(options.backtranslate) or nil<br /> local numbered_backtranslate = options.numbered_backtranslate and tableClone(options.numbered_backtranslate) or nil<br /> local origin = {}<br /> <br /> --[[<br /> -- Set up argument translation.<br /> --]]<br /> local translate_mt = { __index = function(t, k)<br /> local order_num = mw.ustring.match(k,&#039;%d+&#039;)<br /> if order_num and numbered_aliases then<br /> local plist = numbered_aliases[mw.ustring.gsub(k,order_num,&quot;#&quot;)]<br /> if plist then<br /> local ret<br /> if type(plist) == &#039;table&#039; then<br /> ret = {}<br /> for _,v in ipairs(plist) do<br /> local numarg = mw.ustring.gsub(v, &#039;#&#039;, order_num )<br /> table.insert(ret, numarg)<br /> end<br /> else<br /> ret= mw.ustring.gsub(plist, &#039;#&#039;, order_num )<br /> end<br /> return ret<br /> end<br /> end<br /> return k<br /> end<br /> }<br /> <br /> if getmetatable(aliases) == nil then<br /> setmetatable(aliases, translate_mt)<br /> end<br /> <br /> if backtranslate == nil then<br /> backtranslate = {}<br /> for k, list in pairs(aliases) do<br /> if type(list) == &#039;table&#039; then<br /> for _, v in pairs(list) do<br /> backtranslate[v] = k<br /> end<br /> else<br /> backtranslate[list] = k<br /> end<br /> end<br /> end<br /> <br /> if numbered_aliases and numbered_backtranslate == nil then<br /> numbered_backtranslate = {}<br /> for k, list in pairs(numbered_aliases) do<br /> if type(list) == &#039;table&#039; then<br /> for _, v in pairs(list) do<br /> numbered_backtranslate[v] = k<br /> end<br /> else<br /> numbered_backtranslate[list] = k<br /> end<br /> end<br /> end<br /> <br /> if backtranslate and getmetatable(backtranslate) == nil then<br /> setmetatable(backtranslate, {<br /> __index = function(t, k)<br /> local order_num = mw.ustring.match(k,&#039;%d+&#039;)<br /> if order_num and numbered_backtranslate then<br /> local plist = numbered_backtranslate[mw.ustring.gsub(k,order_num,&quot;#&quot;)]<br /> if plist then<br /> return mw.ustring.gsub(plist, &#039;#&#039;, order_num )<br /> end<br /> end<br /> return k<br /> end<br /> })<br /> end<br /> <br /> --[[<br /> -- Get the argument tables. If we were passed a valid frame object, get the<br /> -- frame arguments (fargs) and the parent frame arguments (pargs), depending<br /> -- on the options set and on the parent frame&#039;s availability. If we weren&#039;t<br /> -- passed a valid frame object, we are being called from another Lua module<br /> -- or from the debug console, so assume that we were passed a table of args<br /> -- directly, and assign it to a new variable (luaArgs).<br /> --]]<br /> local fargs, pargs, luaArgs<br /> if type(frame.args) == &#039;table&#039; and type(frame.getParent) == &#039;function&#039; then<br /> if options.wrappers then<br /> --[[<br /> -- The wrappers option makes Module:Arguments look up arguments in<br /> -- either the frame argument table or the parent argument table, but<br /> -- not both. This means that users can use either the #invoke syntax<br /> -- or a wrapper template without the loss of performance associated<br /> -- with looking arguments up in both the frame and the parent frame.<br /> -- Module:Arguments will look up arguments in the parent frame<br /> -- if it finds the parent frame&#039;s title in options.wrapper;<br /> -- otherwise it will look up arguments in the frame object passed<br /> -- to getArgs.<br /> --]]<br /> local parent = frame:getParent()<br /> if not parent then<br /> fargs = frame.args<br /> else<br /> local title = mw.ustring.gsub(mw.ustring.gsub(parent:getTitle(), &#039;/sandbox$&#039;, &#039;&#039;), &#039;/ملعب$&#039;, &#039;&#039;)<br /> local found = false<br /> if matchesTitle(options.wrappers, title) then<br /> found = true<br /> elseif type(options.wrappers) == &#039;table&#039; then<br /> for _,v in pairs(options.wrappers) do<br /> if matchesTitle(v, title) then<br /> found = true<br /> break<br /> end<br /> end<br /> end<br /> <br /> -- We test for false specifically here so that nil (the default) acts like true.<br /> if found or options.frameOnly == false then<br /> pargs = parent.args<br /> end<br /> if not found or options.parentOnly == false then<br /> fargs = frame.args<br /> end<br /> end<br /> else<br /> -- options.wrapper isn&#039;t set, so check the other options.<br /> if not options.parentOnly then<br /> fargs = frame.args<br /> end<br /> if not options.frameOnly then<br /> local parent = frame:getParent()<br /> pargs = parent and parent.args or nil<br /> end<br /> end<br /> if options.parentFirst then<br /> fargs, pargs = pargs, fargs<br /> end<br /> else<br /> luaArgs = frame<br /> end<br /> <br /> -- Set the order of precedence of the argument tables. If the variables are<br /> -- nil, nothing will be added to the table, which is how we avoid clashes<br /> -- between the frame/parent args and the Lua args.<br /> local argTables = {fargs}<br /> argTables[#argTables + 1] = pargs<br /> argTables[#argTables + 1] = luaArgs<br /> <br /> --[[<br /> -- Generate the tidyVal function. If it has been specified by the user, we<br /> -- use that; if not, we choose one of four functions depending on the<br /> -- options chosen. This is so that we don&#039;t have to call the options table<br /> -- every time the function is called.<br /> --]]<br /> local tidyVal = options.valueFunc<br /> if tidyVal then<br /> if type(tidyVal) ~= &#039;function&#039; then<br /> error(<br /> &quot;bad value assigned to option &#039;valueFunc&#039;&quot;<br /> .. &#039;(function expected, got &#039;<br /> .. type(tidyVal)<br /> .. &#039;)&#039;,<br /> 2<br /> )<br /> end<br /> elseif options.trim ~= false then<br /> if options.removeBlanks ~= false then<br /> tidyVal = tidyValDefault<br /> else<br /> tidyVal = tidyValTrimOnly<br /> end<br /> else<br /> if options.removeBlanks ~= false then<br /> tidyVal = tidyValRemoveBlanksOnly<br /> else<br /> tidyVal = tidyValNoChange<br /> end<br /> end<br /> <br /> --[[<br /> -- Set up the args, metaArgs and nilArgs tables. args will be the one<br /> -- accessed from functions, and metaArgs will hold the actual arguments. Nil<br /> -- arguments are memoized in nilArgs, and the metatable connects all of them<br /> -- together.<br /> --]]<br /> local args, metaArgs, nilArgs, metatable = {}, {}, {}, {}<br /> setmetatable(args, metatable)<br /> <br /> local function mergeArgs(tables)<br /> --[[<br /> -- Accepts multiple tables as input and merges their keys and values<br /> -- into one table. If a value is already present it is not overwritten;<br /> -- tables listed earlier have precedence. We are also memoizing nil<br /> -- values, which can be overwritten if they are &#039;s&#039; (soft).<br /> --]]<br /> for _, t in ipairs(tables) do<br /> for akey, val in pairs(t) do<br /> local key = backtranslate[akey]<br /> if metaArgs[key] == nil and nilArgs[key] ~= &#039;h&#039; then<br /> local tidiedVal = tidyVal(key, val)<br /> if tidiedVal == nil then<br /> nilArgs[key] = &#039;s&#039;<br /> else<br /> metaArgs[key] = tidiedVal<br /> origin[key] = akey<br /> end<br /> end<br /> end<br /> end<br /> end<br /> <br /> --[[<br /> -- Define metatable behaviour. Arguments are memoized in the metaArgs table,<br /> -- and are only fetched from the argument tables once. Fetching arguments<br /> -- from the argument tables is the most resource-intensive step in this<br /> -- module, so we try and avoid it where possible. For this reason, nil<br /> -- arguments are also memoized, in the nilArgs table. Also, we keep a record<br /> -- in the metatable of when pairs and ipairs have been called, so we do not<br /> -- run pairs and ipairs on the argument tables more than once. We also do<br /> -- not run ipairs on fargs and pargs if pairs has already been run, as all<br /> -- the arguments will already have been copied over.<br /> --]]<br /> <br /> metatable.__index = function (t, key)<br /> --[[<br /> -- Fetches an argument when the args table is indexed. First we check<br /> -- to see if the value is memoized, and if not we try and fetch it from<br /> -- the argument tables. When we check memoization, we need to check<br /> -- metaArgs before nilArgs, as both can be non-nil at the same time.<br /> -- If the argument is not present in metaArgs, we also check whether<br /> -- pairs has been run yet. If pairs has already been run, we return nil.<br /> -- This is because all the arguments will have already been copied into<br /> -- metaArgs by the mergeArgs function, meaning that any other arguments<br /> -- must be nil.<br /> --]]<br /> local val = metaArgs[key]<br /> if val ~= nil then<br /> return val<br /> elseif metatable.donePairs or nilArgs[key] then<br /> return nil<br /> end<br /> <br /> local list = (type(key) == &quot;number&quot;) and key or aliases[key];<br /> for _,argTable in ipairs(argTables) do<br /> if type( list ) == &#039;table&#039; then<br /> for _, alias_key in pairs( list ) do<br /> local argTableVal = tidyVal(key, argTable[alias_key])<br /> if argTableVal ~= nil then<br /> metaArgs[key] = argTableVal<br /> origin[key] = alias_key<br /> return argTableVal<br /> end<br /> end<br /> elseif list ~= nil then<br /> local argTableVal = tidyVal(key, argTable[list])<br /> if argTableVal ~= nil then<br /> metaArgs[key] = argTableVal<br /> origin[key] = list<br /> return argTableVal<br /> end<br /> end<br /> <br /> if argTable[key] then<br /> local argTableVal = tidyVal(key, argTable[key])<br /> if argTableVal ~= nil then<br /> metaArgs[key] = argTableVal<br /> origin[key] = key<br /> return argTableVal<br /> end<br /> end<br /> end<br /> <br /> nilArgs[key] = &#039;h&#039;<br /> return nil<br /> end<br /> <br /> metatable.__newindex = function (t, key, val)<br /> -- This function is called when a module tries to add a new value to the<br /> -- args table, or tries to change an existing value.<br /> if options.readOnly then<br /> error(<br /> &#039;could not write to argument table key &quot;&#039;<br /> .. tostring(key)<br /> .. &#039;&quot;; the table is read-only&#039;,<br /> 2<br /> )<br /> elseif options.noOverwrite and args[key] ~= nil then<br /> error(<br /> &#039;could not write to argument table key &quot;&#039;<br /> .. tostring(key)<br /> .. &#039;&quot;; overwriting existing arguments is not permitted&#039;,<br /> 2<br /> )<br /> elseif val == nil then<br /> --[[<br /> -- If the argument is to be overwritten with nil, we need to erase<br /> -- the value in metaArgs, so that __index, __pairs and __ipairs do<br /> -- not use a previous existing value, if present; and we also need<br /> -- to memoize the nil in nilArgs, so that the value isn&#039;t looked<br /> -- up in the argument tables if it is accessed again.<br /> --]]<br /> metaArgs[key] = nil<br /> nilArgs[key] = &#039;h&#039;<br /> else<br /> metaArgs[key] = val<br /> end<br /> end<br /> <br /> args._ORIGIN = function ( self, k )<br /> -- تعطي الوسيط الأصلي الذي كتبه المستخدم مهمة في رسائل الخطأ<br /> local dummy = self[k]; -- force the variable to be loaded.<br /> return origin[k];<br /> end<br /> <br /> local function translatenext(invariant)<br /> local k, v = next(invariant.t, invariant.k)<br /> invariant.k = k<br /> if k == nil then<br /> return nil<br /> elseif k == &#039;_ORIGIN&#039; then<br /> return translatenext(invariant)<br /> elseif type(k) ~= &#039;string&#039; or not backtranslate then<br /> return k, v<br /> else<br /> local k_backtranslate = backtranslate[k]<br /> if k_backtranslate == nil then<br /> -- Skip this one. This is a tail call, so this won&#039;t cause stack overflow<br /> return translatenext(invariant)<br /> else<br /> return k_backtranslate, v<br /> end<br /> end<br /> end<br /> <br /> metatable.__pairs = function ()<br /> -- Called when pairs is run on the args table.<br /> if not metatable.donePairs then<br /> mergeArgs(argTables)<br /> metatable.donePairs = true<br /> end<br /> return translatenext, { t = metaArgs }<br /> end<br /> <br /> local function inext(t, i)<br /> -- This uses our __index metamethod<br /> local v = t[i + 1]<br /> if v ~= nil then<br /> return i + 1, v<br /> end<br /> end<br /> <br /> metatable.__ipairs = function (t)<br /> -- Called when ipairs is run on the args table.<br /> return inext, t, 0<br /> end<br /> <br /> return args<br /> end<br /> <br /> return arguments</div> حبيشان