ruby-units 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG.txt CHANGED
@@ -145,3 +145,10 @@ Change Log for Ruby-units
145
145
  but only works properly for unitless Units.
146
146
 
147
147
  2006-12-05 0.3.6 * Fixed bug where (unit/unit).ceil would fail
148
+
149
+ 2006-12-14 0.3.7 * improved handling of percents and added a 'wt%' unit
150
+ equivalent to 1 g/dl.
151
+ * Improved handling for units with non-alphanumeric names
152
+ (like ' for feet, # for pound)
153
+ * Now you can enter durations as "HH:MM:SS, usec" or
154
+ "HH:MM:SS:usec"
data/README.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  =Ruby Units
2
2
 
3
- Version: 0.3.6
3
+ Version: 0.3.7
4
4
 
5
5
  Kevin C. Olbrich, Ph.D.
6
6
  kevin.olbrich@gmail.com
@@ -115,6 +115,14 @@ Note: If you include the 'Chronic' gem, you can specify times in natural
115
115
  '5 min'.before(Time.now)
116
116
  '10 min'.ago
117
117
 
118
+ Durations may be entered as 'HH:MM:SS, usec' and will be returned in 'hours'.
119
+
120
+ '1:00'.unit #=> 1 h
121
+ '0:30'.unit #=> 0.5 h
122
+ '0:30:30'.unit #=> 0.5 h + 30 sec
123
+
124
+ If only one ":" is present, it is interpreted as the separator between hours and minutes.
125
+
118
126
  ==Ranges
119
127
 
120
128
  [U('0 h')..U('10 h')].each {|x| p x}
data/lib/ruby-units.rb CHANGED
@@ -2,7 +2,7 @@ require 'mathn'
2
2
  require 'rational'
3
3
  require 'date'
4
4
  require 'parsedate'
5
- # = Ruby Units 0.3.6
5
+ # = Ruby Units 0.3.7
6
6
  #
7
7
  # Copyright 2006 by Kevin C. Olbrich, Ph.D.
8
8
  #
@@ -40,7 +40,7 @@ require 'parsedate'
40
40
  class Unit < Numeric
41
41
  require 'units'
42
42
  # pre-generate hashes from unit definitions for performance.
43
- VERSION = '0.3.6'
43
+ VERSION = '0.3.7'
44
44
  @@USER_DEFINITIONS = {}
45
45
  @@PREFIX_VALUES = {}
46
46
  @@PREFIX_MAP = {}
@@ -51,6 +51,7 @@ class Unit < Numeric
51
51
  UNITY = '<1>'
52
52
  UNITY_ARRAY= [UNITY]
53
53
  FEET_INCH_REGEX = /(\d+)\s*(?:'|ft|feet)\s*(\d+)\s*(?:"|in|inches)/
54
+ TIME_REGEX = /(\d+)*:(\d+)*:*(\d+)*[:,]*(\d+)*/
54
55
  LBS_OZ_REGEX = /(\d+)\s*(?:#|lbs|pounds)+[\s,]*(\d+)\s*(?:oz|ounces)/
55
56
  SCI_NUMBER = %r{([+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*)}
56
57
  NUMBER_REGEX = /#{SCI_NUMBER}*\s*(.+)?/
@@ -232,7 +233,7 @@ class Unit < Numeric
232
233
 
233
234
  unary_unit = self.units || ""
234
235
  opt_units = options[0].scan(NUMBER_REGEX)[0][1] if String === options[0]
235
- unless @@cached_units.keys.include?(opt_units) || (opt_units =~ /(temp|deg(C|K|R|F))|(pounds|lbs[ ,]\d+ ounces|oz)|('\d+")|(ft|feet[ ,]\d+ in|inch|inches)|%/)
236
+ unless @@cached_units.keys.include?(opt_units) || (opt_units =~ /(temp|deg(C|K|R|F))|(pounds|lbs[ ,]\d+ ounces|oz)|('\d+")|(ft|feet[ ,]\d+ in|inch|inches)|%|(#{TIME_REGEX})/)
236
237
  @@cached_units[opt_units] = (self.scalar == 1 ? self : opt_units.unit) if opt_units && !opt_units.empty?
237
238
  end
238
239
  unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /(temp|deg)(C|K|R|F)/) then
@@ -946,9 +947,11 @@ class Unit < Numeric
946
947
  if unit_string =~ /\$\s*(#{NUMBER_REGEX})/
947
948
  unit_string = "#{$1} USD"
948
949
  end
949
- if unit_string =~ /(.+)%/
950
- unit_string = "#{$1.to_f * 0.01}"
951
- end
950
+
951
+ unit_string.gsub!(/%/,'percent')
952
+ unit_string.gsub!(/'/,'feet')
953
+ unit_string.gsub!(/"/,'inch')
954
+ unit_string.gsub!(/#/,'pound')
952
955
 
953
956
  unit_string =~ NUMBER_REGEX
954
957
  unit = @@cached_units[$2]
@@ -962,13 +965,25 @@ class Unit < Numeric
962
965
 
963
966
  unit_string.gsub!(/[<>]/,"")
964
967
 
968
+ if unit_string =~ /:/
969
+ hours, minutes, seconds, microseconds = unit_string.scan(TIME_REGEX)[0]
970
+ raise ArgumentError, "Invalid Duration" if [hours, minutes, seconds, microseconds].all? {|x| x.nil?}
971
+ result = "#{hours || 0} h".unit +
972
+ "#{minutes || 0} minutes".unit +
973
+ "#{seconds || 0} seconds".unit +
974
+ "#{microseconds || 0} usec".unit
975
+ copy(result)
976
+ return
977
+ end
978
+
979
+
965
980
  # Special processing for unusual unit strings
966
981
  # feet -- 6'5"
967
982
  feet, inches = unit_string.scan(FEET_INCH_REGEX)[0]
968
983
  if (feet && inches)
969
984
  result = Unit.new("#{feet} ft") + Unit.new("#{inches} inches")
970
985
  copy(result)
971
- return #self
986
+ return
972
987
  end
973
988
 
974
989
  # weight -- 8 lbs 12 oz
@@ -976,7 +991,7 @@ class Unit < Numeric
976
991
  if (pounds && oz)
977
992
  result = Unit.new("#{pounds} lbs") + Unit.new("#{oz} oz")
978
993
  copy(result)
979
- return #self
994
+ return
980
995
  end
981
996
 
982
997
  raise( ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.count('/') > 1
@@ -1002,7 +1017,7 @@ class Unit < Numeric
1002
1017
  @denominator = bottom.scan(@@UNIT_MATCH_REGEX).delete_if {|x| x.empty?}.compact if bottom
1003
1018
  us = "#{(top || '' + bottom || '')}".to_s.gsub(@@UNIT_MATCH_REGEX,'').gsub(/[\d\*, "'_^\/\$]/,'')
1004
1019
 
1005
- raise( ArgumentError, "'#{passed_unit_string}' Unit not recognized") unless us.empty?
1020
+ raise( ArgumentError, "'#{passed_unit_string}' Unit not recognized ('#{us}' left '#{top =~ @@UNIT_MATCH_REGEX}')") unless us.empty?
1006
1021
 
1007
1022
  @numerator = @numerator.map do |item|
1008
1023
  @@PREFIX_MAP[item[0]] ? [@@PREFIX_MAP[item[0]], @@UNIT_MAP[item[1]]] : [@@UNIT_MAP[item[1]]]
data/lib/units.rb CHANGED
@@ -132,6 +132,7 @@ UNIT_DEFINITIONS = {
132
132
 
133
133
  #concentration
134
134
  '<molar>' => [%w{M molar}, 1000, :concentration, %w{<mole>}, %w{<meter> <meter> <meter>}],
135
+ '<wtpercent>' => [%w{wt% wtpercent}, 10, :concentration, %w{<kilogram>}, %w{<meter> <meter> <meter>}],
135
136
 
136
137
  #activity
137
138
  '<katal>' => [%w{kat katal Katal}, 1.0, :activity, %w{<mole>}, %w{<second>}],
@@ -141,9 +141,9 @@ class TestRubyUnits < Test::Unit::TestCase
141
141
 
142
142
  def test_to_base
143
143
  unit1 = Unit.new("100 cm")
144
- assert_in_delta 1, 0.001, unit1.to_base.scalar
144
+ assert_in_delta 1, unit1.to_base.scalar, 0.001
145
145
  unit2 = Unit("1 mm^2 ms^-2")
146
- assert_in_delta 1, 0.001, unit2.to_base.scalar
146
+ assert_in_delta 1, unit2.to_base.scalar, 0.001
147
147
  end
148
148
 
149
149
  def test_to_unit
@@ -154,16 +154,16 @@ class TestRubyUnits < Test::Unit::TestCase
154
154
  assert Unit === unit1
155
155
  assert unit1 == unit2
156
156
  unit1 = "2.54 cm".to_unit("in")
157
- assert_in_delta 1, 0.001, unit1.scalar
157
+ assert_in_delta 1, unit1.scalar, 0.001
158
158
  assert_equal ['<inch>'], unit1.numerator
159
159
  unit1 = "2.54 cm".unit("in")
160
- assert_in_delta 1, 0.001, unit1.scalar
160
+ assert_in_delta 1, unit1.scalar, 0.001
161
161
  assert_equal ['<inch>'], unit1.numerator
162
162
  unit1 = 1.unit
163
- assert_in_delta 1, 0.001, unit1.scalar
163
+ assert_in_delta 1, unit1.scalar, 0.001
164
164
  assert_equal ['<1>'], unit1.numerator
165
165
  unit1 = [1,'mm'].unit
166
- assert_in_delta 1, 0.001, unit1.scalar
166
+ assert_in_delta 1, unit1.scalar, 0.001
167
167
  assert_equal ['<milli>','<meter>'], unit1.numerator
168
168
  end
169
169
 
@@ -259,7 +259,7 @@ class TestRubyUnits < Test::Unit::TestCase
259
259
  assert_equal (a+b).units, 'mm'
260
260
  assert_equal (b+a).scalar, 10
261
261
  assert_equal (b+a).units, 'cm'
262
- assert_in_delta 0.01, (b+c).scalar, 12.54
262
+ assert_in_delta (b+c).scalar, 12.54, 0.01
263
263
  assert_equal (b+c).units, 'cm'
264
264
  assert_raises(ArgumentError) {
265
265
  a + d
@@ -276,7 +276,7 @@ class TestRubyUnits < Test::Unit::TestCase
276
276
  assert_equal (a-b).units, 'mm'
277
277
  assert_equal (b-a).scalar, 10
278
278
  assert_equal (b-a).units, 'cm'
279
- assert_in_delta 0.01, (b-c).scalar, 7.46
279
+ assert_in_delta (b-c).scalar, 7.46, 0.01
280
280
  assert_equal (b-c).units, 'cm'
281
281
  assert_raises(ArgumentError) {
282
282
  a - d
@@ -616,11 +616,17 @@ class TestRubyUnits < Test::Unit::TestCase
616
616
  def test_feet
617
617
  unit1 = Unit.new("6'6\"")
618
618
  assert_in_delta 6.5, unit1.scalar, 0.01
619
+ unit2 = "6'".unit
620
+ assert_equal unit2, '6 feet'.unit
621
+ unit3 = '6"'.unit
622
+ assert_equal unit3, '6 inch'.unit
623
+
619
624
  end
620
625
 
621
626
  def test_pounds
622
627
  unit1 = Unit.new("8 pounds, 8 ounces")
623
628
  assert_in_delta 8.5, unit1.scalar, 0.01
629
+ assert_equal '150#'.unit, '150 lbs'.unit
624
630
  end
625
631
 
626
632
  # these units are 'ambiguous' and could be mis-parsed
@@ -782,8 +788,9 @@ class TestRubyUnits < Test::Unit::TestCase
782
788
  }
783
789
  a = '100 ml'.unit
784
790
  b = '50%'.unit
785
- c = a*b
786
- assert_equal '50 ml'.unit, c
791
+ c = a*b >> 'ml'
792
+ assert c =~ a
793
+ assert_in_delta '50 ml'.unit.scalar, c.scalar, 0.0001
787
794
  end
788
795
 
789
796
  def test_parse
@@ -815,5 +822,17 @@ class TestRubyUnits < Test::Unit::TestCase
815
822
  b = '10 mg/ml'.unit
816
823
  assert_equal a/b, 1
817
824
  end
825
+
826
+ def test_wt_percent
827
+ a = '1 wt%'.unit
828
+ b = '1 g/dl'.unit
829
+ assert_equal a,b
830
+ end
818
831
 
832
+ def test_parse_durations
833
+ assert_equal "1:00".unit, '1 hour'.unit
834
+ assert_equal "1:30".unit, "1.5 hour".unit
835
+ assert_equal "1:30:30".unit, "1.5 hour".unit + '30 sec'.unit
836
+ assert_equal "1:30:30,200".unit, "1.5 hour".unit + '30 sec'.unit + '200 usec'.unit
837
+ end
819
838
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: ruby-units
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.6
7
- date: 2006-12-05 00:00:00 -05:00
6
+ version: 0.3.7
7
+ date: 2006-12-14 00:00:00 -05:00
8
8
  summary: A model that performs unit conversions and unit math
9
9
  require_paths:
10
10
  - lib