Line 1: |
Line 1: |
| + | local Core = {} |
| | | |
− | local Utils = {}
| + | -- * Function functions. |
| | | |
− | -- * Function functions :V
| + | function Core.id(x) |
− | | + | return x |
− | function Utils.id(x) | |
− | return x
| |
| end | | end |
| | | |
| -- * Collection functions. | | -- * Collection functions. |
| | | |
− | function Utils.find(tbl, v_, k_) | + | function Core.find(tbl, v_, k_) |
− | for _, v in pairs(tbl) do
| + | for _, v in pairs(tbl) do |
− | if k_ and v and v[k_] == v_ or not k_ and v == v_ then
| + | if k_ and v and v[k_] == v_ or not k_ and v == v_ then |
− | return v
| + | return v |
− | end
| |
− | end
| |
− | return false
| |
− | end
| |
− | | |
− | function Utils.includes(tbl, v_, k_)
| |
− | for _, v in pairs(tbl) do
| |
− | if k_ and v and v[k_] == v_ or not k_ and v == v_ then
| |
− | return true
| |
− | end
| |
− | end
| |
− | return false
| |
− | end
| |
− | | |
− | function Utils.map(tbl, fn)
| |
− | local result = {}
| |
− | for k, v in pairs(tbl) do
| |
− | table.insert(result, fn(v, k))
| |
− | end
| |
− | return result
| |
− | end
| |
− |
| |
− | function Utils.filter(tbl, pred)
| |
− | local result = {}
| |
− | for k, v in pairs(tbl) do
| |
− | if pred(v, k) then
| |
− | table.insert(result, v)
| |
− | end
| |
− | end
| |
− | return result
| |
− | end
| |
− | | |
− | function Utils.first(tbl)
| |
− | for k, v in pairs(tbl) do
| |
− | return k, v
| |
− | end
| |
− | end
| |
− | | |
− | function Utils.keys(tbl)
| |
− | local result = {}
| |
− | for k, _ in pairs(tbl) do
| |
− | table.insert(result, k)
| |
− | end
| |
− | return result
| |
− | end
| |
− | | |
− | function Utils.ifind(arr, v_)
| |
− | for i, v in ipairs(arr) do
| |
− | if v == v_ then
| |
− | return i
| |
− | end
| |
− | end
| |
− | return false
| |
− | end
| |
− | | |
− | function Utils.ifindBy(arr, p)
| |
− | for i, v in ipairs(arr) do
| |
− | if p(v) then
| |
− | return v, i
| |
− | end
| |
− | end
| |
− | return false
| |
− | end
| |
− | | |
− | function Utils.imax(arr)
| |
− | local maxValue
| |
− | local maxIndex
| |
− | for i, v in ipairs(arr) do
| |
− | if not maxValue or v > maxValue then
| |
− | maxValue = v
| |
− | maxIndex = i
| |
− | end
| |
− | end
| |
− | return maxValue
| |
− | end
| |
− | | |
− | function Utils.imap(arr, fn)
| |
− | local result = {}
| |
− | for i, v in ipairs(arr) do
| |
− | table.insert(result, fn(v, i))
| |
− | end
| |
− | return result
| |
− | end
| |
− | | |
− | function Utils.ifilter(arr, pred)
| |
− | local result = {}
| |
− | for i, v in ipairs(arr) do
| |
− | if pred(v, i) then
| |
− | table.insert(result, v)
| |
− | end
| |
− | end
| |
− | return result
| |
− | end
| |
− | | |
− | function Utils.ifirst(arr)
| |
− | for k, v in ipairs(arr) do
| |
− | return k, v
| |
− | end
| |
− | end
| |
− | | |
− | function Utils.insertNew(arr, el)
| |
− | if not Utils.find(arr, el) then
| |
− | table.insert(arr, el)
| |
− | end
| |
− | end
| |
− | | |
− | function Utils.concat(arr1, arr2)
| |
− | for i = 1, #arr2 do
| |
− | arr1[#arr1 + 1] = arr2[i]
| |
− | end
| |
− | return arr1
| |
− | end
| |
− | | |
− | Utils.join = table.concat
| |
− | | |
− | function Utils.ijoin(arr, sep)
| |
− | sep = sep or ""
| |
− | return table.concat(arr, sep)
| |
− | end
| |
− | | |
− | function Utils.icopy(arr)
| |
− | return Utils.imap(arr, function(v) return v end)
| |
− | end
| |
− | | |
− | function Utils.isort(arr)
| |
− | local result = Utils.icopy(arr)
| |
− | table.sort(result)
| |
− | return result
| |
− | end
| |
− | | |
− | function Utils.isum(arr, result)
| |
− | result = result or 0
| |
− | for _, v in ipairs(arr) do
| |
− | result = result + (v or 0)
| |
− | end
| |
− | return result
| |
− | end
| |
− | | |
− | -- * Number functions.
| |
− | | |
− | function Utils.round(x)
| |
− | return x % 2 ~= 0.5 and math.floor(x + 0.5) or x - 0.5
| |
− | end
| |
− | | |
− | -- * String functions.
| |
− | | |
− | function Utils.pad(s, n, c)
| |
− | c = c or " "
| |
− | n = n or 0
| |
− | s = tostring(s) or ""
| |
− | return #s < n and string.rep(c, n - #s) .. s or s
| |
− | end
| |
− | | |
− | function Utils.trim(s)
| |
− | return string.gsub(s, "^%s*(.-)%s*$", "%1")
| |
− | end
| |
− | | |
− | function Utils.startsWith(s, ss)
| |
− | return string.sub(s, 1, string.len(ss)) == ss
| |
− | end
| |
− | | |
− | -- Capitalize each word in a string.
| |
− | function Utils.capitalize(s)
| |
− | s = s:gsub("(%s)(%l)", function(a, b) return a .. string.upper(b) end)
| |
− | s = s:gsub("^(%l)", function(a) return string.upper(a) end)
| |
− | return s
| |
− | end
| |
− | | |
− | -- * Wikitext/HTML functions.
| |
− | | |
− | function Utils.category(name)
| |
− | return "[[" .. "Category:" .. name .. "]]"
| |
− | end
| |
− | | |
− | function Utils.red(s)
| |
− | return Utils.format{[[<span style="color:red">${s}</span>]], s = s}
| |
− | end
| |
− | | |
− | -- * Calling arbitrary Lua functions using #invoke.
| |
− | | |
− | -- Used to call Formatting:tooltip in Template:Tooltip, mainly because Lua code properly escapes characters,
| |
− | -- so that span's title attribute always works.
| |
− | function Utils.method(frame)
| |
− | local m = require("Module:" .. frame.args[1])
| |
− | local f = frame.args[2]
| |
− | local args = {}
| |
− | for k, v in ipairs(frame.args) do
| |
− | if type(k) == "number" and k >= 3 and type(v) == "string" then
| |
− | table.insert(args, v)
| |
− | end
| |
− | end
| |
− | return m[f](m, unpack(args))
| |
− | end
| |
− | | |
− | -- * Frame functions.
| |
− | | |
− | local getArgs = require("Module:GetArgs")
| |
− | | |
− | -- Unused.
| |
− | function Utils.getContext(frame)
| |
− | local frame1 = frame:getParent()
| |
− | if frame1 then
| |
− | local frame2 = frame1:getParent()
| |
− | if frame2 then
| |
− | return { pagename = frame2:getTitle(), args = getArgs{ frame = frame2 } }
| |
− | else
| |
− | return { pagename = frame1:getTitle(), args = getArgs{ frame = frame1 } }
| |
− | end
| |
− | else
| |
− | return { pagename = frame:getTitle(), args = getArgs{ frame = frame } }
| |
| end | | end |
| + | end |
| + | return false |
| end | | end |
| | | |
− | -- getParent -> getArgs
| + | return Core |
− | function Utils.getParentArgs(frame)
| |
− | local frame1 = frame:getParent()
| |
− | if frame1 then
| |
− | return getArgs{ frame = frame1 }
| |
− | else
| |
− | return nil
| |
− | end
| |
− | end
| |
− | | |
− | -- getArgs + getParent -> getArgs, "implicit" args can be defined in the template (e.g. pagename={{PAGENAME}})
| |
− | -- "explicit" args are user defined.
| |
− | function Utils.getTemplateArgs(frame)
| |
− | local frame1 = frame:getParent()
| |
− | if frame1 then
| |
− | return { implicit = getArgs{ frame = frame }, explicit = getArgs{ frame = frame1 } }
| |
− | else
| |
− | return { implicit = getArgs{ frame = frame }, explicit = {} }
| |
− | end
| |
− | end
| |
− | | |
− | function Utils.requireModule(name)
| |
− | local success, data = pcall(function () return require(string.format("Module:%s", name)) end)
| |
− | -- module without return (or empty, nil, false, true return) gives success = true, data = true
| |
− | if data == true then
| |
− | return false, nil
| |
− | else
| |
− | return success, data
| |
− | end
| |
− | end
| |
− | | |
− | -- * Testing functions.
| |
− | | |
− | function Utils.debugPrint(x, i)
| |
− | i = i or 0
| |
− | if type(x) == "table" then
| |
− | for k, v in pairs(x) do
| |
− | mw.log(
| |
− | string.rep(" ", i) .. tostring(k) .. " : " .. type(k) .. " = " ..
| |
− | (type(v) == "table" and "table" or tostring(v) .. " : " .. type(v))
| |
− | )
| |
− | if type(v) == "table" then
| |
− | Utils.debugPrint(v, i + 1)
| |
− | end
| |
− | end
| |
− | else
| |
− | mw.log(tostring(x) .. " : " .. type(x))
| |
− | end
| |
− | end
| |
− | | |
− | local function showValue(v)
| |
− | return type(v) == "string" and string.format('"%s"', v) or type(v) == "function" and '"function"' or tostring(v)
| |
− | end
| |
− | | |
− | function Utils.js(x, i)
| |
− | i = i or 0
| |
− | local r = ""
| |
− | if type(x) == "table" then
| |
− | r = "{\n"
| |
− | for k, v in pairs(x) do
| |
− | if type(v) == "table" then
| |
− | r = r .. string.rep(" ", i + 1) .. tostring(k) .. ": " .. Utils.js(v, i + 1)
| |
− | else
| |
− | r = r .. string.rep(" ", i + 1) .. tostring(k) .. ": " .. showValue(v) .. ",\n"
| |
− | end
| |
− | end
| |
− | r = r .. string.rep(" ", i) .. (i == 0 and "}\n" or "},\n")
| |
− | else
| |
− | return showValue(x)
| |
− | end
| |
− | return r
| |
− | end
| |
− | | |
− | function Utils.registerFormatTests(obj, tests, fn)
| |
− | obj.run_format_tests = function()
| |
− | for _, test in ipairs(tests) do
| |
− | local result = obj.format(nil, test)
| |
− | mw.log(fn and fn(result) or result)
| |
− | end
| |
− | end
| |
− | end
| |
− | | |
− | function Utils.registerTableTests(obj, tests, fn)
| |
− | obj.run_table_tests = function()
| |
− | for _, test in ipairs(tests) do
| |
− | local result = obj:Table(test)
| |
− | mw.log(fn and fn(result) or result)
| |
− | end
| |
− | end
| |
− | end
| |
− | | |
− | function Utils.test(obj, desc, fn)
| |
− | obj.test = function()
| |
− | mw.log(desc)
| |
− | fn(obj)
| |
− | mw.log("ok")
| |
− | end
| |
− | end
| |
− | | |
− | Utils.log = mw.log
| |
− | | |
− | function Utils.format(s, lookup)
| |
− | if not lookup then
| |
− | lookup = s
| |
− | s = lookup[1]
| |
− | table.remove(lookup, 1)
| |
− | end
| |
− | return (string.gsub(s, '${([^%.%!%:%}%[%]]+)%[?([^%.%!%:%}%]]*)%]?%.?([^%!%:%}]*)!?([^%:%}]?):?([^%}]*)}',
| |
− | function(name, element, attribute, conversion, format_spec)
| |
− | --local start_of_value, end_of_value, value = string.find(x, '^${(.-)[[.!:}]')
| |
− | --local start_of_access, end_of_access, access = string.find(x, '^${.-%[(.-)%][!:}]')
| |
− | --if not access then
| |
− | -- start_of_access, end_of_access, access = string.find(x, '^${[^:]-%.(.-)[!:}]')
| |
− | --end
| |
− | --local start_of_conversion, end_of_conversion, conversion = string.find(x, '^${.-!(.)[:}]')
| |
− | --local start_of_format_spec, end_of_format_spec, format_spec = string.find(x, ':(.*)}$')
| |
− | | |
− | local value = lookup[name]
| |
− | if string.len(element) > 0 then
| |
− | value = value[element]
| |
− | elseif string.len(attribute) > 0 then
| |
− | value = value[attribute]
| |
− | end
| |
− | | |
− | if string.len(conversion) > 0 then
| |
− | if conversion == 's' then
| |
− | value = tostring(value)
| |
− | end
| |
− | end
| |
− | | |
− | if string.len(format_spec) > 0 then
| |
− | local start_of_sign, end_of_sign, sign = string.find(format_spec, '([+%- ])')
| |
− | local start_of_width, end_of_width, width, comma, precision, option = string.find(format_spec, '(%d*)(,?)([.0-9]*)([bcdeEfFgGnosxX%%]?)$')
| |
− | precision = string.sub(precision, 2)
| |
− | local number = tonumber(value)
| |
− | if #width > 0 then
| |
− | if number then
| |
− | value = string.format(string.format(number % 1 ~= 0 and "%%0%s.%sf" or "%%0%sd", width, #precision > 0 and precision or 0), number)
| |
− | end
| |
− | value = string.format(string.format("%%0%ss", width), value)
| |
− | elseif #precision > 0 and number then
| |
− | value = string.format(string.format("%%0%s.%sf", width, precision), number)
| |
− | end
| |
− | if sign then
| |
− | if number and number > 0 then
| |
− | if sign == "+" then
| |
− | value = "+" .. value
| |
− | elseif sign == " " then
| |
− | value = " " .. value
| |
− | end
| |
− | end
| |
− | end
| |
− | end
| |
− | | |
− | return value
| |
− | end))
| |
− | end
| |
− | | |
− | function Utils.split(string, separator, max_split, plain)
| |
− | assert(separator ~= '')
| |
− | assert(max_split == nil or max_split >= 1)
| |
− | | |
− | local default_separator = false
| |
− | | |
− | local result = {}
| |
− | | |
− | if not separator or separator == '' then
| |
− | separator = '%s+'
| |
− | plain = false
| |
− | string = mw.text.trim(string)
| |
− | if string == '' then
| |
− | return result
| |
− | end
| |
− | end
| |
− | | |
− | max_split = max_split or -1
| |
− | | |
− | local item_index, start_index = 1, 1
| |
− | local separator_start, separator_end = mw.ustring.find(string, separator, start_index, plain)
| |
− | while separator_start and max_split ~= 0 do
| |
− | result[item_index] = mw.ustring.sub(string, start_index, separator_start - 1)
| |
− | item_index = item_index + 1
| |
− | start_index = separator_end + 1
| |
− | separator_start, separator_end = mw.ustring.find(string, separator, start_index, plain)
| |
− | max_split = max_split - 1
| |
− | end
| |
− | result[item_index] = mw.ustring.sub(string, start_index)
| |
− | | |
− | return result
| |
− | end
| |
− | | |
− | return Utils
| |