=begin
=class NumRu::Units

* ((<Overview>))
* ((<Installation>))
* ((<Usage Examples>))
* ((<Class Methods>))
* ((<Instance Methods>))
* ((<Supported units|URL:http://ruby.gfd-dennou.org/products/numru-units/doc/dcunits.txt>))  (Plural form allowed if the second field is "P")

==Overview

A class of units of physical quantities.

This class covers most functionality of UNIDATA's 
((<UDUNITS Library|URL:http://www.unidata.ucar.edu/packages/udunits/>)), 
however, with a more sophisticated handling of string expressions. 

UDUNITS always decomposes units into the four base units and discards
the original string expressions. Therefore, 'hPa' always becomes
'100 kg.m-1.sec-1', and 'day' always becomes '86400 sec'. On the other 
hand, this library tries to keep the original expressions as much as
possible by default, while allowing partial to complete decompositions
if needed.

==Installation

Move to the top directly of this library (where you find
the file install.rb). Then, type in the following:

  % ruby install.rb

==Usage Examples

Here is an example using the "irb" interactive shell ("(('%'))" is the
command prompt, and "(('>>'))" is the irb prompt -- Type in those after it
to test.  "(('=>'))" shows the result.):

  % irb --simple-prompt
  >> require "numru/units"
  => true
  >> un1 = NumRu::Units.new('kg.m2/s')
  => Units{kg.m2/s}
  >> un2 = NumRu::Units.new('g.m')
  => Units{g.m}
  >> un3 = un1 / un2
  => Units[Multi[Pow[Name[g], Number[-1]], Name[kg], Pow[Name[m], Number[1]], Pow[Name[s], Number[-1]]]]
  >> un1.to_s
  => "kg.m2/s"
  >> un2.to_s
  => "g.m"
  >> un3.to_s
  => "g-1 kg.m1 s-1"
  >> un3.reduce5
  => Units[Multi[Number[1000], Pow[Name[m], Number[1]], Pow[Name[s], Number[-1]]]]
  >> un3.to_s
  => "1000 m1 s-1"

Note the difference between the results of (('un3.to_s')) 
before and after (('un3.reduce5')),
where the former retains the literal expression
of each atomic unit, while the latter does the maximum reduction.
You can change the default behavior by using the class method 
(('reduce_level=')):

  >> NumRu::Units.reduce_level = 5
  => :reduce5
  >> un3.to_s
  => "1000 m1 s-1"

Note that you can eliminate the prefix (('NumRu::')) by "including"
it:

  >> require "numru/units"
  => true
  >> include NumRu
  => Object
  >> un1 = Units.new('kg.m2/s')
  => Units{kg.m2/s}
  >> Units.reduce_level = 5
  => :reduce5

==Class Methods

In what follows, the prefix (('NumRu::')) is omitted for conciseness.
See ((<Usage Examples>)) on this issue.

---Units.new(string)
    Constructor.

    ARGUMENTS
    * string (String): string expression of the units. 
      [factor] units; [factor] time units [since ...] (see EXAMPLES below)

    RETURN VALUE
    * a Units

    EXAMPLE

      units = Units.new('kg.m2/s')
      units = Units.new('100 m')
      units = Units.new('g/kg')
      units = Units.new('hour since 2003-10-01 00:00:0 +0:00')
      units = Units.new('hour since 2003-10-01')   # same as above
      units = Units.new('minutes since 2003-10-01 03:15:22.5 -6:00')

---Units[string]

    Same as ((<Units.new>))

---Units.reduce_level=(n) 
    Set the reduction level before ((<to_s>)) is applied.

    ARGUMENTS
    * n (Integer): the reduction level. The default value is 4.
      Use 5 if you want a full reduction. Levels lower than 4 
      will not be needed.

==Instance Methods

---to_s
    Returns a string expression of the units.

---*(other)
    Multiplies self with another units. 
    Applies ((<reduce4>)) to format the string expression of the result.

    ARGUMENTS
    * other [Units]: the other units

    RETURN VALUE
    * a Units

---/(other)
    Divides self with another units.
    Applies ((<reduce4>)) to format the string expression of the result.

    ARGUMENTS
    * other [Units]: the other units

    RETURN VALUE
    * a Units

---**(pow)
    Power.
    Applies ((<reduce4>)) to format the string expression of the result.

    ARGUMENTS
    * pow [Numeric -- Integer, Rational, or Float]

    RETURN VALUE
    * a Units

---==(other)
    Whether the two units are the same. 
    ('m/s' and 'm.s-1' are the same, for instance.)

---===(other)
    Same as ((<==>)).

---=~(other)
    Whether the two units are compatible (i.e., with the same dimensionality).
    ('m/s' and '10 m.s-1' are compatible, for instance.)

---reduce4
    Moderately reduces the string expression of the units (destructive method).
    This method preserves string expression of atomic units. 
    See also ((<reduce5>)).

    RETURN VALUE
    * self

    EXAMPLE
      Untis.new('hour/hour').reduce4.to_s
        # => "1"
      Units.new('mm/m').reduce4.to_s
        # => "mm.m-1"

---reduce5
    Aggressively reduces the string expression of the units (destructive method).
    See also ((<reduce4>)).

    RETURN VALUE
    * self

    EXAMPLE
      Units.new('hour/hour').reduce4.to_s
        # => "1"
      Units.new('mm/m').reduce5.to_s
        # => "0.001"

---convert(numeric, to_units)
    Converts a numeric of the current units (=self) to ((|to_units|)).

    ARGUMENTS
    * numeric [Numeric]: the numeric to convert
    * to_units [Units]: the units converted into

    RETURN VALUE
    * a Numeric

    EXCEPTIONS
    * ((|self|)) and ((|to_units|)) are incompatible.

---convert2(val, to_units)
    Like ((<convert>)), but (1) accpets any Numeric-like objects, and (2)
    does not raise an exception even if the two units are incompatible -- 
    in this case, simply returns ((|val|)) (warned).

    ARGUMENTS
    * val [a Numeric-like class, for which (('*')) and (('+')) are defined]:
      the value to convert
    * to_units [Units]: the units converted into

    RETURN VALUE
    * an object with the same class as ((|val|)).

---factor_and_offset(to_units)
    Returns the factor and offset to convert from ((|self|)) to ((|to_units|)).
    The conversion is done as  (('scale_factor * operand + add_offset')).

    ARGUMENTS
    * to_units [Units]: the units to be converted into

    RETURN VALUE
    * [ scale_factor, add_offset ] (a 2-element Array, where both are Numeric)

    EXAMPLE
      scale_factor, add_offset = from_units.factor_and_offset(to_units)
      to = scale_factor * from + add_offset

=end
