Module:Road data/util
Appearance
![]() | This module is rated as ready for general use. It has reached a mature form and is thought to be relatively bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
![]() | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
![]() | This Lua module is used on approximately 42,000 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them. |
Collection of utility functions for use within Module:Road data modules. See the code for function usages. Exported functions are: addAll
, arrayToString
, convertLengths
and err
.
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
@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)
-- 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.
if km and not tonumber(km) then
insert(errMsg, util.err("km is not a number"))
end
if mi and not tonumber(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.
-- The first step is to convert `mi` (as a string) into a number.
local n = tonumber(mi)
if n then
-- If `mi` is indeed a number, compute and round the length in kilometers.
km = round(n * 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
-- The first step is to convert `km` (as a string) into a number.
local n = tonumber(km)
if n then
-- If `km` is indeed a number, compute and round the length in miles.
mi = round(n / 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
return {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