Ruby Units

Version: 0.2.3

Kevin C. Olbrich, Ph.D.

www.sciwerks.com

Project page: rubyforge.org/projects/ruby-units

Introduction

Many technical applications make use of specialized calculations at some point. Frequently, these calculations require unit conversions to ensure accurate results. Needless to say, this is a pain to properly keep track of, and is prone to numerous errors.

Solution

The ‘Ruby units’ gem is designed so simplify the handling of units for scientific calculations. The units of each quantity are specified when a Unit object is created and the Unit class will handle all subsequent conversions and manipulations to ensure an accurate result.

Installation:

This package may be installed using:

gem install ruby-units

Usage:

unit = Unit.new("1")             # constant only
unit = Unit.new("mm")            # unit only (defaults to a value of 1)
unit = Unit.new("1 mm")          # create a simple unit
unit = Unit.new("1 mm/s")        # a compound unit
unit = Unit.new("1 mm s^-1")     # in exponent notation
unit = Unit.new("1 kg*m^2/s^2")  # complex unit
unit = Unit.new("1 kg m^2 s^-2") # complex unit
unit = Unit("1 mm")              # shorthand
unit = "1 mm".to_unit            # convert string object
unit = object.to_unit            # convert any object using object.to_s
unit = U'1 mm'
unit = u'1 mm'
unit = '1 mm'.unit
unit = '1 mm'.u

Rules:

  1. only 1 quantity per unit (with 2 exceptions… 6’5“ and ‘8 lbs 8 oz’)

  2. use SI notation when possible

  3. avoid using spaces in unit names

Unit compatability:

Many methods require that the units of two operands are compatible. Compatible units are those that can be easily converted into each other, such as ‘meters’ and ‘feet’.

unit1 =~ unit2   #=> true if units are compatible

Unit Math:

Method

Comment

Unit#+()

Add. only works if units are compatible

Unit#-()

Subtract. only works if units are compatible

Unit#*()

Multiply.

Unit#/()

Divide.

Unit#**()

Exponentiate. Exponent must be an integer, can be positive, negative, or zero

Unit#inverse

Returns 1/unit

Unit#abs

Returns absolute value of the unit quantity. Strips off the units

Unit#ceil

rounds quantity to next highest integer

Unit#floor

rounds quantity down to next lower integer

Unit#round

rounds quantity to nearest integer

Unit#to_int

returns the quantity as an integer

Unit will coerce other objects into a Unit if used in a formula. This means that ..

Unit("1 mm") + "2 mm"  == Unit("3 mm")

This will work as expected so long as you start the formula with a Unit object.

Conversions & comparisons

Units can be converted to other units in a couple of ways.

unit1 = unit >> "ft"   # => convert to 'feet'
unit >>= "ft"          # => convert and overwrite original object
unit3 = unit1 + unit2  # => resulting object will have the units of unit1
unit3 = unit1 - unit2  # => resulting object will have the units of unit1
unit1 <=> unit2        # => does comparison on quantities in base units, 
                         throws an exception if not compatible
unit1 === unit2        # => true if units and quantity are the same, even if
                         'equivalent' by <=>
unit.to('ft')          # convert

Text Output

Units will display themselves nicely based on the preferred abbreviation for the units and prefixes. Since Unit implements a Unit#to_s, all that is needed in most cases is:

"#{Unit.new('1 mm')}"  #=> "1 mm"

The to_s also accepts some options.

Unit.new('1.5 mm').to_s("%0.2f")  # => "1.50 mm".  Enter any valid format
                                     string.  Also accepts strftime format
U('1.5 mm').to_s("in")     # => converts to inches before printing
U("2 m").to_s(:ft)         #=> returns 6'7"
U("100 kg").to_s(:lbs)     #=> returns 220 lbs, 7 oz

Time Helpers

Time, Date, and DateTime objects can have time units added or subtracted.

Time.now + “10 min”.u

Several helpers have also been defined.

‘min’.since(‘9/18/06 3:00pm’) ‘min’.before(‘9/18/08 3:00pm’) ‘days’.until(‘1/1/07’) ‘5 min’.from(Time.now) ‘5 min’.from_now ‘5 min’.before_now ‘5 min’.before(Time.now) ‘10 min’.ago

Ranges

[U(‘0 h’)..U(‘10 h’)].each {|x| p x} works so long as the starting point has an integer scalar

Math functions

All Trig math functions (sin, cos, sinh, …) can take a unit as their parameter. It will be converted to radians and then used if possible.