行 47: |
行 47: |
| return val | | return val |
| end | | end |
| + | |
| + | local function matchesTitle(given, title) |
| + | local tp = type( given ) |
| + | return (tp == 'string' or tp == 'number') and mw.title.new( given ).prefixedText == title |
| + | end |
| + | |
| + | local translate_mt = { __index = function(t, k) return k end } |
| | | |
| function arguments.getArgs(frame, options) | | function arguments.getArgs(frame, options) |
行 53: |
行 60: |
| frame = frame or {} | | frame = frame or {} |
| options = options or {} | | options = options or {} |
| + | |
| + | --[[ |
| + | -- Set up argument translation. |
| + | --]] |
| + | options.translate = options.translate or {} |
| + | if getmetatable(options.translate) == nil then |
| + | setmetatable(options.translate, translate_mt) |
| + | end |
| + | if options.backtranslate == nil then |
| + | options.backtranslate = {} |
| + | for k,v in pairs(options.translate) do |
| + | options.backtranslate[v] = k |
| + | end |
| + | end |
| + | if options.backtranslate and getmetatable(options.backtranslate) == nil then |
| + | setmetatable(options.backtranslate, { |
| + | __index = function(t, k) |
| + | if options.translate[k] ~= k then |
| + | return nil |
| + | else |
| + | return k |
| + | end |
| + | end |
| + | }) |
| + | end |
| | | |
| --[[ | | --[[ |
行 82: |
行 114: |
| local title = parent:getTitle():gsub('/sandbox$', '') | | local title = parent:getTitle():gsub('/sandbox$', '') |
| local found = false | | local found = false |
− | if type(options.wrappers) == 'table' then | + | if matchesTitle(options.wrappers, title) then |
| + | found = true |
| + | elseif type(options.wrappers) == 'table' then |
| for _,v in pairs(options.wrappers) do | | for _,v in pairs(options.wrappers) do |
− | if v == title then | + | if matchesTitle(v, title) then |
| found = true | | found = true |
| break | | break |
| end | | end |
| end | | end |
− | elseif options.wrappers == title then
| |
− | found = true
| |
| end | | end |
− |
| + | |
| -- We test for false specifically here so that nil (the default) acts like true. | | -- We test for false specifically here so that nil (the default) acts like true. |
| if found or options.frameOnly == false then | | if found or options.frameOnly == false then |
行 117: |
行 149: |
| luaArgs = frame | | luaArgs = frame |
| end | | end |
− |
| + | |
| -- Set the order of precedence of the argument tables. If the variables are | | -- Set the order of precedence of the argument tables. If the variables are |
| -- nil, nothing will be added to the table, which is how we avoid clashes | | -- nil, nothing will be added to the table, which is how we avoid clashes |
− | -- between the frame/parent args and the Lua args. | + | -- between the frame/parent args and the Lua args. |
| local argTables = {fargs} | | local argTables = {fargs} |
| argTables[#argTables + 1] = pargs | | argTables[#argTables + 1] = pargs |
行 165: |
行 197: |
| setmetatable(args, metatable) | | setmetatable(args, metatable) |
| | | |
− | local function mergeArgs(iterator, tables) | + | local function mergeArgs(tables) |
| --[[ | | --[[ |
| -- Accepts multiple tables as input and merges their keys and values | | -- Accepts multiple tables as input and merges their keys and values |
− | -- into one table using the specified iterator. If a value is already | + | -- into one table. If a value is already present it is not overwritten; |
− | -- present it is not overwritten; tables listed earlier have precedence.
| + | -- tables listed earlier have precedence. We are also memoizing nil |
− | -- We are also memoizing nil values, but those values can be
| + | -- values, which can be overwritten if they are 's' (soft). |
− | -- overwritten.
| |
| --]] | | --]] |
| for _, t in ipairs(tables) do | | for _, t in ipairs(tables) do |
− | for key, val in iterator(t) do | + | for key, val in pairs(t) do |
− | if metaArgs[key] == nil then | + | if metaArgs[key] == nil and nilArgs[key] ~= 'h' then |
| local tidiedVal = tidyVal(key, val) | | local tidiedVal = tidyVal(key, val) |
| if tidiedVal == nil then | | if tidiedVal == nil then |
− | nilArgs[key] = true | + | nilArgs[key] = 's' |
| else | | else |
| metaArgs[key] = tidiedVal | | metaArgs[key] = tidiedVal |
行 211: |
行 242: |
| -- must be nil. | | -- must be nil. |
| --]] | | --]] |
| + | if type(key) == 'string' then |
| + | key = options.translate[key] |
| + | end |
| local val = metaArgs[key] | | local val = metaArgs[key] |
| if val ~= nil then | | if val ~= nil then |
行 219: |
行 253: |
| for _, argTable in ipairs(argTables) do | | for _, argTable in ipairs(argTables) do |
| local argTableVal = tidyVal(key, argTable[key]) | | local argTableVal = tidyVal(key, argTable[key]) |
− | if argTableVal == nil then | + | if argTableVal ~= nil then |
− | nilArgs[key] = true
| |
− | else
| |
| metaArgs[key] = argTableVal | | metaArgs[key] = argTableVal |
| return argTableVal | | return argTableVal |
| end | | end |
| end | | end |
| + | nilArgs[key] = 'h' |
| return nil | | return nil |
| end | | end |
行 232: |
行 265: |
| -- This function is called when a module tries to add a new value to the | | -- This function is called when a module tries to add a new value to the |
| -- args table, or tries to change an existing value. | | -- args table, or tries to change an existing value. |
| + | if type(key) == 'string' then |
| + | key = options.translate[key] |
| + | end |
| if options.readOnly then | | if options.readOnly then |
| error( | | error( |
行 255: |
行 291: |
| --]] | | --]] |
| metaArgs[key] = nil | | metaArgs[key] = nil |
− | nilArgs[key] = true | + | nilArgs[key] = 'h' |
| else | | else |
| metaArgs[key] = val | | metaArgs[key] = val |
| + | end |
| + | end |
| + | |
| + | local function translatenext(invariant) |
| + | local k, v = next(invariant.t, invariant.k) |
| + | invariant.k = k |
| + | if k == nil then |
| + | return nil |
| + | elseif type(k) ~= 'string' or not options.backtranslate then |
| + | return k, v |
| + | else |
| + | local backtranslate = options.backtranslate[k] |
| + | if backtranslate == nil then |
| + | -- Skip this one. This is a tail call, so this won't cause stack overflow |
| + | return translatenext(invariant) |
| + | else |
| + | return backtranslate, v |
| + | end |
| end | | end |
| end | | end |
行 264: |
行 318: |
| -- Called when pairs is run on the args table. | | -- Called when pairs is run on the args table. |
| if not metatable.donePairs then | | if not metatable.donePairs then |
− | mergeArgs(pairs, argTables) | + | mergeArgs(argTables) |
| metatable.donePairs = true | | metatable.donePairs = true |
− | metatable.doneIpairs = true
| |
| end | | end |
− | return pairs(metaArgs) | + | return translatenext, { t = metaArgs } |
| end | | end |
| | | |
− | metatable.__ipairs = function () | + | local function inext(t, i) |
| + | -- This uses our __index metamethod |
| + | local v = t[i + 1] |
| + | if v ~= nil then |
| + | return i + 1, v |
| + | end |
| + | end |
| + | |
| + | metatable.__ipairs = function (t) |
| -- Called when ipairs is run on the args table. | | -- Called when ipairs is run on the args table. |
− | if not metatable.doneIpairs then | + | return inext, t, 0 |
− | mergeArgs(ipairs, argTables)
| |
− | metatable.doneIpairs = true
| |
− | end
| |
− | return ipairs(metaArgs)
| |
| end | | end |
| | | |