File:Alpha lowercase.svg | This module is rated as alpha. It is ready for third-party input, and may be used on a few pages to see if problems arise, but should be watched. Suggestions for new features or changes in their input and output mechanisms are welcome. |
UsageEdit
This module provides a function which adds fallback functionalities to a given table args according to the fallback sequence given in arg_aliases. Note that this module currently only supports indexing, i.e. __index
.
ParametersEdit
- args
- The table to add fallback functionalities.
- arg_aliases
- A table of the form
{ [key] = { fallback1, fallback2... } }
.
ExampleEdit
The following snippet adds template parameter aliases to a metatable obtained from Module:Arguments.
local getArgs = require('Module:Arguments').getArgs
local makeFallback = require('Module:Sandbox/Artoria2e5/Fallback')
local p = {}
function p.main(frame)
local args = makeFallback(getArgs(frame), {
["foo_bar"] = {"foobar", "foo", "bar"}
})
-- Try calling this template with |foo=42.
return (args["foo_bar"] or "nothing here!")
end
return p
The following snippet shows basic usage of indexing fallback.
local makeFallback = require('Module:Arguments/Fallback')
table = {
["bar"] = "crunchy"
}
makeFallback(table, {
["foo_bar"] = {"foobar", "foo", "bar"}
})
return table["foo_bar"]
The following snippet creates a fallback list with all fallback names aliasing back to the main name.
local makeFallback = require('Module:Sandbox/Artoria2e5/Fallback')
table = {
["bar"] = "crunchy"
}
makeFallback(table, {
["foo_bar"] = {"foobar", "foo", "bar"},
["foo"] = {"foo_bar"},
["foobar"] = {"foo_bar"},
["bar"] = {"foo_bar"}
})
return table["foo"]
-- A simple index fallback implementation for tables.
-- Useful for template argument aliasing.
-- Hmm, what about __newindex?
local function makeFallback(args, arg_aliases)
local oldArgsMeta = getmetatable(args) or {}
local newArgsMeta = {}
-- Forget about thread-safety.
-- States kept to avoid strange loops.
local referencedKeys = {} -- dataType:Set/hashtable-impl
local attemptDepth = 0 -- useful for "last nil" case
-- Start the new metatable as a copy of the old metatable.
for k, v in ipairs(oldArgsMeta) do
newArgsMeta[k] = v
end
-- Change the __index metamethod to our implementation.
-- See https://www.lua.org/pil/13.4.1.html.
newArgsMeta.__index = function (t, k)
-- My friend, why are you here again?
if referencedKeys[k] then
-- You have to be drunk. Go home.
return nil
end
referencedKeys[k] = true
-- Try the old metamethod first.
-- Thanks to closures, this whole oldArgsMeta object will stay.
if oldArgsMeta.__index ~= nil then
local val = oldArgsMeta.__index(t, k)
if val ~= nil then
referencedKeys = {}
return val
end
end
attemptDepth = attemptDepth + 1
-- Now try use the aliases given.
for _, v in ipairs(arg_aliases[k] or {}) do
-- If a working value is found, use it.
-- Note: mw-argument-specific empty str chk.
if t[v] ~= nil and t[v] ~= '' then
referencedKeys = {}
return t[v]
end
end
attemptDepth = attemptDepth - 1
if attemptDepth == 0 then
referencedKeys = {}
end
return nil
end
setmetatable(args, newArgsMeta)
return args -- just in case someone wants a return value.
end
return makeFallback
--[[
P.S. Don't blame me for writing these obj-states. Sure, we can use an
accumulator and do some "index with acc" ourselves, but that sounds like too
much work done just to avoid states.
Here is that custom index function in case anyone is curious about it:
function index_w_acc(t, k, acc)
local v = rawget(t, k)
if v ~= nil
return v
else
return getmetatable(t).__index(k, acc)
end
end
My guess is that it will certainly be slower than the native t[k] one. Perhaps
not getting the metatable every time will help a bit.
]]--