Module:Shared

--- Shared contains useful utilities, including extensions of STL libraries.

-- --  On this Wiki, Shared is used in: -- * Module:Amulets -- --  @module     shared -- @alias      p --  @author     FINNER -- @author     Cephalon Scientia -- @attribution    Falterfire -- @attribution    Cephalon Scientia -- @attribution    FINNER -- @attribution    Gigamicro -- @attribution    NoBrainz -- @image -- @require    Module:Math -- @require    Module:String -- @require    Module:Arguments -- @release    stable -- local p = {}

-- Module Dependencies  --- -- TODO: Add math and string variables to package so other modules that require M:Shared can access -- STL extension functions via shared.math.func syntax? local math = require(Module:Math); local string = require(Module:String); -- local table = require('Module:Table');  -- M:Tables is next STL extension library to be added local Args = require('Dev:Arguments');

-- Adding M:Math functions to M:Shared package for k, v in pairs(math) do p[k] = v end

-- Adding M:String functions to M:Shared package for k, v in pairs(string) do p[k] = v end

--- For getting frame or parent arguments. -- @function       p.getArgs -- @param          {table} frame The input arguments -- @param          {table} options Options for getting the args -- @return         {table} The arguments function p.getArgs(frame, options) if type(frame[1]) == 'table' and table.getn(frame) < 2 then frame = frame[1]; end if type(options) ~= 'table' then options = {options}; end local args = Args.getArgs(frame, options); local tempArgs = {}; local str; if options.replace then for i, v in pairs(args) do           if type(i) ~= 'number' or type(v) ~= 'string' then tempArgs[i] = v;            else str = '('..math.replace(v)..')'; if options.eval then tempArgs[i] = tonumber(math.eval(str)); else tempArgs[i] = str; end end end args = tempArgs; end local j = 1; tempArgs = {}; if options.noNil then for i, v in pairs(args) do           if type(i) ~= 'number' then tempArgs[i] = v;            elseif v then tempArgs[j] = v; j = j + 1; end end args = tempArgs; end return args; end

-- TODO: Extract value finding in a table functionality into a separate function. Call it hasValue -- Right now function name conflicts with M:String's contains --- Checks if a string is in a table or is a substring of a string -- @function       p.contains -- @param          {table, string} list A table or a string -- @param          {string} item The element that is being searched for -- @param          {boolean} ignoreCase If false, search is case-sensitive; true otherwise -- @return         {boolean} True if element exists in List, false otherwise function p.contains(list, item, ignoreCase) if (list == nil or item == nil) then return false end if (ignoreCase == nil) then ignoreCase = false end if (type(list) == "table") then for _, value in pairs(list) do           if (value == item) then return true elseif (ignoreCase and string.upper(value) == string.upper(item)) then return true end end else local start = string.find(list, item) return start ~= nil end return false end

--- Iterator sorted by keys.

-- For example, for a table `data = {["Cat"] = 5, ["Bat"] = 4, ["Hat"] = 7 }`

-- `for k, v in skpairs(data) do print(('k="$s", v=%d'):format(k, v)) end`

-- would loop through: k="Bat", v=4 k="Cat", v=5 k="Hat", v=7

-- By u:gigamicro -- @function       p.skpairs -- @param          {table} t A table to be sorted -- @param          {boolean} sortDescending If true, sort by descending order; false otherwise -- @return         {function} Sorted iterators function p.skpairs(t, sortType) local keys = {} for k in pairs(t) do keys[#keys + 1] = k end if type(sortType) == 'function' then table.sort(keys, sortType)--custom sort (always applied to keys) elseif sortType then--descending table.sort(keys, function(a, b) return a > b end) else table.sort(keys)--implicit <, function(a, b) return a < b end)>   end

local invkeys = {} for i, k in ipairs(keys) do       invkeys[k]=i end

return function(tab, k)       local key = tab[2][(tab[1][k] or 0)+1] return key, t[key] end, {invkeys,keys}, startingkey end

--Loops through all the Relic types --Comes up a surprising amount --rework 11/9/2020 by u:gigamicro -- TODO: Move Shared.relicLoop to in M:Void or M:VoidByReward function p.relicLoop return function(_, lastTier) return ({ ['']='Lith', ['Lith']='Meso', ['Meso']='Neo', ['Neo']='Axi' })[lastTier] end, _, '' end

function p.consoleLoop return function(_, lastTier) return ({['']='PC', ['PC']='PS4', ['PS4']='XB1', ['XB1']='NSW'})[lastTier] end, _, '' end

--- Returns the number of elements/entries in a table. -- Originally from Module:VoidByReward written by User:NoBrainz. -- @function       p.tableCount -- @param          {table} table A table with no explicit nil values -- @return         {number} The size of table, ignoring keys with nil values and --                          nil values themselves function p.tableCount(table) assert(type(table) == 'table', 'p.tableCount(table): table is not of type "table"') local count = 0 for _ in pairs(table) do count = count + 1 end return count end

--- Returns the number of indexed elements in a table. -- @function       p.indexCount -- @param          {table} t A table with no explicit nil values -- @return         {number} The number of indexed elements in a table; --                          if table is not of type 'table' then return nil function p.indexCount(t) if (type(t) == 'table') then local count = 0 for _ in ipairs(t) do count = count + 1 end return count else return nil end end

--- Sorts a table based on the listed column. -- @function       p.tableSort -- @param          {table} t Table to be sorted -- @param          {string} sortCol Name of column to be sorted by --  @param          {boolean} sortAscend If true, sorts in ascending order by specified column; false otherwise function p.tableSort(t, sortCol, sortAscend) local function comparator(r1, r2) if sortAscend then return r1[sortCol] < r2[sortCol] else return r1[sortCol] > r2[sortCol] end end table.sort(t, comparator) end

--- Checks to see if a key exists in a given nested table. -- @function       p.hasKey -- @param          {string} table A nested table -- @param          {string} key Key name -- @param          {number} length Represents the size of outer table (optional) -- @return         {boolean} True if key exists in table, false otherwise or if key contains a nil value function p.hasKey(table, key, length) if (length == nil) then length = p.tableCount(table) end -- iterating through outer table for i = 1, length, 1 do       local elem = table[i]   -- storing one of inner tables into a variable if (elem[key] ~= nil) then return true end end return false end

--upk by User:gigamicro, sanitizes any object to a string do local conversion = { string=function(v) v = v:gsub('\n','\\n'):gsub('%c',function(s) return '\\'..s:byte end) if not v:match"'" then return "'"..v.."'" elseif not v:match '"' then                return '"'..v..'"'             else                 local n=0; while v:match(']'..(('='):rep(n))..']') do n=n+1 end; local s = (('='):rep(n)); return table.concat{'[',s,'[',v,']',s,']'}            end            end,        boolean=function(v) return v and 'true' or 'false' end,        number=function(v) return tostring(v) end,        table=function(v, linedepth)            local str = {'{'}            local index = 1            if linedepth and linedepth > 0 then table.insert(str, '\n') end            for k,val in pairs(v) do                 --print (k, '(', type(val), ')')                if k==index then index=index+1 else table.insert(str, '['..p.upk(k)..'] = ') end                if v ~= val and k~='_G' and k~='loaded' then                    table.insert(str, p.upk(val, linedepth and linedepth>0 and linedepth-1))                else table.insert(str, ' ') end --print (k,'=',str[#str]) table.insert(str, ', ') if linedepth and linedepth>0 then table.insert(str, '\n') end end table.insert(str,'}') --if print then print (table.concat(str)) end return table.concat(str) end, ['function'] = function return ' ' end,--functionend' end, ['nil']     = function return 'nil' end, userdata    = function return ' ' end, thread      = function return ' ' end, }

function p.upk(v, linedepth) return conversion[type(v)](v,linedepth) end --(conversion[type(v)..'e'] or function(v,ld) error(type(v)..' is not a recognized type') end)(v, linedepth or 0) end end--upk

-- @function       p.Cache -- @author         Gigamicro -- @param          {string} s --  @return         {string} function p.Cache(frame) return p.upk(require(frame.args[1])[frame.args[2]][frame.args[3]]) end

return p