Modul:Arguments
Author
Albert FloresModul:Arguments je skriptovací modul vytvořený pro mediawiki, který poskytuje funkce pro práci s argumenty předanými do šablony nebo funkce. Tento modul je široce využíván na české Wikipedii pro manipulaci s parametry a proměnnými v různých šablonách a funkcích. Skriptovací modul je implementován v Lua a obsahuje různé metody pro práci s argumenty, jako například získávání hodnoty určitého parametru, kontrolu existence parametru nebo jejich vytváření a manipulaci s nimi. Modul také poskytuje možnost provádět matematické operace s hodnotami argumentů a porovnávat je mezi sebou. Modul:Arguments je velmi užitečný pro tvorbu uživatelských šablon a funkcí na Wikipedii, protože umožňuje jednoduše předávat a upravovat hodnoty různých parametrů. Díky své flexibilitě a rozsáhlým funkcím je často používán pro různé účely, jako například vytváření seznamů, tabulek, grafů, formátování textu a dalších úprav. Modul:Arguments je jedním z mnoha modulů, které jsou dostupné na české Wikipedii pro zjednodušení práce s šablonami a funkcemi. Jeho účel spočívá v usnadnění manipulace s argumenty a jejich využití při tvorbě obsahu na stránkách.
-- This module provides easy processing of arguments passed to Scribunto from -- #invoke. It is intended for use by other Lua modules, and should not be -- called from #invoke directly.
local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType
local arguments = {}
-- Generate four different tidyVal functions, so that we don't have to check the -- options every time we call it.
local function tidyValDefault(key, val) if type(val) == 'string' then val = val:match('^%s*(.-)%s*$') if val
then return nil else return val end else return val end end local function tidyValTrimOnly(key, val) if type(val)
'string' then return val:match('^%s*(.-)%s*$') else return val end end
local function tidyValRemoveBlanksOnly(key, val) if type(val) == 'string' then if val:find('%S') then return val else return nil end else return val end end
local function tidyValNoChange(key, val) return val 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) checkType('getArgs', 1, frame, 'table', true) checkType('getArgs', 2, options, 'table', true) frame = frame or {} options = options or {}
-- -- Set up argument translation. -- options.translate = options.translate or {} if getmetatable(options.translate)
Important
nil then setmetatable(options.translate, translate_mt) end if options.backtranslate
nil then options. backtranslate = {} for k,v in pairs(options. +moretranslate) 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.
'table' and type(frame.getParent)
'function' then if options. wrappers then --+more_This_means_that_users_can_use_either_the_'>invoke syntax -- or a wrapper template without the loss of performance associated -- with looking arguments up in both the frame and the parent frame. -- Module:Arguments will look up arguments in the parent frame -- if it finds the parent frame's title in options. wrapper; -- otherwise it will look up arguments in the frame object passed -- to getArgs. -- local parent = frame:getParent if not parent then fargs = frame. args else local title = parent:getTitle:gsub('/sandbox$') local found = false if matchesTitle(options. wrappers, title) then found = true elseif type(options. wrappers) == 'table' then for _,v in pairs(options. wrappers) do if matchesTitle(v, title) then found = true break end end end.
-- We test for false specifically here so that nil (the default) acts like true. if found or options. +moreframeOnly == false then pargs = parent. args end if not found or options. parentOnly == false then fargs = frame. args end end else -- options. wrapper isn't set, so check the other options. if not options. parentOnly then fargs = frame. args end if not options. frameOnly then local parent = frame:getParent pargs = parent and parent. args or nil end end if options. parentFirst then fargs, pargs = pargs, fargs end else luaArgs = frame end.
-- 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 -- between the frame/parent args and the Lua args. +more local argTables = {fargs} argTables[#argTables + 1] = pargs argTables[#argTables + 1] = luaArgs.
--+more_This_is_so_that_we_don't_have_to_call_the_options_table --_every_time_the_function_is_called. --'> -- Generate the tidyVal function. If it has been specified by the user, we -- use that; if not, we choose one of four functions depending on the -- options chosen. This is so that we don't have to call the options table -- every time the function is called. -- local tidyVal = options. valueFunc if tidyVal then if type(tidyVal) ~= 'function' then error( "bad value assigned to option 'valueFunc'" . '(function expected, got ' . type(tidyVal) . ')', 2 ) end elseif options. trim ~= false then if options. removeBlanks ~= false then tidyVal = tidyValDefault else tidyVal = tidyValTrimOnly end else if options. removeBlanks ~= false then tidyVal = tidyValRemoveBlanksOnly else tidyVal = tidyValNoChange end end.
--+more_Nil --_arguments_are_memoized_in_nilArgs,_and_the_metatable_connects_all_of_them --_together. --'> -- Set up the args, metaArgs and nilArgs tables. args will be the one -- accessed from functions, and metaArgs will hold the actual arguments. Nil -- arguments are memoized in nilArgs, and the metatable connects all of them -- together. -- local args, metaArgs, nilArgs, metatable = {}, {}, {}, {} setmetatable(args, metatable).
local function mergeArgs(tables) --+more_We_are_also_memoizing_nil --_values,_which_can_be_overwritten_if_they_are_'s'_(soft). --'> -- Accepts multiple tables as input and merges their keys and values -- into one table. If a value is already present it is not overwritten; -- tables listed earlier have precedence. We are also memoizing nil -- values, which can be overwritten if they are 's' (soft). -- for _, t in ipairs(tables) do for key, val in pairs(t) do if metaArgs[key] == nil and nilArgs[key] ~= 'h' then local tidiedVal = tidyVal(key, val) if tidiedVal == nil then nilArgs[key] = 's' else metaArgs[key] = tidiedVal end end end end end.
metatable. __index = function (t, key) --+more_First_we_check --_to_see_if_the_value_is_memoized,_and_if_not_we_try_and_fetch_it_from --_the_argument_tables. _When_we_check_memoization,_we_need_to_check --_metaArgs_before_nilArgs,_as_both_can_be_non-nil_at_the_same_time. --_If_the_argument_is_not_present_in_metaArgs,_we_also_check_whether --_pairs_has_been_run_yet. _If_pairs_has_already_been_run,_we_return_nil. --_This_is_because_all_the_arguments_will_have_already_been_copied_into --_metaArgs_by_the_mergeArgs_function,_meaning_that_any_other_arguments --_must_be_nil. --'> -- Fetches an argument when the args table is indexed. First we check -- to see if the value is memoized, and if not we try and fetch it from -- the argument tables. When we check memoization, we need to check -- metaArgs before nilArgs, as both can be non-nil at the same time. -- If the argument is not present in metaArgs, we also check whether -- pairs has been run yet. If pairs has already been run, we return nil. -- This is because all the arguments will have already been copied into -- metaArgs by the mergeArgs function, meaning that any other arguments -- must be nil. -- if type(key) == 'string' then key = options. translate[key] end local val = metaArgs[key] if val ~= nil then return val elseif metatable. donePairs or nilArgs[key] then return nil end for _, argTable in ipairs(argTables) do local argTableVal = tidyVal(key, argTable[key]) if argTableVal ~= nil then metaArgs[key] = argTableVal return argTableVal end end nilArgs[key] = 'h' return nil end.
metatable. __newindex = function (t, key, val) -- This function is called when a module tries to add a new value to the -- args table, or tries to change an existing value. +more if type(key) == 'string' then key = options. translate[key] end if options. readOnly then error( 'could not write to argument table key "' . tostring(key) . '"; the table is read-only', 2 ) elseif options. noOverwrite and args[key] ~= nil then error( 'could not write to argument table key "' . tostring(key) . '"; overwriting existing arguments is not permitted', 2 ) elseif val == nil then -- -- If the argument is to be overwritten with nil, we need to erase -- the value in metaArgs, so that __index, __pairs and __ipairs do -- not use a previous existing value, if present; and we also need -- to memoize the nil in nilArgs, so that the value isn't looked -- up in the argument tables if it is accessed again. -- metaArgs[key] = nil nilArgs[key] = 'h' else metaArgs[key] = val end end.
local function translatenext(invariant) local k, v = next(invariant. t, invariant. +morek) 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.
metatable. __pairs = function -- Called when pairs is run on the args table. +more if not metatable. donePairs then mergeArgs(argTables) metatable. donePairs = true end return translatenext, { t = metaArgs } end.
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. return inext, t, 0 end
return args end
return arguments