uom 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ This history lists major release themes. See the GitHub Commits (https://github.com/caruby/uom)
2
+ for change details.
3
+
4
+ === 1.2.2 / 2011-12-13
5
+
6
+ * Fix comma-separated number inifinite loop.
7
+
8
+ === 1.2.1 / 2010-09-30
9
+
10
+ * Initial public release.
data/README.md CHANGED
@@ -3,24 +3,23 @@ UOM: Unit of Measure library
3
3
 
4
4
  **Git**: [http://github.com/caruby/uom](http://github.com/caruby/uom)
5
5
  **Author**: OHSU Knight Cancer Institute
6
- **Copyright**: 2010
6
+ **Copyright**: 2010, 2011
7
7
  **License**: MIT License
8
- **Latest Version**: 1.2.1
9
- **Release Date**: September 30th 2010
10
8
 
11
9
  Synopsis
12
10
  --------
13
11
 
14
12
  UOM implements Units of Measurement based on the
15
- [http://physics.nist.gov/Pubs/SP330/sp330.pdf](International System of Units) (SI).
13
+ [International System of Units](http://physics.nist.gov/Pubs/SP330/sp330.pdf) (SI).
16
14
  The base SI units, metric scalar factors and all possible combinations of these units
17
- are supported out of the box.
15
+ are supported out of the box. Common alternative non-metric measurement systems, e.g.
16
+ US Customary units, are supported with conversions between these units and the SI units.
17
+ Supported units are listed in +doc/units.txt+.
18
18
 
19
- Common alternative non-metric measurement systems, e.g. US Customary units, are
20
- supported with conversions between these units and the SI units.
21
19
  Additional units can be defined with conversion to an existing unit.
22
20
  UOM infers full conversion capability between units of the same dimension from
23
- the minimal number of conversion definitions.
21
+ the minimal number of conversion definitions. See the __Usage__ section
22
+ for an example of combining pre-defined units into a novel unit.
24
23
 
25
24
  Arithmetic operations between UOM Measurement objects converts the measurement units
26
25
  and scalar factors as necessary, including unit products, quotients and powers of
@@ -88,12 +87,6 @@ Usage
88
87
  end
89
88
  UOM::Measurement.new(:jpeg, 1) #=> 1 jpeg
90
89
 
91
- Changelog
92
- ---------
93
-
94
- - **September.30.10**: 2010.1 release
95
- - Initial public release
96
-
97
90
  Copyright
98
91
  ---------
99
92
 
data/lib/uom.rb CHANGED
@@ -1,7 +1 @@
1
1
  require 'uom/measurement'
2
-
3
- # UOM implements Units of Measurement based on the International System of Units.
4
- # See [http://github.com/caruby/uom] for details.
5
- module UOM
6
- VERSION = "1.2.1"
7
- end
@@ -1,12 +1,15 @@
1
1
  require 'singleton'
2
- require 'generator'
2
+
3
+ # JRuby SyncEnumerator moved from generator to REXML in JRuby 1.5.
4
+ require 'rexml/document'
5
+
3
6
  require 'extensional'
4
7
  require 'active_support/inflector'
5
8
  require 'uom/unit'
6
9
  require 'uom/composite_unit_key_canonicalizer'
7
10
 
8
11
  module UOM
9
- # A CompositeUnit represents a measurement unit across more than one dimension, e.g. +:gram_per_liter+.
12
+ # A CompositeUnit represents a measurement unit across more than one dimension, e.g. :gram_per_liter.
10
13
  class CompositeUnit < Unit
11
14
  SUPPORTED_OPERATORS = [:/, :*]
12
15
 
@@ -48,7 +51,7 @@ module UOM
48
51
  # convert the the first axis quantity to the first unit axis
49
52
  first = axes[0].as(quantity, unit.axes[0])
50
53
  # convert the remaining units
51
- vector = SyncEnumerator.new(axes[1..-1], unit.axes[1..-1]).map { |from, to| from.as(1, to).to_f }
54
+ vector = REXML::SyncEnumerator.new(axes[1..-1], unit.axes[1..-1]).map { |from, to| from.as(1, to).to_f }
52
55
  # apply the operator
53
56
  vector.inject(first) { |q, item| q.send(@operator, item) }
54
57
  end
@@ -71,8 +74,8 @@ module UOM
71
74
 
72
75
  def create_label
73
76
  case @operator
74
- when :/ then create_division_label
75
- when :* then create_product_label
77
+ when :/ then create_division_label
78
+ when :* then create_product_label
76
79
  end
77
80
  end
78
81
 
@@ -27,6 +27,9 @@ module UOM
27
27
  # All metric factors.
28
28
  METRIC_FACTORS = [YOTTA, ZETTA, EXA, TERA, GIGA, MEGA, KILO, HECTO, DECA, DECI, CENTI, MILLI, MICRO, NANO, PICO, FEMTO, ATTO, ZEPTO, YOCTO]
29
29
 
30
- # Factors commonly used in electronics
30
+ # Factors commonly used in electronics.
31
31
  ELECTRONIC_FACTORS = [MILLI, MICRO, NANO, PICO, TERA, GIGA, MEGA, KILO]
32
+
33
+ # Factors commonly used for measures in a moderate range about 1.
34
+ SIMPLE_FACTORS = [CENTI, MILLI, MEGA, KILO]
32
35
  end
@@ -2,6 +2,8 @@ require 'forwardable'
2
2
  require 'uom/error'
3
3
  require 'uom/units'
4
4
 
5
+ # UOM implements Units of Measurement based on the International System of Units.
6
+ # See [http://github.com/caruby/uom] for details.
5
7
  module UOM
6
8
  # Measurement qualifies a quantity with a unit.
7
9
  class Measurement
@@ -110,7 +112,7 @@ class String
110
112
  # If unit is given, then this method converts the measurement to the given unit.
111
113
  def to_measurement_quantity(unit=nil)
112
114
  # remove commas
113
- return to_measurement_quantity(delete(',')) if self[',']
115
+ return delete(',').to_measurement_quantity(unit) if self[',']
114
116
  # extract the quantity portion
115
117
  quantity_s = self[/\d*\.?\d*/]
116
118
  return if quantity_s.nil? or quantity_s == '.'
@@ -39,6 +39,15 @@ module UOM
39
39
  # the first symbol is the label
40
40
  labels = params.select { |param| Symbol === param }
41
41
  @label = labels.first
42
+ # the optional Factor parameters are the permissible scaling factors
43
+ factors = params.select { |param| Factor === param }.to_set
44
+ # a convertable unit must have a unique factor
45
+ if converter and factors.size > 1 then
46
+ raise MeasurementError.new("Derived unit #{label} can have at most one scalar: #{factors.to_a.join(', ')}")
47
+ @permissible_factors = []
48
+ else
49
+ @permissible_factors = factors
50
+ end
42
51
  # a Numeric parameter indicates a conversion multiplier instead of a converter block
43
52
  multiplier = params.detect { |param| Numeric === param }
44
53
  if multiplier then
@@ -49,15 +58,6 @@ module UOM
49
58
  # make the converter block from the multiplier
50
59
  converter = lambda { |n| n * multiplier }
51
60
  end
52
- # the optional Factor parameters are the permissible scaling factors
53
- factors = params.select { |param| Factor === param }.to_set
54
- # a convertable unit must have a unique factor
55
- if converter and factors.size > 1 then
56
- raise MeasurementError.new("Derived unit #{label} can have at most one scalar: #{axes.join(', ')}")
57
- @permissible_factors = []
58
- else
59
- @permissible_factors = factors
60
- end
61
61
  # the optional single Unit parameter is the axis for a derived unit
62
62
  axes = params.select { |param| Unit === param }
63
63
  raise MeasurementError.new("Unit #{label} can have at most one axis: #{axes.join(', ')}") if axes.size > 1
@@ -184,7 +184,9 @@ module UOM
184
184
  converter = @converters[unit]
185
185
  return converter.call(quantity) if converter
186
186
  # validate the target unit dimension
187
- raise MeasurementError.new("Cannot convert #{unit} dimension #{unit.dimension} to #{self} dimension #{@dimension}") unless @dimension == unit.dimension
187
+ unless @dimension == unit.dimension then
188
+ raise MeasurementError.new("Cannot convert #{unit} dimension #{unit.dimension} to #{self} dimension #{@dimension}")
189
+ end
188
190
  # convert via an axis pivot intermediary
189
191
  pivot = conversion_pivot(unit)
190
192
  pivot.as(self.as(quantity, pivot), unit)
@@ -53,7 +53,7 @@ module UOM
53
53
  MINUTE = Unit.new(:minute, :min, SECOND, 60)
54
54
  HOUR = Unit.new(:hour, :hr, MINUTE, 60)
55
55
  DAY = Unit.new(:day, HOUR, 24)
56
-
56
+
57
57
  # information
58
58
  BIT = Unit.new(:bit, BYTE, 1.0 / 8)
59
59
 
@@ -76,6 +76,11 @@ module UOM
76
76
  JOULE = Unit.new(:joule, :J, (KILOGRAM * (METER * METER)) / (SECOND * SECOND), *ELECTRONIC_FACTORS)
77
77
  ERG = Unit.new(:erg, (GRAM * (CENTIMETER * CENTIMETER)) / (SECOND * SECOND), *ELECTRONIC_FACTORS)
78
78
  DYNE = Unit.new(:dyne, :dyn, (GRAM * CENTIMETER) / (SECOND * SECOND), *ELECTRONIC_FACTORS)
79
+ NEWTON = Unit.new(:newton, :N, (KILOGRAM * METER) / (SECOND * SECOND), *SIMPLE_FACTORS)
80
+ BAR = Unit.new(:bar, NEWTON, 0.00001, *SIMPLE_FACTORS)
81
+ PASCAL = Unit.new(:pascal, :Pa, NEWTON / (METER * METER), *SIMPLE_FACTORS)
82
+ ATMOSPHERE = Unit.new(:atmosphere, :atm, PASCAL, 0.101325, *SIMPLE_FACTORS)
83
+ TORR = Unit.new(:torr, ATMOSPHERE, 1.0 / 760, *SIMPLE_FACTORS)
79
84
  BARYE = Unit.new(:barye, :Ba, GRAM / (CENTIMETER * (SECOND * SECOND)), *ELECTRONIC_FACTORS)
80
85
  POISE = Unit.new(:poise, :P, GRAM / (CENTIMETER * SECOND), KILO, MILLI, MICRO, NANO, PICO)
81
86
  COULOMB = Unit.new(:coulomb, AMPERE / SECOND, *ELECTRONIC_FACTORS) # C abbreviation is taken by CENTIGRADE
@@ -109,7 +114,7 @@ module UOM
109
114
  DRY_GALLON = Unit.new(:dry_gallon, :dry_gal, DRY_QUART, 4)
110
115
  PECK = Unit.new(:peck, :pk, DRY_GALLON, 2)
111
116
  BUSHEL = Unit.new(:bushel, :bu, PECK, 4)
112
-
113
- # Pressure
117
+
118
+ # Pressure alias
114
119
  PSI = Unit.for(:pounds_per_square_inch).add_abbreviation(:psi)
115
120
  end
@@ -0,0 +1,3 @@
1
+ module UOM
2
+ VERSION = "1.2.2"
3
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.require(:test, :development)
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/../helper'
2
+ require "test/unit"
3
+ require 'uom/units'
4
+ require 'uom/composite_unit_key_canonicalizer'
5
+
6
+ class CompositeUnitKeyCanonicalizerTest < Test::Unit::TestCase
7
+ def setup
8
+ @canonicalizer = UOM::CompositeUnitKeyCanonicalizer.new
9
+ end
10
+
11
+ def test_product_product
12
+ standard = [UOM::GRAM * UOM::METER, UOM::SECOND, :*]
13
+ variant = @canonicalizer.canonicalize(UOM::GRAM, UOM::METER * UOM::SECOND, :*)
14
+ assert_equal(standard, variant, "Canonicalization of x * (y * z) incorrect")
15
+ end
16
+
17
+ def test_product_quotient
18
+ standard = [UOM::GRAM * UOM::METER, UOM::SECOND, :/]
19
+ variant = @canonicalizer.canonicalize(UOM::GRAM, UOM::METER / UOM::SECOND, :*)
20
+ assert_equal(standard, variant, "Canonicalization of x * (y / z) incorrect")
21
+ end
22
+
23
+ def test_quotient_product
24
+ standard = [UOM::GRAM / UOM::METER, UOM::SECOND, :/]
25
+ variant = @canonicalizer.canonicalize(UOM::GRAM, UOM::METER * UOM::SECOND, :/)
26
+ assert_equal(standard, variant, "Canonicalization of x / (y * z) incorrect")
27
+ end
28
+
29
+ def test_quotient_quotient
30
+ standard = [UOM::GRAM / UOM::METER, UOM::SECOND, :*]
31
+ variant = @canonicalizer.canonicalize(UOM::GRAM, UOM::METER / UOM::SECOND, :/)
32
+ assert_equal(standard, variant, "Canonicalization of x / (y / z) incorrect")
33
+ end
34
+
35
+ def test_joule
36
+ joule = UOM::JOULE.axis
37
+ assert_equal(((UOM::KILOGRAM * UOM::METER) * UOM::METER) / UOM::SECOND, joule.axes.first, "Joule canonicalization first axis incorrect")
38
+ assert_equal(UOM::SECOND, joule.axes.last, "Joule canonicalization second axis incorrect")
39
+ assert_equal(:/, joule.operator, "Joule canonicalization operator incorrect")
40
+ end
41
+ end
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + '/../helper'
2
+ require "test/unit"
3
+ require 'uom/units'
4
+
5
+ class CompositeUnitTest < Test::Unit::TestCase
6
+ def test_square
7
+ square_meter = UOM::METER * UOM::METER
8
+ assert_equal(:square_meter, square_meter.label, "Square meter label incorrect")
9
+ assert_equal([UOM::METER, UOM::METER], square_meter.axes, "Square meter axes incorrect: #{square_meter.axes.join(', ')}")
10
+ assert_same(square_meter, UOM::Unit.for(:square_meter), "Square meter lookup by label incorrect")
11
+ assert_same(square_meter, UOM::METER * UOM::METER, "Square meter product inconsistent")
12
+ end
13
+
14
+ def test_cube
15
+ cubic_meter = UOM::METER * UOM::METER * UOM::METER
16
+ assert_equal(:cubic_meter, cubic_meter.label, "Cubic meter label incorrect")
17
+ assert_equal([UOM::METER * UOM::METER, UOM::METER], cubic_meter.axes, "Cubic meter axes incorrect: #{cubic_meter.axes.join(', ')}")
18
+ assert_same(cubic_meter, UOM::Unit.for(:cubic_meter), "Cubic meter lookup by label incorrect")
19
+ assert_same(cubic_meter, UOM::METER * UOM::METER * UOM::METER, "Cubic meter product inconsistent")
20
+ end
21
+
22
+ def test_basic_scale_low_to_high
23
+ roundtrip = UOM::MILLIMETER.as(UOM::METER.as(4, UOM::MILLIMETER), UOM::METER)
24
+ assert_in_delta(4.0, roundtrip, 0.0000000001, "Scale conversion incorrect")
25
+ end
26
+
27
+ def test_idempotent_product_conversion
28
+ product = UOM::MILLIGRAM * UOM::LITER
29
+ assert_equal(:milligram_liter, product.label, "Composite product label incorrect")
30
+ other = UOM::GRAM * UOM::MILLILITER
31
+ roundtrip = other.as(product.as(4, other), product)
32
+ assert_in_delta(4.0, roundtrip, 0.0000000001, "Idempotent roduct conversion milligram_liter => gram_milliter incorrect: #{roundtrip}")
33
+ end
34
+
35
+ def test_idempotent_quotient_conversion
36
+ quotient = UOM::GRAM / UOM::LITER
37
+ assert_equal(:grams_per_liter, quotient.label, "Composite divide label incorrect")
38
+ other = UOM::MILLIGRAM / UOM::MILLILITER
39
+ roundtrip = other.as(quotient.as(4, other), quotient)
40
+ assert_in_delta(4.0, roundtrip, 0.0000000001, "Idempotent quotient conversion grams_per_liter => milligrams_per_milliliter incorrect: #{roundtrip}")
41
+ end
42
+
43
+ def test_basic_volume_conversion
44
+ roundtrip = UOM::QUART.as(UOM::LITER.as(4, UOM::QUART), UOM::LITER)
45
+ assert_in_delta(4.0, roundtrip, 0.000000001, "Quotient volume liter => quart => liter incorrect: #{roundtrip}")
46
+ end
47
+
48
+ def test_volume_scale_conversion
49
+ roundtrip = UOM::LITER.as(UOM::MILLILITER.as(4, UOM::LITER), UOM::MILLILITER)
50
+ assert_in_delta(4.0, roundtrip, 0.0000000001, "Quotient volume millliter => liter => liter incorrect: #{roundtrip}")
51
+ end
52
+
53
+ def test_scaled_axis_concentration_conversion
54
+ roundtrip = UOM::CUP.as(UOM::MILLILITER.as(4, UOM::CUP), UOM::MILLILITER)
55
+ assert_in_delta(4.0, roundtrip, 0.0000000001, "Quotient conversion milligrams_per_milliliter => dram_per_cup incorrect: #{roundtrip}")
56
+ end
57
+
58
+ def test_measurement_system_quotient_conversion
59
+ quotient = UOM::MILLIGRAM / UOM::MILLILITER
60
+ other = UOM::DRAM / UOM::CUP
61
+ roundtrip = other.as(quotient.as(4, other), quotient)
62
+ assert_in_delta(4.0, roundtrip, 0.0000000001, "Quotient conversion milligrams_per_milliliter => dram_per_cup incorrect: #{roundtrip}")
63
+ end
64
+
65
+ def test_psi
66
+ assert_not_nil(UOM::Unit.for(:psi), "PSI abbreviation missing")
67
+ end
68
+ end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/../helper'
2
+ require "test/unit"
3
+ require 'uom'
4
+
5
+ class FactorTest < Test::Unit::TestCase
6
+ def test_small_to_unit
7
+ assert_equal(0.001, UOM::MILLI.as(UOM::UNIT), "milli => unit incorrect")
8
+ end
9
+
10
+ def test_unit_to_large
11
+ assert_equal(0.1, UOM::UNIT.as(UOM::DECA), "unit => deca incorrect")
12
+ end
13
+
14
+ def test_large_to_small
15
+ assert_equal(1000000000, UOM::KILO.as(UOM::MICRO), "kilo => micro incorrect")
16
+ end
17
+
18
+ def test_small_to_large
19
+ assert_equal(0.000001, UOM::MILLI.as(UOM::KILO), "milli => kilo incorrect")
20
+ end
21
+ end
@@ -0,0 +1,74 @@
1
+ require File.dirname(__FILE__) + '/../helper'
2
+ require "test/unit"
3
+ require 'uom'
4
+
5
+ class UOMTest < Test::Unit::TestCase
6
+ include UOM
7
+
8
+ def test_alias
9
+ assert_equal(:gram, Measurement.new(:g, 1).unit.label, "Gram alias not recognized")
10
+ end
11
+
12
+ def test_scale
13
+ assert_equal(:milligram, Measurement.new(:mg, 1).unit.label, "Milligram not recognized")
14
+ end
15
+
16
+ def test_conversion
17
+ round_trip = Measurement.new(MILLIMETER, 4).as(INCH).as(MILLIMETER)
18
+ assert_in_delta(4.0, round_trip.to_f, 0.0000001, "Unit conversion incorrect")
19
+ end
20
+
21
+ def test_product
22
+ assert_equal(4, Measurement.new(:meter, 2) * 2, "Numeric product incorrect")
23
+ actual = Measurement.new(:meter, 2) * Measurement.new(:millimeter, 2000)
24
+ assert_equal(Measurement.new(:square_meter, 4), actual, "Measurement product incorrect: #{actual}")
25
+ end
26
+
27
+ def test_quotient
28
+ assert_equal(2, Measurement.new(:gram, 4) / 2, "Numeric quotient incorrect")
29
+ actual = Measurement.new(:milligram, 4) / Measurement.new(:milliliter, 2)
30
+ assert_equal(Measurement.new(:milligram_per_milliliter, 2), actual, "Measurement quotient incorrect: #{actual}")
31
+ end
32
+
33
+ def test_equal
34
+ assert_equal(1, Measurement.new(:gram, 1), "Numeric equality not supported")
35
+ assert_equal(Measurement.new(:gram, 1), Measurement.new(:gram, 1), "Equality not reflexive")
36
+ assert_equal(Measurement.new(:g, 1), Measurement.new(:mg, 1000), "Equality does not account for factor conversion")
37
+ end
38
+
39
+ def test_concentration_alias
40
+ assert_equal(:grams_per_liter, Measurement.new(:g_per_l, 1).unit.label,"Concentration alias not recognized")
41
+ end
42
+
43
+ def test_concentration_conversion
44
+ assert_equal(0.004, Measurement.new(:mg_per_l, 4).as(:ug_per_ul).quantity, "Concentration conversion incorrect")
45
+ end
46
+
47
+ def test_idempotent_quotient_conversion
48
+ quotient = GRAM / LITER
49
+ assert_equal(:grams_per_liter, quotient.label, "Composite divide label incorrect")
50
+ other = MILLIGRAM / MILLILITER
51
+ roundtrip = Measurement.new(quotient, 4).as(other).as(quotient)
52
+ assert_equal(Measurement.new(other, 4.0), roundtrip, "Idempotent quotient conversion 4 grams_per_liter => milligrams_per_milliliter incorrect: #{roundtrip}")
53
+ end
54
+
55
+ def test_parse_unknown_factor
56
+ assert_raises(UOM::MeasurementError, "'1 unknown' didn't raise a measurement error") { "1 unknown".to_measurement }
57
+ end
58
+
59
+ def test_parse_known_factors
60
+ assert_equal(Measurement.new(:gram, 1), "1g".to_measurement, "'1g' not parsed")
61
+ assert_equal(Measurement.new(:gram, 1), "1 g".to_measurement, "'1 g' not parsed")
62
+ assert_equal(Measurement.new(:gram, 1), "1 gm".to_measurement, "'1 gm' not parsed")
63
+ assert_equal(Measurement.new(:gram, 1), "1 gram".to_measurement, "gram not parsed")
64
+ assert_equal(Measurement.new(:gram, 4), "4 grams".to_measurement, "grams not parsed")
65
+ assert_equal(:micrograms_per_microliter, ".2 ug_per_ul".to_measurement.unit.label, "ug_per_ul not parsed")
66
+ assert_equal(:milligrams_per_liter, ".2 mg/l".to_measurement.unit.label, "ug/ul not parsed")
67
+ assert_equal(:milligram, "2".to_measurement(:milligram).unit.label, "Default not used")
68
+ end
69
+
70
+ def test_print
71
+ assert_equal("1 gram", Measurement.new(:gram, 1).to_s, "Measurement String incorrect")
72
+ assert_equal("2 grams", Measurement.new(:gram, 2).to_s, "Measurement String incorrect")
73
+ end
74
+ end
@@ -0,0 +1,134 @@
1
+ require File.dirname(__FILE__) + '/../helper'
2
+ require "test/unit"
3
+
4
+ # JRuby SyncEnumerator moved from generator to REXML in JRuby 1.5
5
+ require 'rexml/document'
6
+
7
+ require 'uom/units'
8
+
9
+ class UnitFactoryTest < Test::Unit::TestCase
10
+ def setup
11
+ @factory = UOM::UnitFactory.new
12
+ end
13
+
14
+ def test_gram
15
+ assert_equal(:gram, @factory.create('gram').label, "gram not recognized")
16
+ assert_equal(:gram, @factory.create('gm').label, "gm not recognized")
17
+ assert_equal(:gram, @factory.create('g').label, "g not recognized")
18
+ end
19
+
20
+ def test_milligram
21
+ assert_equal(:milligram, @factory.create('milligram').label, "milligram not recognized")
22
+ assert_equal(:milligram, @factory.create('mg').label, "mg not recognized")
23
+ end
24
+
25
+ def test_kiloliter
26
+ assert_equal(:kiloliter, @factory.create('kiloliter').label, "kiloliter not recognized")
27
+ assert_equal(:kiloliter, @factory.create('kl').label, "kl not recognized")
28
+ end
29
+
30
+ def test_product
31
+ assert_equal(:foot_pound, @factory.create('foot_pound').label, "foot_pound not recognized")
32
+ assert_equal(:foot_pound, @factory.create('ft_lb').label, "ft_lb not recognized")
33
+ end
34
+
35
+ def test_quotient
36
+ assert_equal(:milligrams_per_milliliter, @factory.create('milligrams_per_milliliter').label, "milligrams_per_milliliter not recognized")
37
+ assert_equal(:milligrams_per_milliliter, @factory.create('mg_per_ml').label, "mg_per_ml not recognized")
38
+ end
39
+
40
+ def test_square
41
+ assert_equal(:square_inch, @factory.create('square_inch').label, "square_inch not recognized")
42
+ assert_equal(:square_inch, @factory.create('sq_in').label, "sq_in not recognized")
43
+ end
44
+
45
+ def test_cubic
46
+ assert_equal(:cubic_inch, @factory.create('cubic_inch').label, "cubic_inch not recognized")
47
+ assert_equal(:cubic_inch, @factory.create('cu_in').label, "cu_in not recognized")
48
+ end
49
+
50
+ def test_psi
51
+ assert_equal(:pounds_per_inches_per_inch, @factory.create('pounds_per_square_inch').label, "pounds_per_square_inch not recognized")
52
+ assert_equal(:pounds_per_inches_per_inch, @factory.create('lb_per_sq_in').label, "lb_per_sq_in not recognized")
53
+ end
54
+
55
+ def test_energy
56
+ assert_equal(:kilojoule, @factory.create('kilojoule').label, "joule not recognized")
57
+ assert_equal(:kilojoule, @factory.create('kJ').label, "kJ not recognized")
58
+ end
59
+
60
+ def test_time
61
+ assert_equal(:nanosecond, @factory.create('nanosecond').label, "nanosecond not recognized")
62
+ assert_equal(:nanosecond, @factory.create('nsec').label, "nsec not recognized")
63
+ end
64
+
65
+ def test_temperature
66
+ assert_equal(:celsius, @factory.create('celsius').label, "celsius not recognized")
67
+ assert_equal(:celsius, @factory.create('C').label, "C not recognized")
68
+ assert_equal(:farenheit, @factory.create('farenheit').label, "farenheit not recognized")
69
+ assert_equal(:farenheit, @factory.create('F').label, "F not recognized")
70
+ end
71
+
72
+ def test_kilobyte
73
+ assert_equal(:kilobyte, @factory.create('kilobyte').label, "kilobyte not recognized")
74
+ assert_equal(:kilobyte, @factory.create('kByte').label, "KByte not recognized")
75
+ assert_equal(:kilobyte, @factory.create('kb').label, "KB not recognized")
76
+ end
77
+
78
+ # Tests parsing all possible combinations of labels, abbrevs and factors.
79
+ def test_all
80
+ units = File.open(ALL_UNITS, 'r').map { |line| line.chomp }
81
+ REXML::SyncEnumerator.new(units, generate_all_units).each do |expected, actual|
82
+ assert_equal(expected, actual, "Generated units differs from documented units")
83
+ end
84
+ end
85
+
86
+ def verify_create(label, axis, scalar=nil)
87
+ actual = @factory.create(label)
88
+ assert_same(axis.basis, actual.basis, "Unit with label '#{label}' basis is incorrect")
89
+ unless actual.scalar == UOM::UNIT and scalar.nil? then
90
+ assert_same(scalar, actual.scalar, "Unit '#{label}' scalar factor incorrect")
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ ALL_UNITS = File.expand_path('units.txt', File.dirname(__FILE__) + '/../../../doc')
97
+
98
+ def generate_all_units
99
+ basic = UOM::Unit.select do |unit|
100
+ unit.scalar == UOM::UNIT and not UOM::CompositeUnit === unit
101
+ end
102
+ all = basic.map do |unit|
103
+ labels = []
104
+ [UOM::UNIT].concat(unit.permissible_factors.to_a).each do |factor|
105
+ labels << label = "#{factor}#{unit}"
106
+ verify_create(label, unit, factor)
107
+ unless label == label.pluralize then
108
+ verify_create(label.pluralize, unit, factor)
109
+ labels << label.pluralize
110
+ end
111
+ unit.abbreviations.each do |abbrev|
112
+ labels << label = "#{factor.abbreviation}#{abbrev}"
113
+ verify_create(label, unit, factor)
114
+ abbrev_s = abbrev.to_s
115
+ unless abbrev_s.length < 2 then
116
+ plural = label + 's'
117
+ verify_create(plural, unit, factor)
118
+ labels << plural
119
+ end
120
+ end
121
+ end
122
+ labels.join(', ')
123
+ end
124
+ # combine byte measures
125
+ byte, std = all.partition { |line| line =~ /byte/ }
126
+ bh = {}
127
+ byte.each do |line|
128
+ key = /^(.*byte),.*/.match(line).captures.first.to_sym
129
+ bh[key] = line.chomp
130
+ end
131
+ std << [:byte, :kilobyte, :megabyte, :gigabyte, :terabyte, :petabyte].map { |k| bh[k] }.join(', ')
132
+ std.sort
133
+ end
134
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/../helper'
2
+ require "test/unit"
3
+ require 'uom'
4
+
5
+ # Not to be confused with Test::Unit, UnitTest tests Unit.
6
+ class UnitTest < Test::Unit::TestCase
7
+ include UOM
8
+
9
+ def test_scale_high_to_low
10
+ assert_equal(4000, METER.as(4, MILLIMETER).to_f, "Scale conversion incorrect")
11
+ end
12
+
13
+ def test_scale_low_to_high
14
+ assert_equal(0.04, CENTIMETER.as(4, METER).to_f, "Scale conversion incorrect")
15
+ end
16
+
17
+ def test_byte
18
+ assert_equal(4 * 1024 * 1024, GIGABYTE.as(4, KILOBYTE).to_f, "Scale conversion incorrect")
19
+ end
20
+
21
+ def test_axis_conversion
22
+ round_trip = INCH.as(MILLIMETER.as(4, INCH), MILLIMETER)
23
+ assert_in_delta(4.0, round_trip.to_f, 0.000000001, "Unit conversion incorrect")
24
+ end
25
+
26
+ def test_basic_to_derived
27
+ round_trip = DRAM.as(GRAM.as(4, DRAM), GRAM)
28
+ assert_in_delta(4.0, round_trip.to_f, 0.000000001, "Unit conversion incorrect")
29
+ end
30
+
31
+ def test_new_unit
32
+ jpeg = Measurement.new(:jpeg, 4)
33
+ expected = Measurement.new(:joule_peck, 4) / Measurement.new(:erg_gauss, 1)
34
+ assert_equal(expected, jpeg, "New unit incorrect")
35
+ end
36
+
37
+ private
38
+
39
+ # joule-pecks per erg-gauss
40
+ JPEG = Unit.for((JOULE * PECK) / (ERG * GAUSS)).add_abbreviation(:jpeg)
41
+ end
metadata CHANGED
@@ -1,37 +1,62 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uom
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
5
- prerelease: false
6
- segments:
7
- - 1
8
- - 2
9
- - 1
10
- version: 1.2.1
4
+ prerelease:
5
+ version: 1.2.2
11
6
  platform: ruby
12
7
  authors:
13
- - OHSU
8
+ - OHSU
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
12
 
18
- date: 2010-10-04 00:00:00 -07:00
13
+ date: 2011-12-13 00:00:00 -08:00
19
14
  default_executable:
20
15
  dependencies:
21
- - !ruby/object:Gem::Dependency
22
- name: extensional
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 0
32
- version: "0"
33
- type: :runtime
34
- version_requirements: *id001
16
+ - !ruby/object:Gem::Dependency
17
+ name: extensional
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: "0"
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: yard
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: rake
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ type: :development
59
+ version_requirements: *id004
35
60
  description: " UOM implements Units of Measurement based on the International System of Units (SI).\n The base SI units, metric scalar factors and all possible combinations of these units\n are supported out of the box.\n"
36
61
  email: caruby.org@gmail.com
37
62
  executables: []
@@ -41,61 +66,67 @@ extensions: []
41
66
  extra_rdoc_files: []
42
67
 
43
68
  files:
44
- - doc/units.txt
45
- - lib/active_support/core_ext/string/inflections.rb
46
- - lib/active_support/core_ext/string.rb
47
- - lib/active_support/inflections.rb
48
- - lib/active_support/inflector.rb
49
- - lib/active_support/README.txt
50
- - lib/uom/composite_unit.rb
51
- - lib/uom/composite_unit_key_canonicalizer.rb
52
- - lib/uom/dimension.rb
53
- - lib/uom/dimensions.rb
54
- - lib/uom/error.rb
55
- - lib/uom/factor.rb
56
- - lib/uom/factors.rb
57
- - lib/uom/measurement.rb
58
- - lib/uom/unit.rb
59
- - lib/uom/unit_factory.rb
60
- - lib/uom/units.rb
61
- - lib/uom.rb
62
- - History.txt
63
- - LEGAL
64
- - LICENSE
65
- - README.md
66
- has_rdoc: uom
69
+ - lib/uom.rb
70
+ - lib/active_support/inflections.rb
71
+ - lib/active_support/inflector.rb
72
+ - lib/active_support/README.txt
73
+ - lib/active_support/core_ext/string.rb
74
+ - lib/active_support/core_ext/string/inflections.rb
75
+ - lib/uom/composite_unit.rb
76
+ - lib/uom/composite_unit_key_canonicalizer.rb
77
+ - lib/uom/dimension.rb
78
+ - lib/uom/dimensions.rb
79
+ - lib/uom/error.rb
80
+ - lib/uom/factor.rb
81
+ - lib/uom/factors.rb
82
+ - lib/uom/measurement.rb
83
+ - lib/uom/unit.rb
84
+ - lib/uom/unit_factory.rb
85
+ - lib/uom/units.rb
86
+ - lib/uom/version.rb
87
+ - test/lib/helper.rb
88
+ - test/lib/uom/composite_unit_key_canonicalizer_test.rb
89
+ - test/lib/uom/composite_unit_test.rb
90
+ - test/lib/uom/factor_test.rb
91
+ - test/lib/uom/measurement_test.rb
92
+ - test/lib/uom/unit_factory_test.rb
93
+ - test/lib/uom/unit_test.rb
94
+ - History.md
95
+ - LEGAL
96
+ - LICENSE
97
+ - README.md
98
+ has_rdoc: yard
67
99
  homepage: http://github.com/caruby/uom/
68
- licenses: []
69
-
100
+ licenses:
101
+ - MIT
70
102
  post_install_message:
71
103
  rdoc_options: []
72
104
 
73
105
  require_paths:
74
- - lib
106
+ - lib
75
107
  required_ruby_version: !ruby/object:Gem::Requirement
76
108
  none: false
77
109
  requirements:
78
- - - ">="
79
- - !ruby/object:Gem::Version
80
- hash: 3
81
- segments:
82
- - 0
83
- version: "0"
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: "0"
84
113
  required_rubygems_version: !ruby/object:Gem::Requirement
85
114
  none: false
86
115
  requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- hash: 3
90
- segments:
91
- - 0
92
- version: "0"
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: "0"
93
119
  requirements: []
94
120
 
95
121
  rubyforge_project: caruby
96
- rubygems_version: 1.3.7
122
+ rubygems_version: 1.5.1
97
123
  signing_key:
98
124
  specification_version: 3
99
125
  summary: Ruby Unit of Measurement library.
100
- test_files: []
101
-
126
+ test_files:
127
+ - test/lib/uom/composite_unit_key_canonicalizer_test.rb
128
+ - test/lib/uom/composite_unit_test.rb
129
+ - test/lib/uom/factor_test.rb
130
+ - test/lib/uom/measurement_test.rb
131
+ - test/lib/uom/unit_factory_test.rb
132
+ - test/lib/uom/unit_test.rb
@@ -1,4 +0,0 @@
1
- === 1.2.1 / 2010-09-30
2
-
3
- * Initial public release
4
-
@@ -1,53 +0,0 @@
1
- ampere, amperes, A, milliampere, milliamperes, mA, microampere, microamperes, uA, nanoampere, nanoamperes, nA, picoampere, picoamperes, pA, teraampere, teraamperes, TA, gigaampere, gigaamperes, GA, megaampere, megaamperes, MA, kiloampere, kiloamperes, kA
2
- angstrom, angstroms, a
3
- astronomical_unit, astronomical_units, AU, AUs
4
- barye, baryes, Ba, Bas, millibarye, millibaryes, mBa, mBas, microbarye, microbaryes, uBa, uBas, nanobarye, nanobaryes, nBa, nBas, picobarye, picobaryes, pBa, pBas, terabarye, terabaryes, TBa, TBas, gigabarye, gigabaryes, GBa, GBas, megabarye, megabaryes, MBa, MBas, kilobarye, kilobaryes, kBa, kBas
5
- bit, bits
6
- bushel, bushels, bu, bus
7
- byte, bytes, Byte, Bytes, B, b, kilobyte, kilobytes, KByte, KBytes, KB, KBs, megabyte, megabytes, MByte, MBytes, MB, MBs, gigabyte, gigabytes, GByte, GBytes, GB, GBs, terabyte, terabytes, TByte, TBytes, TB, TBs, petabyte, petabytes, PByte, PBytes, PB, PBs
8
- candela, candelas, cd, cds
9
- celsius, C
10
- coulomb, coulombs, millicoulomb, millicoulombs, microcoulomb, microcoulombs, nanocoulomb, nanocoulombs, picocoulomb, picocoulombs, teracoulomb, teracoulombs, gigacoulomb, gigacoulombs, megacoulomb, megacoulombs, kilocoulomb, kilocoulombs
11
- cup, cups, cp, cps
12
- day, days
13
- dram, drams, dr, drs
14
- dry_gallon, dry_gallons, dry_gal, dry_gals
15
- dry_pint, dry_pints, dry_pt, dry_pts
16
- dry_quart, dry_quarts, dry_qt, dry_qts
17
- dyne, dynes, dyn, dyns, millidyne, millidynes, mdyn, mdyns, microdyne, microdynes, udyn, udyns, nanodyne, nanodynes, ndyn, ndyns, picodyne, picodynes, pdyn, pdyns, teradyne, teradynes, Tdyn, Tdyns, gigadyne, gigadynes, Gdyn, Gdyns, megadyne, megadynes, Mdyn, Mdyns, kilodyne, kilodynes, kdyn, kdyns
18
- erg, ergs, millierg, milliergs, microerg, microergs, nanoerg, nanoergs, picoerg, picoergs, teraerg, teraergs, gigaerg, gigaergs, megaerg, megaergs, kiloerg, kiloergs
19
- farad, farads, millifarad, millifarads, microfarad, microfarads, nanofarad, nanofarads, picofarad, picofarads, terafarad, terafarads, gigafarad, gigafarads, megafarad, megafarads, kilofarad, kilofarads
20
- farenheit, F
21
- fluid_ounce, fluid_ounces, fl_oz, fl_ozs
22
- foot, foots, ft, fts
23
- gallon, gallons, gal, gals
24
- gauss, gausses, G
25
- grain, grains, gr, grs
26
- gram, grams, gm, gms, g, yottagram, yottagrams, Ygm, Ygms, Yg, zettagram, zettagrams, Zgm, Zgms, Zg, exagram, exagrams, Egm, Egms, Eg, teragram, teragrams, Tgm, Tgms, Tg, gigagram, gigagrams, Ggm, Ggms, Gg, megagram, megagrams, Mgm, Mgms, Mg, kilogram, kilograms, kgm, kgms, kg, hectogram, hectograms, hgm, hgms, hg, decagram, decagrams, dagm, dagms, dag, decigram, decigrams, dgm, dgms, dg, centigram, centigrams, cgm, cgms, cg, milligram, milligrams, mgm, mgms, mg, microgram, micrograms, ugm, ugms, ug, nanogram, nanograms, ngm, ngms, ng, picogram, picograms, pgm, pgms, pg, femtogram, femtograms, fgm, fgms, fg, attogram, attograms, agm, agms, ag, zeptogram, zeptograms, zgm, zgms, zg, yoctogram, yoctograms, ygm, ygms, yg
27
- henry, henries, H
28
- hour, hours, hr, hrs
29
- inch, inches, in, ins
30
- joule, joules, J, millijoule, millijoules, mJ, microjoule, microjoules, uJ, nanojoule, nanojoules, nJ, picojoule, picojoules, pJ, terajoule, terajoules, TJ, gigajoule, gigajoules, GJ, megajoule, megajoules, MJ, kilojoule, kilojoules, kJ
31
- kelvin, K
32
- light_year, light_years, ly, lys
33
- liter, liters, l, L, yottaliter, yottaliters, Yl, YL, zettaliter, zettaliters, Zl, ZL, exaliter, exaliters, El, EL, teraliter, teraliters, Tl, TL, gigaliter, gigaliters, Gl, GL, megaliter, megaliters, Ml, ML, kiloliter, kiloliters, kl, kL, hectoliter, hectoliters, hl, hL, decaliter, decaliters, dal, daL, deciliter, deciliters, dl, dL, centiliter, centiliters, cl, cL, milliliter, milliliters, ml, mL, microliter, microliters, ul, uL, nanoliter, nanoliters, nl, nL, picoliter, picoliters, pl, pL, femtoliter, femtoliters, fl, fL, attoliter, attoliters, al, aL, zeptoliter, zeptoliters, zl, zL, yoctoliter, yoctoliters, yl, yL
34
- maxwell, maxwells, Mx, Mxs
35
- meter, meters, m, yottameter, yottameters, Ym, zettameter, zettameters, Zm, exameter, exameters, Em, terameter, terameters, Tm, gigameter, gigameters, Gm, megameter, megameters, Mm, kilometer, kilometers, km, hectometer, hectometers, hm, decameter, decameters, dam, decimeter, decimeters, dm, centimeter, centimeters, cm, millimeter, millimeters, mm, micrometer, micrometers, um, nanometer, nanometers, nm, picometer, picometers, pm, femtometer, femtometers, fm, attometer, attometers, am, zeptometer, zeptometers, zm, yoctometer, yoctometers, ym
36
- mile, miles, mi, mis
37
- minute, minutes, min, mins
38
- mole, moles, mol, mols
39
- ohm, ohms
40
- ounce, ounces, oz, ozs
41
- peck, pecks, pk, pks
42
- pint, pints, pt, pts
43
- poise, poises, P, kilopoise, kilopoises, kP, millipoise, millipoises, mP, micropoise, micropoises, uP, nanopoise, nanopoises, nP, picopoise, picopoises, pP
44
- pound, pounds, lb, lbs
45
- quart, quarts, qt, qts
46
- second, seconds, sec, secs, s, millisecond, milliseconds, msec, msecs, ms, microsecond, microseconds, usec, usecs, us, nanosecond, nanoseconds, nsec, nsecs, ns, picosecond, picoseconds, psec, psecs, ps, femtosecond, femtoseconds, fsec, fsecs, fs
47
- tablespoon, tablespoons, tbsp, tbsps
48
- teaspoon, teaspoons, tsp, tsps
49
- tesla, teslas, T, decitesla, deciteslas, dT, centitesla, centiteslas, cT, millitesla, milliteslas, mT, microtesla, microteslas, uT, nanotesla, nanoteslas, nT, picotesla, picoteslas, pT
50
- ton, tons
51
- volt, volts, V, millivolt, millivolts, mV, microvolt, microvolts, uV, nanovolt, nanovolts, nV, picovolt, picovolts, pV, teravolt, teravolts, TV, gigavolt, gigavolts, GV, megavolt, megavolts, MV, kilovolt, kilovolts, kV
52
- weber, webers, Wb, Wbs, milliweber, milliwebers, mWb, mWbs, microweber, microwebers, uWb, uWbs, nanoweber, nanowebers, nWb, nWbs, picoweber, picowebers, pWb, pWbs, teraweber, terawebers, TWb, TWbs, gigaweber, gigawebers, GWb, GWbs, megaweber, megawebers, MWb, MWbs, kiloweber, kilowebers, kWb, kWbs
53
- yard, yards, yd, yds