local util = {}
local insert = table.insert
local concat = table.concat
local format = mw.ustring.format
---
-- Add all entries in `arr` into `target`.
-- An error is raised if any key in `arr` is already in `target`.
function util.addAll(target, arr)
for key,value in pairs(arr) do
if target[key] == nil then
target[key] = value
else
error("Duplicate key: " .. tostring(key))
end
end
end
local function comp(e1, e2)
local t1 = type(e1)
local t2 = type(e2)
if t1 ~= t2 then return t1 < t2 end
return e1 < e2
end
local arrayToStringAux
arrayToStringAux = function(arr, indent)
local result = {}
local keys = {}
for key in pairs(arr) do insert(keys, key) end
table.sort(keys, comp)
for _,key in ipairs(keys) do
local value = arr[key]
local keyPrint
if type(key) == "string" then
keyPrint = format("\"%s\"", key)
else
keyPrint = tostring(key)
end
local valuePrint
if type(value) == "table" then
valuePrint = format("{\n%s\n%s}",
arrayToStringAux(value, indent + 4),
string.rep(" ", indent))
elseif type(value) == "string" then
valuePrint = format("\"%s\"", value)
else
valuePrint = tostring(value)
end
insert(result, format("%s[%s] = %s",
string.rep(" ", indent),
keyPrint,
valuePrint))
end
return concat(result, ", \n")
end
--- Return a string representation of `arr`.
function util.arrayToString(arr, indent)
return arrayToStringAux(arr, indent or 0)
end
local function convertedPrecision(distance)
-- Import math functions.
local math = require "Module:Math"
-- This function returns the precision of a given string representing a number.
local precision = math._precision
-- This function returns the order of magnitude of a given string representing a number.
local order = math._order
local prec = precision(distance)
local ord = order(distance)
if prec == -ord then
-- If the distance has only one significant digit, add a digit to the precision.
prec = prec + 1
end
return prec
end
--[[-
Convert length specified in one unit (mi or km) to length in the other unit.
@param #map<#string, #string> lengths
a map from unit to distance (as a string) in that unit
@param #string blank text to be used if length is unspecified
@param cont if specified, a function to be applied to the result before returned
@return #table a table containing the conversion result:
mi = length in miles;
km = length in kilometers;
orig = source unit;
comp = target unit;
error = error message, if any
]]
function util.convertLengths(lengths, blank, cont)
-- Import math functions.
local math = require "Module:Math"
-- In Lua, storing functions locally results in more efficient execution.
-- This function rounds a given number to the given number of digits.
local round = math._precision_format
local kmPerMile = 1.609344
-- The length in kilometers as passed to the function.
local km = lengths.km
-- The length in miles as passed to the function.
local mi = lengths.mi
-- Precision for the converted length.
local prec = lengths.prec
local errMsg = {}
-- Sanitize inputs.
local km_ = tonumber(km)
if km and not km_ then
insert(errMsg, util.err("km is not a number"))
end
local mi_ = tonumber(mi)
if mi and not mi_ then
insert(errMsg, util.err("mi is not a number"))
end
local prec_ = tonumber(prec)
if prec and not prec_ then
insert(errMsg, util.err("prec is not a number"))
end
prec = prec_
local orig = "mi"
local comp = "km"
if mi and km then
insert(errMsg, util.err("Both mi and km are specified"))
elseif mi then
-- Length in miles was passed.
if mi_ then
-- If `mi` is indeed a number, compute and round the length in kilometers.
km = round(mi_ * kmPerMile, prec or convertedPrecision(mi))
else
-- `mi` is not a number.
km = blank
end
elseif km then
-- Length in kilometers was passed.
-- Swap units.
orig, comp = comp, orig
if km_ then
-- If `km` is indeed a number, compute and round the length in miles.
mi = round(km_ / kmPerMile, prec or convertedPrecision(km))
else
-- `km` is not a number.
mi = blank
end
else
mi = blank
km = blank
end
local error = concat(errMsg)
if error == "" then error = nil end
cont = cont or function(x) return x end
return cont({mi = mi, km = km, orig = orig, comp = comp, error = error})
end
--- Generates wikitext error messages.
function util.err(msg)
return format('<strong class="error">Error: %s</strong>', msg)
end
return util