Unitwise-193
This is a fork of Josh W Lewis's very cool Unitwise library. I've pushed it as a gem so that I can use it in a few situations where a git source isn't possible.
Currently the only differences are that I've dropped support for ruby's pre 1.9.3 so I could upgrade dependencies as they were causing conflicts with other gems.
Primarily this upgrades parslet and nori. If you can use the stock unitwise gem I highly recommend it.
Normal readme follows.
![Code Climate](http://img.shields.io/codeclimate/github/wizarddevelopment/unitwise.svg?style=flat)
Unitwise is a Ruby library for unit measurement conversion and math.
For an over the top example, consider a car (2800 lb) completing the quarter
mile in 10 seconds (with uniform acceleration).
distance = 0.25.mile
time = 10.second
mass = 2800.pound
acceleration = 2.0 * distance / time ** 2
force = (mass * acceleration).to_lbf
power = (force * distance / time).to_horsepower
speed = ((2.0 * acceleration * distance) ** 0.5).convert_to("mile/hour")
RubyTapas subscribers can also view a screencast:
225-Unitwise
Rationale
Unitwise is based on the Unified Code for Units of Measure(UCUM),
which aims to maintain a cross-platform list of units and their conversions.
This gives Unitwise a few key advantages:
-
An enormous list of units. At the time of writing, there are 96 metric units,
211 non-metric units, and 24 unit prefixes. Whatever unit/units you need, they
are here.
-
An accurate and up to date set of units. The units, prefixes, and conversions
are maintained by UCUM, and are imported into this library with a rake task.
One of the objectives of Unitwise was that it should comprehend any combination
of units. For instance it needed to understand that a unit of
'kilogram.(meter/second)2' was equivalent to 'kilogram.meter.(meter/second2)'.
This resulted in two unique features:
-
An expression grammar built with a PEG parser. This makes expression
parsing more efficient and allows nested parentheses. For example, this is possible: '(kilogram.(meter/second)2)2'
-
Smart compatibility detection. Each unit is reduced down to its most elementary
atoms to determine compatibility with another unit. For example, it knows that
'meter/second2' should be considered compatible with 'kilogram.foot.minute-2/pound'.
Usage
Initialization:
Measurements can be instantiated with Unitwise()
.
require 'unitwise'
Unitwise(2.3, 'kilogram')
Unitwise(100, 'pound')
Unitwise doesn't mess with the core library by default. However, you can
optionally require the core extensions for some handy helpers.
require 'unitwise/ext'
1.convert_to('liter')
4.teaspoon
Conversion
Unitwise is able to convert any unit within the UCUM spec to any other
compatible unit.
5.0.kilometer.convert_to('mile')
The prettier version of convert_to(unit)
is appending the unit code, name, etc.
to a to_
message name.
Unitwise(26.2, 'mile').to_kilometer
Comparison
It also has the ability to compare measurements with the same or different units.
12.inch == 1.foot
1.meter > 1.yard
Again, you have to compare compatible units. For example, comparing two
temperatures will work, comparing a mass to a length would fail.
SI abbreviations
You can use shorthand for SI units.
1000.m == 1.km
1.ml == 0.001.l
Complex Units
Units can be combined to make more complex ones. There is nothing special about
them -- they can still be converted, compared, or operated on.
speed = Unitwise(60, 'mile/hour')
speed.convert_to('m/s')
Exponents and parenthesis are supported as well.
Unitwise(1000, 'kg.s-1.(m/s)2').to_kilowatt
Math
You can add or subtract compatible measurements.
2.0.meter + 3.0.inch - 1.0.yard
You can multiply or divide measurements and numbers.
110.volt * 2
You can multiply or divide measurements with measurements.
20.milligram / 1.liter
Exponentiation is also supported.
(10.cm ** 3).to_liter
Unit Names and Atom Codes
This library is based around the units in the UCUM specification, which is
extensive and well thought out. However, not all of our unit systems throughout
the world and history are consistent or logical. UCUM has devised a system where
each unit has a unique atom code to try and solve this. The previous code examples
don't show this, because for the most part you won't need it. Unitwise can
figure out most of the units by their name or symbol. If you find you need to
(or just want to be explicit) you use the UCUM atom codes without any
modification.
Just for example, you can see here that there are actually a few versions of inch
and foot:
Unitwise(1, '[ft_i]') == Unitwise(1, '[ft_us]')
Unitwise(3, '[in_br]') == Unitwise(3, '[in_i]')
Available Units
If you are looking for a particular unit, you can search with a string or
Regexp.
Unitwise.search('fathom')
You can also get the official list from the UCUM website in XML format at
unitsofmeasure.org/ucum-essence.xml
or a YAML version within this repo
github.com/joshwlewis/unitwise/tree/master/data.
UCUM designations
UCUM defines several designations for it's units: names
,
primary_code
, secondary_code
, and symbol
. You can see them all when
inspecting an atom:
Unitwise::Atom.all.sample
When initializing a measurement, you can use any of the designations:
Unitwise(1, '[Btu]') == Unitwise(1, 'British thermal unit')
Unitwise(1, 'btu') == Unitwise(1, "[BTU]")
When inspecting or printing (to_s
) that measurement, it will remember the
desigation you used. However, if you want to print it with another designation,
that's also possible:
temperature = Unitwise(10, "Cel")
temperature.to_s
temperature.to_s(:names)
temperature.to_s(:symbol)
There is on caveat here. You must use the same designation for each atom in a
complex unit. Meaning you can't mix designations within a unit.
Unitwise(1, "m/s")
Unitwise(1, "meter/second")
Unitwise(1, "meter/s")
Unitwise(1, "meter") / Unitwise(1, "s")
Supported Ruby Versions
This library aims to support and is tested against the following Ruby
implementations:
If something doesn't work on one of these versions, it's a bug.
This library may inadvertently work (or seem to work) on other Ruby versions or
implementations, however support will only be provided for the implementations
listed above.
Installation
Add this line to your application's Gemfile:
gem 'unitwise'
And then execute:
$ bundle
Or install it yourself as:
$ gem install unitwise
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request