See Global Lua Modules/Feature Miscellaneous useful functions.
Documentation
Package items
lib.ternary(cond, T, F)(function)- Choose one of two values to return.
- Parameters:
condDetermines which value to return. (boolean)TThe value to return ifcondis true (or truthy).FThe value to return ifcondis false (or falsey).
lib.trim(text)(function)- Removes ASCII whitespace from the start and end of
text. Slightly more efficient than themw.textimplementation. - Parameter:
textThe text to trim. (string) - Returns: The trimmed text. (string)
- See also: https://help.fandom.com/wiki/Extension:Scribunto#mw.text.trim_is_slow
lib.gsplit()(function)- Returns an iterator over substrings that would be returned by
lib. split. - Returns: Iterator over substrings of
textseparated bydelim. (function) - See also:
lib.splitfor argument documentation. lib.split(text, delim, opt)(function)- Returns a table containing the substrings of
textthat are separated bydelim. (Compared tomw.text.split, this function always treatsdelimas a literal string rather than a pattern, and it trims output substrings usinglib.trimby default.) - Parameters:
- Returns: Substrings of
text separated bydelim`. (table) lib.unstripNoWiki()(function)- A wrapper around
mw. text.unstripNoWikithat un-escapes characters/sequences that <nowiki> escapes. - See also: https://github.com/wikimedia/mediawiki/blob/c22d01f23b7fe754ef106e97bae32c3966f8db3e/includes/parser/CoreTagHooks.php#L146 for MediaWiki source code for <nowiki>
lib.spairs(tbl, order)(function)- Returns an iterator over
tblthat outputs items in the order defined byorder. - Parameters:
tblThe table to iterate over. (table)orderThe iteration order. Can be specified either as an ordered list (table) of keys fromtblor as an ordering function that acceptstbl,keyA, andkeyBand returns true when the entry intblassociated witykeyAshould come before the one forkeyB. If not specified, the keys' natural ordering is used (i.e.,function(tbl, a, b) return a < b end). (table|function; optional)
- Returns: The iterator. (function)
lib.parseTemplateFormat(input, key_separator, end_separator, equal_separator)(function)- Parses Phantom Template Format strings into a list of maps.
- Parameters:
inputA string formed by concatenating the output of Phantom Templates. Usually, this string is generated by DPL. (string)key_separatorSeparator between the entries (key-value pairs) of items ininput. Defaults to ';'. (string; optional)end_separatorSeparator between items ininput. Defaults to '$'. (string; optional)equal_separatorSeparator between the key and value of each entry ininput. Defaults to '='. (string; optional)
- Returns: A list of items from
input; each value is a map of the item's entries. (table) lib.parseTemplateFormatOrdered(input, key_separator, end_separator, equal_separator)(function)- Parses Phantom Template Format strings into a list of ordered maps.
- Parameters:
inputA string formed by concatenating the output of Phantom Templates. Usually, this string is generated by DPL. (string)key_separatorSeparator between the entries (key-value pairs) of items ininput. Defaults to ';'. (string; optional)end_separatorSeparator between items ininput. Defaults to '$'. (string; optional)equal_separatorSeparator between the key and value of each entry ininput. Defaults to '='. (string; optional)
- Returns:
lib.thousandsSeparator(n)(function)- Add thousands separator to number
n. - Parameter:
nIf a frame is given, then its first argument (frame.args1) will be used as input instead. (number|frame; optional) - Returns: The number formatted with commas for thousands separators. (string)
- See also: https://stackoverflow.com/questions/10989788/format-integer-in-lua/10992898#10992898
lib.isEmpty()(function)- Returns: true iff string or table is empty (boolean)
- Note: May not be correct for tables with metatables.
lib.isNotEmpty()(function)- Returns: true iff string or table is not empty (boolean)
- Note: May not be correct for tables with metatables.
lib.nilIfEmpty()(function)- Returns: nil if string or table is empty, otherwise return the value.
lib.inArray(t, elm)(function)- Parameters:
tA table of items (table)elmThe item to search for
- Returns: true if
elmis a value int; false otherwise. (Does not check keys oft.) - See also:
- http://stackoverflow.com/q/2282444
- another implementation: Dev:TableTools.includes()
--- Miscellaneous useful functions.
local lib = {}
local util = require('libraryUtil')
local checkType = util.checkType
local checkTypeMulti = util.checkTypeMulti
local NIL_OK = true
--- Choose one of two values to return.
-- @param {boolean} cond Determines which value to return.
-- @param T The value to return if `cond` is true (or truthy).
-- @param F The value to return if `cond` is false (or falsey).
function lib.ternary(cond, T, F)
if cond then
return T
end
return F
end
---
-- Removes ASCII whitespace from the start and end of `text`.
-- Slightly more efficient than the `mw.text` implementation.
-- @see https://help.fandom.com/wiki/Extension:Scribunto#mw.text.trim_is_slow
-- @param {string} text The text to trim.
-- @return {string} The trimmed text.
function lib.trim(text)
return (text:gsub( '^[\t\r\n\f ]+', '' ):gsub( '[\t\r\n\f ]+$', '' ))
-- the "extra" parentheses are important for removing the second value returned from `gsub`
end
--- Returns an iterator over substrings that would be returned by @{lib.split}.
-- @see @{lib.split} for argument documentation.
-- @return {function} Iterator over substrings of `text` separated by `delim`.
function lib.gsplit(text, delim, opt)
checkType('Feature.gsplit', 1, text, 'string')
checkType('Feature.gsplit', 2, delim, 'string', NIL_OK)
checkType('Feature.gsplit', 3, opt, 'table', NIL_OK)
if delim == nil then delim = " " end
if opt == nil then opt = {} end
-- the mediawiki implementation uses ustring, which is slower than string
-- and also not necessary if delim isn't a pattern.
-- https://help.fandom.com/wiki/Extension:Scribunto#mw.text.split_is_very_slow
-- local g = mw.text.gsplit(text, delim, true)
-- local function f()
-- local value = g()
-- if value and not opt.noTrim then -- value is nil when the generator ends
-- value = mw.text.trim(value)
-- end
-- if value == "" and opt.removeEmpty then
-- return f()
-- end
-- return value
-- end
-- return f, nil, nil
-- based on https://github.com/wikimedia/mediawiki-extensions-Scribunto/blob/1eecdac6def6418fb36829cc2f20b464c30e4b37/includes/Engines/LuaCommon/lualib/mw.text.lua#L222
if delim==';' and text:find('(%&[#%d%w]+);') then
text = text:gsub('(%&[#%d%w]+);', '%1‡');
end
local s, l = 1, #text
local function f()
if s then
local e, n = string.find( text, delim, s, true )
local ret
if not e then
ret = string.sub( text, s )
s = nil
elseif n < e then
-- Empty separator!
ret = string.sub( text, s, e )
if e < l then
s = e + 1
else
s = nil
end
else
ret = e > s and string.sub( text, s, e - 1 ) or ''
s = n + 1
end
if not opt.noTrim then
ret = lib.trim(ret)
end
if ret == '' and opt.removeEmpty then
return f()
end
if delim==';' and ret:find('(%&[#%d%w]+)‡') then
ret = ret:gsub('(%&[#%d%w]+)‡', '%1;');
end
return ret
end
end
return f, nil, nil
end
--- Returns a table containing the substrings of `text` that are separated by `delim`.
-- (Compared to @{mw.text.split}, this function always treats `delim` as a literal
-- string rather than a pattern, and it trims output substrings using @{lib.trim} by default.)
-- @param {string} text The string to split.
-- @param[opt] {string} delim The delimiter string to use when splitting `text`.
-- (Using an empty string will split `text` into individual characters.)
-- @param[opt] {table} opt Extra options:
-- @param[opt] {boolean} opt.noTrim Set true to disable trimming of generated substrings
-- using @{lib.trim}.
-- @param[opt] {boolean} opt.removeEmpty Set true to omit empty substrings
-- (i.e., when multiple `delim` appear consecutively, or when
-- `delim` appears at the start or end of `text`).
-- @return {table} Substrings of `text separated by `delim`.
function lib.split(text, delim, opt)
checkType('Feature.split', 1, text, 'string')
checkType('Feature.split', 2, delim, 'string', NIL_OK)
checkType('Feature.split', 3, opt, 'table', NIL_OK)
local output = {}
for item in lib.gsplit(text, delim, opt) do
table.insert(output, item)
end
return output
end
--- A wrapper around @{mw.text.unstripNoWiki} that un-escapes
-- characters/sequences that <nowiki> escapes.
-- @see https://github.com/wikimedia/mediawiki/blob/c22d01f23b7fe754ef106e97bae32c3966f8db3e/includes/parser/CoreTagHooks.php#L146
-- for MediaWiki source code for <nowiki>
function lib.unstripNoWiki(str)
return (mw.text.unstripNoWiki(str)
:gsub('<', '<'):gsub('>', '>')
:gsub('-{', '-{'):gsub('}-', '}-'))
-- the "extra" parentheses are important for removing the second value returned from `gsub`
end
--- Returns an iterator over `tbl` that outputs items in the order defined by `order`.
-- @param {table} tbl The table to iterate over.
-- @param[opt] {table|function} order The iteration order.
--
-- Can be specified either as an ordered list (table) of keys from `tbl`
-- or as an ordering function that accepts `tbl`, `keyA`, and `keyB`
-- and returns true when the entry in `tbl` associated wity `keyA`
-- should come before the one for `keyB`.
--
-- If not specified, the keys' natural ordering is used
-- (i.e., `function(tbl, a, b) return a < b end`).
-- @return {function} The iterator.
function lib.spairs(tbl, order)
checkType('Feature.spairs', 1, tbl, 'table')
checkTypeMulti('Feature.spairs', 2, order, {'table', 'function', 'nil'})
local keys
if type(order) == "table" then
keys = order
else
-- collect the keys
keys = {}
for k in pairs(tbl) do table.insert(keys, k) end
-- sort the keys (using order function if given)
if order then
table.sort(keys, function(a, b) return order(tbl, a, b) end)
else
table.sort(keys)
end
end
-- return the iterator function
local i = 0
return function()
i = i + 1
local key = keys[i]
return key, tbl[key]
end
end
--[[
Parses Phantom Template Format strings into a list of maps.
@param {string} input A string formed by concatenating the output of Phantom Templates.
Usually, this string is generated by DPL.
@param[opt] {string} key_separator Separator between the entries (key-value pairs) of items in `input`. Defaults to ';'.
@param[opt] {string} end_separator Separator between items in `input`. Defaults to '$'.
@param[opt] {string} equal_separator Separator between the key and value of each entry in `input`. Defaults to '='.
@return {table} A list of items from `input`; each value is a map of the item's entries.
--]]
function lib.parseTemplateFormat (inputStr, key_separator, end_separator, equal_separator)
if key_separator == nil then key_separator = ";" end
if end_separator == nil then end_separator = "$" end
if equal_separator == nil then equal_separator = "=" end
local arg_format = "^%s*(.-)%s*" .. equal_separator .. "%s*(.-)%s*$"
local resultTable = {}
for str in lib.gsplit(inputStr, end_separator, {noTrim=true, removeEmpty=true}) do
local result = {}
for param in lib.gsplit(str, key_separator) do
local arg, val = param:match(arg_format)
if arg then
result[arg] = val
else
-- skip, i guess
-- mw.log("Warning: Lua module found extra " .. key_separator .. " or " .. end_separator .. " separators in DPL output.")
end
end
table.insert(resultTable, result)
end
return resultTable
end
--[=[
Parses Phantom Template Format strings into a list of ordered maps.
@param {string} input A string formed by concatenating the output of Phantom Templates.
Usually, this string is generated by DPL.
@param[opt] {string} key_separator Separator between the entries (key-value pairs) of items in `input`. Defaults to ';'.
@param[opt] {string} end_separator Separator between items in `input`. Defaults to '$'.
@param[opt] {string} equal_separator Separator between the key and value of each entry in `input`. Defaults to '='.
@return[name=output] {table} A list of items from `input`; each value is a list of the item's entries.
@return[name=output[i]] {table} The i-th item of `input`.
@return[name=output[i].page] {string} The value of the `page` key for this item.
@return[name=output[i][j]] {table} The j-th key-value pair of this item.
@return[name=output[i][j].key] {string} The j-th key of this item.
@return[name=output[i][j].value] The j-th value of this item.
--]=]
function lib.parseTemplateFormatOrdered (inputStr, key_separator, end_separator, equal_separator)
if key_separator == nil then key_separator = ";" end
if end_separator == nil then end_separator = "$" end
if equal_separator == nil then equal_separator = "=" end
local arg_format = "^%s*(.-)%s*" .. equal_separator .. "%s*(.-)%s*$"
local resultTable = {}
for str in lib.gsplit(inputStr, end_separator, {noTrim=true, removeEmpty=true}) do
local result = {}
for param in lib.gsplit(str, key_separator) do
local arg, val = param:match(arg_format)
if arg == 'page' then
result['page'] = val
else
table.insert(result,{
key = arg,
value = val
})
end
end
table.insert(resultTable, result)
end
return resultTable
end
-- searches ordered table and returns value
function lib.orderedTableSearch(tbl, search)
for i, obj in ipairs(tbl) do
if obj.key == search then
return obj.value
end
end
return false
end
--- Add thousands separator to number `n`.
-- @param {number|frame} n If a frame is given, then its first argument (`frame.args[1]`) will be used as input instead.
-- @return {string} The number formatted with commas for thousands separators.
-- @see https://stackoverflow.com/questions/10989788/format-integer-in-lua/10992898#10992898
function lib.thousandsSeparator(n)
if (n == mw.getCurrentFrame()) then
n = n.args[1]
elseif (type(n) == "table") then
n = n[1]
end
local i, j, minus, int, fraction = tostring(n):find('([-]?)(%d+)([.]?%d*)')
-- reverse the int-string and append a comma to all blocks of 3 digits
int = int:reverse():gsub("(%d%d%d)", "%1,")
-- reverse the int-string back remove an optional comma and put the optional minus and fractional part back
return minus .. int:reverse():gsub("^,", "") .. fraction
end
--- @return {boolean} true iff string or table is empty
-- @note May not be correct for tables with metatables.
function lib.isEmpty(item)
if item == nil or item == "" then
return true
end
if type(item) == "table" then
return next(item) == nil
end
return false
end
--- @return {boolean} true iff string or table is not empty
-- @note May not be correct for tables with metatables.
function lib.isNotEmpty(item)
return not lib.isEmpty(item)
end
--- @return nil if string or table is empty, otherwise return the value.
function lib.nilIfEmpty(item)
if lib.isEmpty(item) then
return nil
else
return item
end
end
---
-- @param {table} t A table of items
-- @param elm The item to search for
-- @returns true if `elm` is a value in `t`; false otherwise. (Does not check keys of `t`.)
-- @see http://stackoverflow.com/q/2282444
-- @see another implementation: Dev:TableTools.includes()
function lib.inArray(t, elm)
for _, v in pairs(t) do
if v == elm then
return true
end
end
return false
end
return lib