ruby-units 0.3.6 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
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