=begin
=class Units
A class of units of physical quantities.

This class covers most functionality of UNIDATA's UDUNITS Library
(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 otehr 
hand, this library tries to keep the original expressions as much as
possible by default, while allowing partial to complete decompositions
if needed.

==class methods
---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')

---reduce_level
    by default returns 4.
---reduce_level = i
    Integer value within 1..5 is acceptable for ((|i|)).
    After this call, ((*reduce*))((|i|)) is used in
    ((<*>)), ((<"/">)), ((<**>)) instance methods.

==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 [Integer]

    RETURN VALUE
    * a Units

---==(other)
    Judges whether the two units are the same. 
    Comparison is done after ((<reduce5>)) operation is applied
    to both self and other.
    ('m/s' and 'm.s-1' will be the same, for instance.)

---===(other)
    Similar to ((<==>)), but reference date or shift value is ignored.

---=~(other)
    Similar to ((<===>)), but numerical factor is also ignored.
    When (units1 =~ units2) is true, you may add or subtract
    two quantities in units1 and units2.

---reduce4
    Moderately parses the string expression of the units (destructive method).
    This method preserves string expression of atomic units,
    but plural form and SI prefixes are normalized.
    See also ((<reduce5>)).

    RETURN VALUE
    * self

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

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

    RETURN VALUE
    * self

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

---convert(numeric, to_units)
    converts Numeric value ((|numeric|)) into new units ((|to_units|)).

    EXAMPLE
      Units.new('degree_F').convert(32, Units.new('K')).to_s
      # => "273.15"

---convert2(numeric_etc, to_units)
    Similat to ((<convert>)), but the first argument is more flexible
    to accept not only numerics but also NArray etc etc.

    EXAMPLE
      require "narray"
      na = NArray[-40.0, 0.0]
      Units.new('degree_F').convert(na, Units.new('degC'))
      # => NArray.float(2): 
           [ -40.0, -17.7778 ]

=end
