ATTENTION! The process of updating WiKi to version Eco 10.x has begun. Those wishing to participate can find out more Information on our ECO Contribution Wiki Discord.
From April 26 to May 12, errors may occur in the Wiki, as we will be carrying out a major update to the information processing modules.

Module:Unit

From Eco - English Wiki

This Lua module provides the backend functionality for Template:Unit. Unit definitions are loaded from Module:Unit/data.


local p = {}
local Utils = require("Module:Utils")
local UnitsData = mw.loadData("Module:Unit/data")
local HTMLUtils = require("Module:UtilsHTML")

--- Find a definition for a unit measurement with the given case sensitive abbreviation and return a HTML <code>abbr</code> tag with the appropriate unit details.
--
-- Most abbreviations are <strong>case sensitive</strong> to differentiate between the milli- and mega- prefixes for example (e.g., millihertz (mHz) and megahertz (MHz)), but about a third of the abbreviations are not.
-- Non-case sensitivity is simply provided as an <em>ease of use</em> feature in the case that user mistypes a unit (e.g., writing "MO" instead of "mo" for month): the only way to truly know if a unit is or is not case sensitive is to read the module data file.
--
-- For example the meter per second abbreviation ("m/s" or "mps") is not case sensitive as there is no other unit defined by just the letter "m".
-- All units that contain a forward slash (e.g., "rad/s" radian per second) can be written with the character "p" replacing the slash. So "radps" and "rad/s" are equivalent.
-- @param #string abbr Abbreviation for a unit. This should be treated as case sensitive because <strong>most</strong>, but not all, units are case sensitive.
-- @return #table Unit abbreviation data.
-- @author User:Demian
-- @see _unit
-- @usage getUnit("kWh") = { "kW&sdot;h", { "kilowatt-hour", "kilowatt-hours" } }
-- @usage getUnit("ppm") = { "ppm", { "part per million", "parts per million" } }
-- @usage getUnit("GiB") = { "GiB", { "gibibyte", "gibibytes" } }
function p.getUnit(abbr)
	local abbrKey = tostring(abbr)
	local unitData = UnitsData["caseSensitiveUnits"][abbrKey]

	if not unitData then
		-- All case insensitive unit abbreviations are lower case, the user written abbreviation may not be.
		abbrKey = mw.ustring.lower(abbrKey)
		unitData = UnitsData["caseInsensitiveUnits"][abbrKey]
	end

	return unitData
end

--- Find a definition for a unit measurement with the given case sensitive abbreviation and return a HTML <code>abbr</code> tag with the appropriate unit details.
-- @param #string number Numerical value to format with a thousands separator. Optional.
-- @param #string abbr Case sensitive abbreviation for a unit. Optional.
-- @param #bool plural Override abbreviation plurality. If <code>nil</code>, determine plurality from number. Optional. Default: <code>nil</code>
-- @return #string "<code>number</code> <code>abbr</code>" where <code>number</code> is formatted with a thousands separator and <code>abbr</code> is an HTML abbr element, if a unit definition was found.
-- @return #string "<code>number</code>" with whitespace trimmed if <code>abbr</code> was undefined and no unit definition is found for <code>number</code>.
-- @return #string An HTML abbr element, if a unit definition was found for <code>number</code>.
-- @return #string "<code>number</code>" formatted with a thousands separator if <code>abbr</code> was undefined and no unit definition is found for <code>number</code>.
-- @return #string "" if both <code>number</code> and <code>abbr</code> evaluate as <code>false</code>.
-- @author User:Demian
-- @see getUnit
-- @usage _unit("kWh") = "<abbr title="kilowatt-hour">kW&sdot;h</abbr>"
-- @usage _unit(nil, "ppm", true) = "<abbr title="parts per million">ppm</abbr>"
-- @usage _unit("GiB") = "<abbr title="gibibyte">GiB</abbr>"
-- @usage _unit(-1200.34, "MHz", false) = "-1 200.34 <abbr title="megahertz">MHz</abbr>"
-- @usage _unit("123456789", "kg") = "123 456 789 <abbr title="kilograms">kg</abbr>"
function p._unit(number, abbr, plural)
	local unitData = nil
	local pluralIdx = 1

	if true == plural then
		pluralIdx = 2
	end

	if number and abbr then
		-- Has both.
		-- This can be done through the template or Lua.

		unitData = p.getUnit(abbr)

		if unitData then
			-- Check if number is 1, otherwise use plural.
			if nil == plural then
				local num = tonumber(number)
				pluralIdx = (1 == num or -1 == num) and 1 or 2
			end

			abbr = HTMLUtils.tagAbbr(unitData[1], unitData[2][pluralIdx])
		end

		return mw.ustring.format("%s %s", Utils.formatNumber(number), abbr)
	elseif number and not abbr then
		-- Only has number.
		-- This is a likely use case from the template.

		-- Try to get it as a unit instead.
		unitData = p.getUnit(number)

		if unitData then
			-- No number given, just return the unit.
			return HTMLUtils.tagAbbr(unitData[1], unitData[2][pluralIdx])
		else
			-- Did not find it as unit, assume it is a unitless number.
			return Utils.formatNumber(number)
		end
	elseif not number and abbr then
		-- Only has unit but no number.
		-- This is an invalid use case from the template, expecting use through Lua.

		unitData = p.getUnit(abbr)

		if unitData then
			abbr = HTMLUtils.tagAbbr(unitData[1], unitData[2][pluralIdx])
		end

		-- Else did not find it as unit, don't know what to do, return it back unchanged.
		return abbr
	else
		-- Has neither.
		return ""
	end
end

function p.unit(frame)
	local args = Utils.normaliseArgs(frame)
	return p._unit(args[1], args[2])
end

return p