Unity
An Elixir unit conversion calculator inspired by the Unix units utility. Uses Localize as the primary engine for unit creation, conversion, arithmetic, and localized output.
Features
-
Parse and evaluate unit expressions:
3 meters to feet,60 mph to km/h. -
Arithmetic on units:
12 ft + 3 in,100 kg * 9.8 m/s^2. -
Built-in functions:
sqrt,cbrt,abs,round,ceil,floor, trig, logarithms. -
Juxtaposition multiplication:
kg m / s^2=(kg * m) / s^2, matching GNUunitsprecedence. -
Rational numbers:
1|3 cup to mL. -
Concatenated exponents:
cm3=cm^3. -
Measurement system conversion:
100 meter to us,100 fahrenheit to metric,to preferred,to imperial,to SI. -
Variables:
let distance = 42.195 km, then reusedistance / time. -
Mixed-unit display:
3.756 hours to h;min;s→3 hours, 45 minutes, 21.6 seconds. -
Locale-aware output: number and unit formatting via
Localize. -
Interactive REPL with
_(previous result),help,list,info,conformable, andlocalecommands. - CLI for single-expression evaluation, piping, and scripting.
Installation
Add unity to your list of dependencies in mix.exs:
def deps do
[
{:unity, "~> 0.1.0"}
]
endLibrary usage
iex> {:ok, result, _env} = Unity.eval("3 meters to feet")
iex> result.value
9.84251968503937
iex> Unity.format!(Unity.eval!("60 mph to km/h"))
"96.56064 kilometers per hour"
iex> Unity.format!(Unity.eval!("100 celsius to fahrenheit"))
"212 degrees Fahrenheit"
iex> {:ok, result, _env} = Unity.eval("3.756 hours to h;min;s")
iex> Unity.format!(result)
"3 hours, 45 minutes, 21.6 seconds"Variables
iex> {:ok, _, env} = Unity.eval("let distance = 42.195 km")
iex> {:ok, _, env} = Unity.eval("let time = 2 hours", env)
iex> {:ok, result, _} = Unity.eval("distance / time", env)
iex> result.name
"kilometer-per-hour"Measurement system conversion
iex> Unity.format!(Unity.eval!("100 meter to us"))
"0.062137 miles"
iex> Unity.format!(Unity.eval!("100 fahrenheit to metric"))
"37.777778 degrees Celsius"
iex> Unity.format!(Unity.eval!("100 meter to imperial"))
"0.062137 miles"
# "preferred" uses the current locale's measurement system
iex> Localize.put_locale(:de)
iex> Unity.format!(Unity.eval!("100 fahrenheit to preferred"))
"37,777778 Grad Celsius"Locale-aware output
iex> result = Unity.eval!("1234.5 meter to kilometer")
iex> Unity.format!(result, locale: :de)
"1,2345 Kilometer"
iex> Unity.format!(result, locale: :ja)
"1.2345 キロメートル"Interactive REPL
$ mix run -e "Unity.Repl.start()"
Unity v0.1.0 — type "help" for commands, "quit" to exit
> 3 meters to feet
9.84252 feet
> 60 mph to km/h
96.56064 kilometers per hour
> 100 kg * 9.8 m/s^2
980 kilogram-meter-per-square-second
> 1 gallon to liters
3.785412 liters
> 12 ft + 3 in to ft
12.25 feet
> sqrt(9 m^2)
3 meters
> _ to cm
300 centimeters
> 1|3 cup to mL
78.862746 milliliters
> 3.756 hours to h;min;s
3 hours, 45 minutes, 21.6 seconds
> let distance = 42.195 km
42.195 kilometers
> let time = 2 hours
2 hours
> distance / time
21.0975 kilometers per hour
> locale de
Locale set to :de
> 1234.5 meter to kilometer
1,2345 KilometerCLI (escript)
Build and install the escript:
mix escript.buildUsage:
# Interactive mode
./unity
# Single conversion
./unity "3 meters to feet"
# Two-argument conversion (GNU units style)
./unity "3 meters" "feet"
# Verbose mode
./unity -v "1 gallon" "liters"
# Terse mode (for scripts)
./unity -t "100 celsius" "fahrenheit"
# Locale-aware output
./unity --locale de "1234.5 meter to kilometer"
# Read from stdin
echo "3 meters" | ./unity - feet
# Pipe-friendly
echo "3 meters to feet" | ./unity
# List unit categories
./unity --list
# List units in a category
./unity --list length
# List conformable units
./unity --conformable meterExpression syntax
| Syntax | Example | Description |
|---|---|---|
| Conversion | 3 meters to feet, 3 m -> cm, 3 m in cm | Convert between units |
| Addition | 12 ft + 3 in | Add compatible units |
| Subtraction | 10 km - 3 km | Subtract compatible units |
| Multiplication | 100 kg * 9.8 m | Multiply units or values |
| Division | 100 m / 10 s, 5 miles per hour |
Divide units, per = / |
| Exponentiation | m^2, s^-2, cm3 | Powers and concatenated exponents |
| Juxtaposition | kg m / s^2 |
Space = implicit *, higher precedence than / |
| Parentheses | (3 + 4) m | Grouping |
| Functions | sqrt(9 m^2), abs(-5 m) | Built-in math functions |
| Rationals | 1|3 cup |
Rational numbers (GNU units style) |
| Variables | let x = 42 km | Variable binding |
| Previous result | _, _ to cm | Refer to last REPL result |
| System target | to metric, to us, to imperial, to SI | Convert to measurement system |
| Preferred | to preferred | Convert to locale's preferred system |
| Mixed-unit | 3.756 hours to h;min;s | Decompose into multiple units |
Operator precedence (highest to lowest)
| Precedence | Operators | Description |
|---|---|---|
| 1 | ^, concatenated exponent | cm^3, m2 |
| 2 | juxtaposition (space) | kg m = kg * m |
| 3 | *, /, per | Explicit multiply/divide |
| 4 | +, - | Add/subtract (conformable units only) |
| 5 | to, in, -> | Conversion (outermost) |
Supported unit aliases
Over 150 common abbreviations are supported, including:
Length: m, km, cm, mm, ft, in, yd, mi, nmi, ly
Mass: g, kg, mg, lb, oz, t, st
Time: s, ms, min, h, d, wk, yr
Temperature: °C, °F, K, celsius, fahrenheit, kelvin
Speed: mph, kph, mps, kn
Volume: L, mL, gal, qt, pt, cup, tbsp, tsp, floz
Energy: J, kJ, cal, kcal, kWh, eV, BTU
Power: W, kW, MW, hp
Pressure: Pa, kPa, atm, psi
Frequency: Hz, kHz, MHz, GHz
Force: N, kN, lbf
And more: area, angle, digital, electric, light, radiation units
All CLDR unit names (meter, kilogram, second, etc.) and SI-prefixed forms (kilometer, milligram, gigahertz, etc.) are accepted directly.
Importing Gnu Units unit definitions
Its possible to directly import many - but not all - of the unit definitions from Gnu Units. A copy of the data is included in the library package but you can specify other locations at import time. Importing Gnu Unit definitions converts the data into Localize.Unit custom units. Only linear units can be imoprts (those of the form ax + b
See Unity.GnuUnitsImporter for more information.
A fun example from history
See https://www.ibiblio.org/harris/500milemail.html. Here's our implementation:
$ iex -S mix
iex(1)> Unity.GnuUnitsImporter.import()
iex(2)> Unity.Repl.start()
Unity v0.2.0 — type "help" for commands, "quit" to exit
> 3 millilightsecond to mile
558.847191 milesReferences
units, the inspiration for
Unity.Numbat s a statically typed programming language for scientific computations with first class support for physical dimensions and units.
License
Apache 2.0 (See LICENSE.md)