1,303
edits
(tableIsEmpty: Initial implementation) |
(Issue finally found...) |
||
(20 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
-- Module that contains all functions regarding numeric formatting and calculations. | |||
-- TODO: Make modules that now call Shared call Number (for relevant functions) | |||
local numModule = require('Module:Number') | |||
--So there are a handful of functions that I'm using in a lot of places | --So there are a handful of functions that I'm using in a lot of places | ||
--So rather than continue to copy across the same handful of functions to every single new module | --So rather than continue to copy across the same handful of functions to every single new module | ||
Line 13: | Line 17: | ||
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 32: | Line 36: | ||
table.sort(keys) | table.sort(keys) | ||
end | end | ||
local i = 0 | local i = 0 | ||
local iterator = function() | local iterator = function() | ||
Line 46: | Line 50: | ||
end | end | ||
-- Function to sort a dictionary-like structure where items are added like tbl['key'] = value | |||
-- We need to turn this structure into a table first, in order to sort it. | |||
function p.sortDictionary(dict, comparer) | |||
local sortedTable = {} | |||
for k, v in pairs(dict) do | |||
table.insert(sortedTable, {key = k, value = v}) | |||
end | |||
table.sort(sortedTable, comparer) | |||
return sortedTable | |||
end | |||
--General purpose function for going through a table after sorting based on a custom sort order | --General purpose function for going through a table after sorting based on a custom sort order | ||
Line 71: | Line 88: | ||
end | end | ||
end | end | ||
-- | -- Takes an input string and returns the same string with title case-like | ||
-- | -- formatting (that is, the first letter of every word becomes uppercase, | ||
-- while the remainder becomes lowercase) | |||
-- Examples: | |||
-- titleCase('ALL CAPS') = 'All Caps' | |||
-- titleCase('all lowercase') = 'All Lowercase' | |||
-- titleCase('A MiXTUre') = 'A Mixture' | |||
-- Note that non-alphanumeric characters are treated as a word boundary, so: | |||
-- titleCase('a!b(c)d') = 'A!B(C)D' (not 'A!b(c)d') | |||
--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) | ||
Line 84: | Line 108: | ||
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 117: | Line 141: | ||
end | 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 131: | Line 155: | ||
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 | local sorter = function(r1, r2) | ||
if ascend then | if ascend then | ||
return r1[sortCol] < r2[sortCol] | return r1[sortCol] < r2[sortCol] | ||
Line 143: | Line 167: | ||
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) | -- @param inputstr (string) The input to separate. | ||
-- @param sep (string/char) The separation character. | |||
-- @param trim (boolean) TRUE to trim the leading/trailing whitespaces | |||
function p.splitString(inputstr, sep, trim) | |||
if sep == nil then | if sep == nil then | ||
sep = "%s" | sep = "%s" | ||
Line 152: | Line 179: | ||
local t = {} | local t = {} | ||
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do | for str in string.gmatch(inputstr, "([^"..sep.."]+)") do | ||
if trim == true then | |||
str = str:gsub("^%s*(.-)%s*$", "%1") | |||
end | |||
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 | ||
Line 162: | Line 192: | ||
return string.sub(string1, 1, string.len(start)) == start | return string.sub(string1, 1, string.len(start)) == start | ||
end | end | ||
--Adds commas | --Adds commas | ||
function p.formatnum(number) | function p.formatnum(number) | ||
return numModule.formatnum(number) | |||
end | end | ||
function p.formatNumber(frame) | function p.formatNumber(frame) | ||
number = frame.args ~= nil and frame.args[1] or frame | local number = frame.args ~= nil and frame.args[1] or frame | ||
return p.formatnum(number) | return p.formatnum(number) | ||
end | end | ||
function p.round(val, maxDigits, minDigits) | function p.round(val, maxDigits, minDigits) | ||
return numModule.round(val, maxDigits, minDigits) | |||
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) | ||
return numModule.round2(num, numDecimalPlaces) | |||
return | |||
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 229: | Line 223: | ||
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 | ||
Line 274: | Line 268: | ||
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 | ||
Line 284: | Line 278: | ||
return false | return false | ||
end | end | ||
-- copies the contents of a variable; handy for when you might want to modify an object taken from a data file | -- 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 | -- or any other read-only variable | ||
Line 292: | Line 286: | ||
local res = {} | local res = {} | ||
for k, v in pairs(obj) do res[p.clone(k)] = p.clone(v) end | for k, v in pairs(obj) do res[p.clone(k)] = p.clone(v) end | ||
return res | |||
end | |||
-- Shallow clone, desirable when operations such as sorting are to be performed | |||
-- on a table where it is not necessary to perform a deep clone of all data within | |||
-- the table's elements | |||
function p.shallowClone(obj) | |||
if type(obj) ~= 'table' then return obj end | |||
local res = {} | |||
for k, v in pairs(obj) do | |||
res[k] = v | |||
end | |||
return res | return res | ||
end | end | ||
Line 297: | Line 303: | ||
-- Euclidean Greatest Common Divisor algorithm | -- Euclidean Greatest Common Divisor algorithm | ||
function p.gcd(a, b) | function p.gcd(a, b) | ||
return numModule.gcd(a, b) | |||
end | end | ||
--Formats a pair of numbers as a reduced fraction | --Formats a pair of numbers as a reduced fraction | ||
function p.fraction(n, d) | function p.fraction(n, d) | ||
return numModule.fraction(n, d) | |||
end | end | ||
--Similar to p.fraction but returns the simplified numerator and denomerator separately without formatting | --Similar to p.fraction but returns the simplified numerator and denomerator separately without formatting | ||
function p.fractionpair(n, d) | function p.fractionpair(n, d) | ||
return numModule.fractionpair(n, d) | |||
end | end | ||
Line 372: | Line 372: | ||
result = string.gsub(result, "%%27", "'") | result = string.gsub(result, "%%27", "'") | ||
result = string.gsub(result, "'", "'") | result = string.gsub(result, "'", "'") | ||
result = string.gsub(result, "&", "&") | |||
return result | return result | ||
end | end | ||
Line 392: | Line 393: | ||
--Returns a number including the sign, even if positive | --Returns a number including the sign, even if positive | ||
function p.numStrWithSign(number) | function p.numStrWithSign(number) | ||
if number | return numModule.numStrWithSign(number) | ||
return ' | end | ||
-- Applies formatting to an error message for display on wiki pages. | |||
-- Also appends a category such that errors can be easily located | |||
function p.printError(message) | |||
-- Prevent message being interpreted as wikitext and handle non-string messages | |||
local messageString = mw.text.nowiki(type(message) == 'string' and message or mw.dumpObject(message)) | |||
return '[[Category:Pages with script errors]]<div class="text-negative">ERROR: ' .. messageString .. '</div>' | |||
end | |||
-- Takes a description template & template data, returning a description with variables populated | |||
function p.applyTemplateData(descTemplate, templateData) | |||
local resultDesc = descTemplate | |||
for k, v in pairs(templateData) do | |||
local val = v | |||
if type(v) == 'number' then | |||
val = p.formatnum(val) | |||
end | |||
resultDesc = string.gsub(resultDesc, '${' .. k .. '}', val) | |||
end | |||
return resultDesc | |||
end | |||
-- Given a namespace & local ID, returns a namespaced ID | |||
function p.getNamespacedID(namespace, localID) | |||
if string.find(localID, ':') == nil then | |||
return namespace .. ':' .. localID | |||
else | |||
-- ID already appears to be namespaced | |||
return localID | |||
end | |||
end | |||
-- Given a namespaced ID, returns both the namespace & local ID | |||
function p.getLocalID(ID) | |||
local namespace, localID = nil, nil | |||
local sepIdx = string.find(ID, ':') | |||
if sepIdx == nil then | |||
-- Provided ID doesn't appear to be namespaced | |||
localID = ID | |||
else | else | ||
namespace = string.sub(ID, 1, sepIdx - 1) | |||
localID = string.sub(ID, sepIdx + 1, string.len(ID)) | |||
end | end | ||
return namespace, localID | |||
end | |||
-- Compares two strings, optionally ignoring case | |||
function p.compareString(left, right, ignoreCase) | |||
-- Both are nil (equal) | |||
if left == nil and right == nil then return true end | |||
-- Only one is nil (not equal) | |||
if left == nil or right == nil then return false end | |||
-- Convert inputs to strings, just in case | |||
left = tostring(left) | |||
right = tostring(right) | |||
if ignoreCase == true then | |||
return left:upper() == right:upper() | |||
else | |||
return left == right | |||
end | |||
end | |||
function p._replace(str, searchTerm, replacementTerm) | |||
if str == nil then | |||
return str | |||
end | |||
local escapedSearch = searchTerm:gsub("[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%1") | |||
local result = str:gsub(escapedSearch, replacementTerm) | |||
return result | |||
end | |||
function p.replace(frame) | |||
local args = frame:getParent().args | |||
return p._replace( | |||
frame.args[1], | |||
frame.args[2] or '', | |||
frame.args[3] or '') | |||
end | end | ||
return p | return p |
edits