Anonymous

Module:Shared: Difference between revisions

From Melvor Idle
2,682 bytes added ,  26 October 2022
no edit summary
(Copied over some handy shared functions I'll probably need later.)
 
No edit summary
(26 intermediate revisions by 3 users not shown)
Line 13: Line 13:


local p = {}
local p = {}
 
-- iterator sorted by keys
-- iterator sorted by keys
-- For example, if you had a table that looked something like
-- For example, if you had a table that looked something like
Line 25: Line 25:
--Originally snagged this from Module:VoidByReward written by User:NoBrainz
--Originally snagged this from Module:VoidByReward written by User:NoBrainz
function p.skpairs(t, revert)
function p.skpairs(t, revert)
    local keys = {}
local keys = {}
    for k in pairs(t) do keys[#keys + 1] = k end
for k in pairs(t) do keys[#keys + 1] = k end
    if revert ~= nil then
if revert ~= nil then
        table.sort(keys, function(a, b) return a > b end)
table.sort(keys, function(a, b) return a > b end)
    else
else
        table.sort(keys)
table.sort(keys)
    end
end
 
    local i = 0
local i = 0
    local iterator = function()
local iterator = function()
        i = i + 1
i = i + 1
        local key = keys[i]
local key = keys[i]
        if key then
if key then
            return key, t[key]
return key, t[key]
        else
else
            return nil
return nil
        end
end
    end
end
    return iterator
return iterator
end
 
 
--General purpose function for going through a table after sorting based on a custom sort order
--Taken from https://stackoverflow.com/questions/15706270/sort-a-table-in-lua
function p.spairs(t, order)
-- collect the keys
local keys = {}
for k in pairs(t) do keys[#keys+1] = k end
 
-- if order function given, sort by it by passing the table and keys a, b,
-- otherwise just sort the keys
if order then
table.sort(keys, function(a,b) return order(t, a, b) end)
else
table.sort(keys)
end
 
-- return the iterator function
local i = 0
return function()
i = i + 1
if keys[i] then
return keys[i], t[keys[i]]
end
end
end
end
 
-- conveniently shifts BLAH to Blah
-- conveniently shifts BLAH to Blah
-- Handy when formatting data in ALL CAPS or all lower case
-- Handy when formatting data in ALL CAPS or all lower case
--Originally snagged this from Module:VoidByReward written by User:NoBrainz
--Originally snagged this from Module:VoidByReward written by User:NoBrainz
function p.titleCase(head, tail)
function p.titleCase(head, tail)
    if tail == nil then
if tail == nil then
        --Split into two lines because don't want the other return from gsub
--Split into two lines because don't want the other return from gsub
        local result = string.gsub(head, "(%a)([%w_']*)", p.titleCase)
local result = string.gsub(head, "(%a)([%w_']*)", p.titleCase)
        return result
return result
    else
else
        return string.upper(head) .. string.lower(tail)
return string.upper(head) .. string.lower(tail)
    end
end
end
end
 
-- Returns the number of rows in a table
-- Returns the number of rows in a table
-- Originally snagged this from Module:VoidByReward written by User:NoBrainz
-- Originally snagged this from Module:VoidByReward written by User:NoBrainz
Line 71: Line 97:
--      if table is not of type 'table' then return nil
--      if table is not of type 'table' then return nil
function p.tableCount(table)
function p.tableCount(table)
    if (type(table) == 'table') then
if (type(table) == 'table') then
        local count = 0
local count = 0
        for _ in pairs(table) do count = count + 1 end
for _ in pairs(table) do count = count + 1 end
        return count
return count
    else
else
        return nil
return nil
    end
end
end
 
-- Returns true if the table is empty, false otherwise
function p.tableIsEmpty(table)
if type(table) == 'table' then
for k, v in pairs(table) do
return false
end
return true
else
return nil
end
end
end
 
-- Returns the number of indexed elements in a table
-- Returns the number of indexed elements in a table
-- pre : table is a table with no explicit nil values
-- pre : table is a table with no explicit nil values
Line 85: Line 123:
--      if table is not of type 'table' then return nil
--      if table is not of type 'table' then return nil
function p.indexCount(table)
function p.indexCount(table)
    if (type(table) == 'table') then
if (type(table) == 'table') then
        local count = 0
local count = 0
        for _ in ipairs(table) do count = count + 1 end
for _ in ipairs(table) do count = count + 1 end
        return count
return count
    else
else
        return nil
return nil
    end
end
end
end
 
--Sorts theTable based on the listed column
--Sorts theTable based on the listed column
function p.tableSort(theTable, sortCol, ascend)
function p.tableSort(theTable, sortCol, ascend)
    local new  function sorter(r1, r2)
local sorter = function(r1, r2)
                    if(ascend) then
if ascend then
                        return r1[sortCol] < r2[sortCol]
return r1[sortCol] < r2[sortCol]
                    else
else
                        return r1[sortCol] > r2[sortCol]
return r1[sortCol] > r2[sortCol]
                    end
end
                end
end
    table.sort(theTable, sorter)
table.sort(theTable, sorter)
end
end
 
--Splits a string based on a sent in separating character
--Splits a string based on a sent in separating character
--For example calling splitString ("Lith V1 Relic", " ") would return {"Lith", "V1", "Relic"}
--For example calling splitString ("Lith V1 Relic", " ") would return {"Lith", "V1", "Relic"}
function p.splitString(inputstr, sep)
function p.splitString(inputstr, sep)
        if sep == nil then
if sep == nil then
                sep = "%s"
sep = "%s"
        end
end
        local t={}
local t = {}
        for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
                table.insert(t, str)
table.insert(t, str)
        end
end
        return t
return t
end
end
 
--Returns 'true' if a string starts with something
--Returns 'true' if a string starts with something
--For example calling startsWith ("Lith V1 Relic", "Lith") would return true
--For example calling startsWith ("Lith V1 Relic", "Lith") would return true
function p.startsWith(string1, start)
function p.startsWith(string1, start)
    return string.sub(string1, 1, string.len(start)) == start
return string.sub(string1, 1, string.len(start)) == start
end
end
 
--Stolen from Stack Overflow
--Adds commas
--Adds commas
function p.formatnum(number)
function p.formatnum(number)
  local i, j, minus, int, fraction = tostring(number):find('([-]?)(%d+)([.]?%d*)')
if tonumber(number) == nil then
return number
  -- reverse the int-string and append a comma to all blocks of 3 digits
else
  int = int:reverse():gsub("(%d%d%d)", "%1,")
local result = number
while true do
  -- reverse the int-string back remove an optional comma and put the
-- Format in blocks of 3 digits at a time until formatting is complete
  -- optional minus and fractional part back
            local k
  return minus .. int:reverse():gsub("^,", "") .. fraction
result, k = string.gsub(result, "^(-?%d+)(%d%d%d)", '%1,%2')
if k == 0 then
break
end
end
return result
end
end
 
function p.formatNumber(frame)
local number = frame.args ~= nil and frame.args[1] or frame
return p.formatnum(number)
end
end
 
function p.round(val, maxDigits, minDigits)
function p.round(val, maxDigits, minDigits)
    if(val == nil) then
if val == nil then
        return nil
return nil
    else
else
        if(type(maxDigits) == "table") then
if type(maxDigits) == "table" then
            minDigits = maxDigits[2]
minDigits = maxDigits[2]
            maxDigits = maxDigits[1]
maxDigits = maxDigits[1]
        end
end
 
        local result = val..""
local result = val..""
        local decimals = string.find(result, "%.")
local decimals = string.find(result, "%.")
        if(decimals ~= nil ) then decimals = string.len(result) - decimals else decimals = 0 end
if decimals ~= nil then
decimals = string.len(result) - decimals
        if(maxDigits ~= nil and decimals > maxDigits) then
else
            result = tonumber(string.format("%."..maxDigits.."f", result))
decimals = 0
        elseif(minDigits ~= nil and decimals < minDigits) then
end
            result = string.format("%."..minDigits.."f", result)
 
        end
if maxDigits ~= nil and decimals > maxDigits then
result = string.format("%."..maxDigits.."f", result)
        return result
elseif minDigits ~= nil and decimals < minDigits then
    end
result = string.format("%."..minDigits.."f", result)
end
 
return result
end
end
end
 
--From http://lua-users.org/wiki/SimpleRound
--From http://lua-users.org/wiki/SimpleRound
function p.round2(num, numDecimalPlaces)
function p.round2(num, numDecimalPlaces)
    local mult = 10^(numDecimalPlaces or 0)
local mult = 10^(numDecimalPlaces or 0)
    return math.floor(num * mult + 0.5) / mult
return math.floor(num * mult + 0.5) / mult
end
end
 
-- pre : List is a table or a string
-- pre : List is a table or a string
--      Item is the element that is being searched
--      Item is the element that is being searched
Line 172: Line 224:
-- post: returns a boolean; true if element exists in List, false otherwise
-- post: returns a boolean; true if element exists in List, false otherwise
function p.contains(List, Item, IgnoreCase)
function p.contains(List, Item, IgnoreCase)
    if (List == nil or Item == nil) then  
if List == nil or Item == nil then  
        return false  
return false  
    end
end
    if(IgnoreCase == nil) then  
if IgnoreCase == nil then  
        IgnoreCase = false  
IgnoreCase = false  
    end
end
 
    if(type(List) == "table") then
if type(List) == "table" then
        for key, value in pairs(List) do
for key, value in pairs(List) do
            if (value == Item) then
if value == Item then
                return true
return true, key
            elseif (IgnoreCase and string.upper(value) == string.upper(Item)) then
elseif IgnoreCase and string.upper(value) == string.upper(Item) then
                return true
return true, key
            end
end
        end
end
    else
else
        local start = string.find(List, Item)
local start = string.find(List, Item)
        return start ~= nil
return start ~= nil
    end
end
    return false
return false
end
end
   
   
Line 208: Line 260:
--User:Giga Martin
--User:Giga Martin
function p.trim(str)
function p.trim(str)
  return (str:gsub("^%s*(.-)%s*$", "%1"))
return (str:gsub("^%s*(.-)%s*$", "%1"))
end
end
   
   
Line 220: Line 272:
--      if key contains a nil value
--      if key contains a nil value
function p.hasKey(table, key, length)
function p.hasKey(table, key, length)
    if (length == nil) then
if (length == nil) then
        length = p.tableCount(table)
length = p.tableCount(table)
    end
end
 
    -- iterating through outer table
-- iterating through outer table
    for i = 1, length, 1 do
for i = 1, length, 1 do
        local elem = table[i]  -- storing one of inner tables into a variable
local elem = table[i]  -- storing one of inner tables into a variable
        if (elem[key] ~= nil) then
if (elem[key] ~= nil) then
            return true
return true
        end
end
    end
end
    return false
return false
end
 
-- copies the contents of a variable; handy for when you might want to modify an object taken from a data file
-- or any other read-only variable
-- Stolen from https://gist.github.com/tylerneylon/81333721109155b2d244
function p.clone(obj)
if type(obj) ~= 'table' then return obj end
local res = {}
for k, v in pairs(obj) do res[p.clone(k)] = p.clone(v) end
return res
end
 
-- Euclidean Greatest Common Divisor algorithm
function p.gcd(a, b)
if b ~= 0 then
return p.gcd(b, a % b)
else
return math.abs(a)
end
end
 
--Formats a pair of numbers as a reduced fraction
function p.fraction(n, d)
local gcd = p.gcd(n, d)
return p.formatnum(n/gcd)..'/'..p.formatnum(d/gcd)
end
 
--Similar to p.fraction but returns the simplified numerator and denomerator separately without formatting
function p.fractionpair(n, d)
local gcd = p.gcd(n, d)
return n / gcd, d / gcd
end
 
function p.timeString(timeInSeconds, shorten)
local remain = timeInSeconds
local days, hours, minutes = 0, 0, 0
local isShort = shorten
 
local pieces = {}
 
if remain >= 86400 then
days = math.floor(remain / 86400)
remain = remain - days * 86400
if isShort then
table.insert(pieces, days..'d')
elseif days > 1 then
table.insert(pieces, days..' days')
else
table.insert(pieces, days..' day')
end
end
if remain >= 3600 then
hours = math.floor(remain / 3600)
remain = remain - hours * 3600
if isShort then
table.insert(pieces, hours..'h')
elseif hours > 1 then
table.insert(pieces, hours..' hours')
else
table.insert(pieces, hours..' hour')
end
end
if remain >= 60 then
minutes = math.floor(remain / 60)
remain = remain - minutes * 60
if isShort then
table.insert(pieces, minutes..'m')
elseif minutes > 1 then
table.insert(pieces, minutes..' minutes')
else
table.insert(pieces, minutes..' minutes')
end
end
if remain > 0 then
if isShort then
table.insert(pieces, remain..'s')
elseif remain > 1 then
table.insert(pieces, remain..' seconds')
else
table.insert(pieces, remain..' second')
end
end
return table.concat(pieces, ', ')
end
 
function p.fixPagename(pageName)
local result = pageName
result = string.gsub(result, "%%27", "'")
result = string.gsub(result, "&#39;", "'")
result = string.gsub(result, "&#38;", "&")
return result
end
 
--Checks if two tables contain the same value with the same indices
function p.tablesEqual(t1, t2)
if p.tableCount(t1) ~= p.tableCount(t2) then return false end
for i, val in p.skpairs(t1) do
if type(val) ~= type(t2[i]) then
return false
elseif type(val) == 'table' then
if not p.tablesEqual(val, t2[i]) then return false end
elseif t2[i] ~= val then
return false
end
end
return true
end
 
--Returns a number including the sign, even if positive
function p.numStrWithSign(number)
if number >= 0 then
return '+'..p.formatnum(number)
else
return p.formatnum(number)
end
end
end
 
-- copies the contents of a variable; for copying tables recursively
-- Takes a description template & template data, returning a description with variables populated
-- source: http://lua-users.org/wiki/CopyTable
function p.applyTemplateData(descTemplate, templateData)
-- pre : orig is the original value
     local resultDesc = descTemplate
-- post: returns a copy of the original table if orig is of type
    for k, v in pairs(templateData) do
--      table, including all children tables but not metatables;
        local val = v
--      otherwise returns whatever is contained in orig
        if type(v) == 'number' then
function p.deepCopy(orig)
             val = p.formatnum(val)
     local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
             copy[p.deepCopy(orig_key)] = p.deepCopy(orig_value)
         end
         end
         -- cannot copy metatables of tables loaded in by mw.loadData();
         resultDesc = string.gsub(resultDesc, '${' .. k .. '}', val)
        -- stack overflow error if you uncomment the statement below
        -- setmetatable(copy, p.deepCopy(getmetatable(orig)))
    else -- number, string, boolean, etc
        copy = orig
     end
     end
     return copy
     return resultDesc
end
end
 
return p
return p