Module:Road data/util

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 `overwrite` is not true
-- and any key in `arr` is already in `target`.
function util.addAll(target, arr, overwrite)
	if type(target) ~= "table" then
		error("target is not a table")
	end
	for key,value in pairs(arr) do
		if overwrite or 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 convert(distance, multiplier, desiredPrec)
	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
	-- This function rounds a given number to the given number of digits.
	local round = math._precision_format

	local prec = desiredPrec or precision(distance)
	if not desiredPrec then
		local ord = order(distance)
		-- Adjust precision based on multiplier, as done in {{convert}}.
		prec = prec - order(multiplier / 0.2)
	end

	local converted = distance * multiplier
	local magnitude = order(converted)
	if prec <= -magnitude then
		-- Ensure the result has at least two significant digits.
		prec = -magnitude + 1
	end
	return round(converted, 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 = convert(mi, kmPerMile, prec)
			m = convert(mi, kmPerMile * 1000, prec)
			-- 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 = convert(km, 1 / kmPerMile, prec)
			ft = convert(km, ftPerMile / kmPerMile, prec)
			-- 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

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.