Module:Road data/util: Difference between revisions
Appearance
Content deleted Content added
m Removed continuation. |
m Added safeguard code. |
||
Line 9: | Line 9: | ||
-- An error is raised if any key in `arr` is already in `target`. |
-- An error is raised if any key in `arr` is already in `target`. |
||
function util.addAll(target, arr) |
function util.addAll(target, arr) |
||
if type(target) ~= "table" then |
|||
error("target is not a table") |
|||
end |
|||
for key,value in pairs(arr) do |
for key,value in pairs(arr) do |
||
if target[key] == nil then |
if target[key] == nil then |
||
Line 22: | Line 25: | ||
local t2 = type(e2) |
local t2 = type(e2) |
||
if t1 ~= t2 then return t1 < t2 end |
if t1 ~= t2 then return t1 < t2 end |
||
if t1 == "function" then |
|||
error("Unexpected function type") |
|||
end |
|||
return e1 < e2 |
return e1 < e2 |
||
end |
end |
||
Line 27: | Line 33: | ||
local arrayToStringAux |
local arrayToStringAux |
||
arrayToStringAux = function(arr, indent) |
arrayToStringAux = function(arr, indent) |
||
if type(arr) ~= "table" then |
|||
error("arr is not a table") |
|||
end |
|||
if type(indent) ~= "number" then |
|||
error("indent is not a number") |
|||
end |
|||
local result = {} |
local result = {} |
||
local keys = {} |
local keys = {} |
||
Line 63: | Line 75: | ||
local function convertedPrecision(distance, multiplier) |
local function convertedPrecision(distance, multiplier) |
||
if type(distance) ~= "string" then |
|||
error("distance is not a string") |
|||
end |
|||
if type(multiplier) ~= "number" then |
|||
error("multiplier is not a number") |
|||
end |
|||
-- Import math functions. |
-- Import math functions. |
||
local math = require "Module:Math" |
local math = require "Module:Math" |
||
Line 83: | Line 101: | ||
Convert length specified in one unit (mi or km) to length in the other unit. |
Convert length specified in one unit (mi or km) to length in the other unit. |
||
@param #map<#string, #string> lengths |
@param #map<#string, #string> lengths |
||
a map from unit to distance (as a string) in that unit |
a map from unit to distance (as a string) in that unit; |
||
may contain entry `prec` indicating desired conversion precision |
|||
@param #string blank text to be used if length is unspecified |
@param #string blank text to be used if length is unspecified |
||
@return #table a table containing the conversion result: |
@return #table a table containing the conversion result: |
||
⚫ | |||
⚫ | |||
orig = source unit; |
orig = source unit; |
||
comp = target unit; |
comp = target unit; |
||
⚫ | |||
ft = converted length in feet; |
|||
⚫ | |||
m = converted length in meters; |
|||
error = error message, if any |
error = error message, if any |
||
]] |
]] |
||
Line 177: | Line 198: | ||
--- Generates wikitext error messages. |
--- Generates wikitext error messages. |
||
function util.err(msg) |
function util.err(msg) |
||
if msg == nil then |
|||
error("Unspecified error message") |
|||
end |
|||
return format('<strong class="error">Error: %s</strong>', msg) |
return format('<strong class="error">Error: %s</strong>', msg) |
||
end |
end |
Revision as of 16:43, 11 May 2016
![]() | 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)
if type(target) ~= "table" then
error("target is not a table")
end
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
if t1 == "function" then
error("Unexpected function type")
end
return e1 < e2
end
local arrayToStringAux
arrayToStringAux = function(arr, indent)
if type(arr) ~= "table" then
error("arr is not a table")
end
if type(indent) ~= "number" then
error("indent is not a number")
end
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, multiplier)
if type(distance) ~= "string" then
error("distance is not a string")
end
if type(multiplier) ~= "number" then
error("multiplier is not a number")
end
-- 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
-- Adjust precision based on multiplier, as done in {{convert}}.
prec = prec - order(multiplier / 0.2)
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;
may contain entry `prec` indicating desired conversion precision
@param #string blank text to be used if length is unspecified
@return #table a table containing the conversion result:
orig = source unit;
comp = target unit;
mi = length in miles;
ft = converted length in feet;
km = length in kilometers;
m = converted length in meters;
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
-- This function returns the precision of a given string representing a number.
local precision = math._precision
local kmPerMile = 1.609344
local ftPerMile = 5280
-- 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 ft
local m
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_ = mi_ * kmPerMile
km = round(km_, prec or convertedPrecision(mi, kmPerMile))
m = round(km_ * 1000,
prec or convertedPrecision(mi, kmPerMile * 1000))
-- format mi (insert separators as in 1,000)
mi = round(mi_, precision(mi))
else
-- `mi` is not a number.
km = blank
m = 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, 1 / kmPerMile))
ft = round(km_ * ftPerMile / kmPerMile,
prec or convertedPrecision(km, ftPerMile / kmPerMile))
-- format km (insert separators as in 1,000)
km = round(km_, precision(km))
else
-- `km` is not a number.
mi = blank
ft = blank
end
else
mi = blank
ft = blank
km = blank
m = blank
end
local error = concat(errMsg)
if error == "" then error = nil end
return {mi = mi, ft = ft, km = km, m = m, orig = orig, comp = comp,
error = error}
end
--- Generates wikitext error messages.
function util.err(msg)
if msg == nil then
error("Unspecified error message")
end
return format('<strong class="error">Error: %s</strong>', msg)
end
return util