ruby-units 1.1.0 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.txt CHANGED
@@ -1,5 +1,13 @@
1
1
  Change Log for Ruby-units
2
2
  =========================
3
+ 2007-12-12 1.1.2 * fixed a bug with format strings
4
+ * detect if ruby 1.8.6 is installed and use its' to_date function
5
+
6
+ 2007-07-14 1.1.1 * fixed bug that would prevent creating '<pound-mass>' units, which
7
+ prevented rounding from working
8
+ * tests do not fail if Uncertain gem is not installed, you just get an
9
+ annoying warning message
10
+
3
11
  2007-01-28 1.1.0 * completely revamped the temperature handling system (see README)
4
12
  * fixed some spelling errors in some units
5
13
  * fixed to_datetime and to_date to convert durations to datetimes and dates'
data/README.txt CHANGED
@@ -1,11 +1,12 @@
1
1
  =Ruby Units
2
2
 
3
3
  Kevin C. Olbrich, Ph.D.
4
+
4
5
  kevin.olbrich@gmail.com
5
6
 
6
7
  http://www.sciwerks.com
7
8
 
8
- Project page: http://rubyforge.org/projects/ruby-units
9
+ Project page: http://ruby-units.rubyforge.org/ruby-units
9
10
 
10
11
  ==Introduction
11
12
  Many technical applications make use of specialized calculations at some point.
@@ -111,26 +112,26 @@ Several helpers have also been defined.
111
112
  Note: If you include the 'Chronic' gem, you can specify times in natural
112
113
  language.
113
114
 
114
- 'min'.since('9/18/06 3:00pm')
115
- 'min'.before('9/18/08 3:00pm')
116
- 'days'.until('1/1/07')
117
- '5 min'.from(Time.now)
118
- '5 min'.from_now
119
- '5 min'.before_now
120
- '5 min'.before(Time.now)
121
- '10 min'.ago
115
+ 'min'.since('9/18/06 3:00pm')
116
+ 'min'.before('9/18/08 3:00pm')
117
+ 'days'.until('1/1/07')
118
+ '5 min'.from(Time.now)
119
+ '5 min'.from_now
120
+ '5 min'.before_now
121
+ '5 min'.before(Time.now)
122
+ '10 min'.ago
122
123
 
123
124
  Durations may be entered as 'HH:MM:SS, usec' and will be returned in 'hours'.
124
125
 
125
- '1:00'.unit #=> 1 h
126
- '0:30'.unit #=> 0.5 h
127
- '0:30:30'.unit #=> 0.5 h + 30 sec
126
+ '1:00'.unit #=> 1 h
127
+ '0:30'.unit #=> 0.5 h
128
+ '0:30:30'.unit #=> 0.5 h + 30 sec
128
129
 
129
130
  If only one ":" is present, it is interpreted as the separator between hours and minutes.
130
131
 
131
132
  ==Ranges
132
133
 
133
- [U('0 h')..U('10 h')].each {|x| p x}
134
+ [U('0 h')..U('10 h')].each {|x| p x}
134
135
  works so long as the starting point has an integer scalar
135
136
 
136
137
  ==Math functions
@@ -145,29 +146,29 @@ Temperature units (i.e., 'tempK') can be converted back and forth, and will take
145
146
  the differences in the zero points of the various scales. Differential temperature (e.g., '100 degC'.unit)
146
147
  units behave like most other units.
147
148
 
148
- '37 tempC'.unit >> 'tempF' #=> 98.6 tempF
149
+ '37 tempC'.unit >> 'tempF' #=> 98.6 tempF
149
150
 
150
151
  Ruby-units will raise an exception if you attempt to create a temperature unit that would
151
152
  fall below absolute zero.
152
153
 
153
154
  Unit math on temperatures is fairly limited.
154
155
 
155
- '100 tempC'.unit + '10 degC'.unit #=> '110 tempC'.unit
156
- '100 tempC'.unit - '10 degC'.unit #=> '90 tempC'.unit
157
- '100 tempC'.unit + '50 tempC'.unit #=> exception
158
- '100 tempC'.unit - '50 tempC'.unit #=> '50 degC'.unit
159
- '50 tempC'.unit - '100 tempC'.unit #=> '-50 degC'.unit
160
- '100 tempC'.unit * [scalar] #=> '100*scalar tempC'.unit
161
- '100 tempC'.unit / [scalar] #=> '100/scalar tempC'.unit
162
- '100 tempC'.unit * [unit] #=> exception
163
- '100 tempC'.unit / [unit] #=> exception
164
- '100 tempC'.unit ** N #=> exception
165
-
166
- '100 tempC'.unit >> 'degC' #=> '100 degC'.unit
167
- This conversion references the 0 point on the scale of the temperature unit
168
-
169
- '100 degC'.unit >> 'tempC' #=> '-173 tempC'.unit
170
- These conversions are always interpreted as being relative to absolute zero.
171
- Conversions are probably better done like this...
172
- '0 tempC'.unit + '100 degC'.unit #=> '100 tempC'.unit
156
+ '100 tempC'.unit + '10 degC'.unit #=> '110 tempC'.unit
157
+ '100 tempC'.unit - '10 degC'.unit #=> '90 tempC'.unit
158
+ '100 tempC'.unit + '50 tempC'.unit #=> exception
159
+ '100 tempC'.unit - '50 tempC'.unit #=> '50 degC'.unit
160
+ '50 tempC'.unit - '100 tempC'.unit #=> '-50 degC'.unit
161
+ '100 tempC'.unit * [scalar] #=> '100*scalar tempC'.unit
162
+ '100 tempC'.unit / [scalar] #=> '100/scalar tempC'.unit
163
+ '100 tempC'.unit * [unit] #=> exception
164
+ '100 tempC'.unit / [unit] #=> exception
165
+ '100 tempC'.unit ** N #=> exception
166
+
167
+ '100 tempC'.unit >> 'degC' #=> '100 degC'.unit
168
+ This conversion references the 0 point on the scale of the temperature unit
169
+
170
+ '100 degC'.unit >> 'tempC' #=> '-173 tempC'.unit
171
+ These conversions are always interpreted as being relative to absolute zero.
172
+ Conversions are probably better done like this...
173
+ '0 tempC'.unit + '100 degC'.unit #=> '100 tempC'.unit
173
174
 
data/Rakefile CHANGED
@@ -2,11 +2,14 @@ require 'rubygems'
2
2
  require 'hoe'
3
3
  require './lib/ruby_units/units'
4
4
  require './lib/ruby_units/ruby-units'
5
- require 'rcov/rcovtask'
6
5
 
7
- Rcov::RcovTask.new do |t|
8
- t.test_files = FileList['test/test*.rb']
9
- #t.verbose = true # uncomment to see the executed command
6
+ begin
7
+ require 'rcov/rcovtask'
8
+ Rcov::RcovTask.new do |t|
9
+ t.test_files = FileList['test/test*.rb']
10
+ #t.verbose = true # uncomment to see the executed command
11
+ end
12
+ rescue
10
13
  end
11
14
 
12
15
  Hoe.new('ruby-units', Unit::VERSION) do |p|
@@ -40,7 +40,7 @@ require 'parsedate'
40
40
  # Unit.setup
41
41
  class Unit < Numeric
42
42
  # pre-generate hashes from unit definitions for performance.
43
- VERSION = '1.1.0'
43
+ VERSION = '1.1.2'
44
44
  @@USER_DEFINITIONS = {}
45
45
  @@PREFIX_VALUES = {}
46
46
  @@PREFIX_MAP = {}
@@ -52,7 +52,7 @@ class Unit < Numeric
52
52
  UNITY_ARRAY= [UNITY]
53
53
  FEET_INCH_REGEX = /(\d+)\s*(?:'|ft|feet)\s*(\d+)\s*(?:"|in|inches)/
54
54
  TIME_REGEX = /(\d+)*:(\d+)*:*(\d+)*[:,]*(\d+)*/
55
- LBS_OZ_REGEX = /(\d+)\s*(?:#|lbs|pounds)+[\s,]*(\d+)\s*(?:oz|ounces)/
55
+ LBS_OZ_REGEX = /(\d+)\s*(?:#|lbs|pounds|pound-mass)+[\s,]*(\d+)\s*(?:oz|ounces)/
56
56
  SCI_NUMBER = %r{([+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*)}
57
57
  RATIONAL_NUMBER = /(\d+)\/(\d+)/
58
58
  COMPLEX_NUMBER = /#{SCI_NUMBER}?#{SCI_NUMBER}i\b/
@@ -240,7 +240,6 @@ class Unit < Numeric
240
240
  self.update_base_scalar
241
241
  raise ArgumentError, "Temperature out of range" if self.is_temperature? && self.base_scalar < 0
242
242
 
243
-
244
243
  unary_unit = self.units || ""
245
244
  opt_units = options[0].scan(NUMBER_REGEX)[0][1] if String === options[0]
246
245
  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})|i\s?(.+)?|&plusmn;|\+\/-/)
@@ -270,6 +269,11 @@ class Unit < Numeric
270
269
  return @@base_unit_cache
271
270
  end
272
271
 
272
+ def self.parse(input)
273
+ first, second = input.scan(/(.+)\s(?:in|to|as)\s(.+)/i).first
274
+ second.nil? ? first.unit : first.unit.to(second)
275
+ end
276
+
273
277
  def to_unit
274
278
  self
275
279
  end
@@ -382,10 +386,13 @@ class Unit < Numeric
382
386
  self.to_s
383
387
  end
384
388
 
389
+ # true if unit is a 'temperature', false if a 'degree' or anything else
385
390
  def is_temperature?
386
391
  return true if self.signature == 400 && self.units =~ /temp/
387
392
  end
388
393
 
394
+ # returns the 'degree' unit associated with a temperature unit
395
+ # '100 tempC'.unit.temperature_scale #=> 'degC'
389
396
  def temperature_scale
390
397
  return nil unless self.is_temperature?
391
398
  self.units =~ /temp(C|F|R|K)/
@@ -456,7 +463,7 @@ class Unit < Numeric
456
463
  case
457
464
  when self.zero? : other.dup
458
465
  when self =~ other :
459
- raise ArgumentError, "Cannot add two temperatures" if (self.is_temperature? && other.is_temperature?)
466
+ raise ArgumentError, "Cannot add two temperatures" if ([self, other].all? {|x| x.is_temperature?})
460
467
  if [self, other].any? {|x| x.is_temperature?}
461
468
  case self.is_temperature?
462
469
  when true:
@@ -492,7 +499,7 @@ class Unit < Numeric
492
499
  when self.is_temperature? :
493
500
  Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => ['<temp-K>'], :denominator => UNITY_ARRAY, :signature => @signature).to(self)
494
501
  when other.is_temperature? :
495
- raise ArgumentError, "Cannot subtract a temperature from a differential unit"
502
+ raise ArgumentError, "Cannot subtract a temperature from a differential degree unit"
496
503
  else
497
504
  @q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.unit.scalar/self.units.unit.to_base.scalar))
498
505
  Unit.new(:scalar=>(self.base_scalar - other.base_scalar)*@q, :numerator=>@numerator, :denominator=>@denominator, :signature=>@signature)
@@ -552,7 +559,7 @@ class Unit < Numeric
552
559
  #
553
560
  # For now, if a rational is passed in, it will be used, otherwise we are stuck with integers and certain floats < 1
554
561
  def **(other)
555
- raise ArgumentError, "Cannot exponentiate a temperature" if self.is_temperature?
562
+ raise ArgumentError, "Cannot raise a temperature to a power" if self.is_temperature?
556
563
  if Numeric === other
557
564
  return Unit("1") if other.zero?
558
565
  return self if other == 1
@@ -660,43 +667,6 @@ class Unit < Numeric
660
667
  when 'tempR' : @base_scalar * (9.0/5.0)
661
668
  end
662
669
 
663
- =begin
664
- q=case start_unit
665
- when /\A(temp|deg)C\Z/:
666
- case target_unit
667
- when 'tempC' : @scalar
668
- when 'tempK' : @scalar + 273.15
669
- when 'tempF' : @scalar * (9.0/5.0) + 32.0
670
- when 'tempR' : @scalar * (9.0/5.0) + 491.67
671
- end
672
- when /\A(temp|deg)K\Z/:
673
- case target_unit
674
- when 'tempC' : @scalar - 273.15
675
- when 'tempK' : @scalar
676
- when 'tempF' : @scalar * (9.0/5.0) - 459.67
677
- when 'tempR' : @scalar * (9.0/5.0)
678
- end
679
- when /\A(temp|deg)F\Z/:
680
- case target_unit
681
- when 'tempC' : (@scalar-32)*(5.0/9.0)
682
- when 'tempK' : (@scalar+459.67)*(5.0/9.0)
683
- when 'tempF' : @scalar
684
- when 'tempR' : @scalar + 459.67
685
- end
686
- when /\A(temp|deg)R\Z/:
687
- case target_unit
688
- when 'tempC' : @scalar*(5.0/9.0) -273.15
689
- when 'tempK' : @scalar*(5.0/9.0)
690
- when 'tempF' : @scalar - 459.67
691
- when 'tempR' : @scalar
692
- end
693
-
694
- else
695
- return self.to_base.to(other) unless self.is_base?
696
- #raise ArgumentError, "Unknown temperature conversion requested #{self.numerator}"
697
- end
698
- =end
699
- #target_unit =~ /temp(C|K|F|R)/
700
670
  Unit.new("#{q} #{target_unit}")
701
671
  else
702
672
  case other
@@ -775,7 +745,6 @@ class Unit < Numeric
775
745
 
776
746
  # negates the scalar of the Unit
777
747
  def -@
778
- #raise ArgumentError, "Cannot negate an absolute temperature" if self.is_temperature? && ['degK','degR'].include?(self.temperature_scale)
779
748
  return -@scalar if self.unitless?
780
749
  self.dup * -1
781
750
  end
@@ -923,9 +892,6 @@ class Unit < Numeric
923
892
  end
924
893
  end
925
894
 
926
-
927
-
928
-
929
895
  # calculates the unit signature vector used by unit_signature
930
896
  def unit_signature_vector
931
897
  return self.to_base.unit_signature_vector unless self.is_base?
@@ -950,8 +916,7 @@ class Unit < Numeric
950
916
 
951
917
  def initialize_copy(other)
952
918
  @numerator = other.numerator.dup
953
- @denominator = other.denominator.dup
954
-
919
+ @denominator = other.denominator.dup
955
920
  end
956
921
 
957
922
  # calculates the unit signature id for use in comparing compatible units and simplification
@@ -1033,8 +998,6 @@ class Unit < Numeric
1033
998
  if unit_string =~ /\$\s*(#{NUMBER_REGEX})/
1034
999
  unit_string = "#{$1} USD"
1035
1000
  end
1036
-
1037
-
1038
1001
  unit_string.gsub!(/%/,'percent')
1039
1002
  unit_string.gsub!(/'/,'feet')
1040
1003
  unit_string.gsub!(/"/,'inch')
@@ -1123,7 +1086,6 @@ class Unit < Numeric
1123
1086
  @numerator = top.scan(@@UNIT_MATCH_REGEX).delete_if {|x| x.empty?}.compact if top
1124
1087
  @denominator = bottom.scan(@@UNIT_MATCH_REGEX).delete_if {|x| x.empty?}.compact if bottom
1125
1088
  us = "#{(top || '' + bottom || '')}".to_s.gsub(@@UNIT_MATCH_REGEX,'').gsub(/[\d\*, "'_^\/\$]/,'')
1126
-
1127
1089
  raise( ArgumentError, "'#{passed_unit_string}' Unit not recognized") unless us.empty?
1128
1090
 
1129
1091
  @numerator = @numerator.map do |item|
@@ -11,7 +11,7 @@ class String
11
11
  def %(*args)
12
12
  case args[0]
13
13
  when Unit: args[0].to_s(self)
14
- when defined?(Uncertain) && Uncertain === args[0]: args[0].to_s(self)
14
+ when (Object.const_defined?('Uncertain') && (Uncertain === args[0])): args[0].to_s(self)
15
15
  when Complex: args[0].to_s
16
16
  else
17
17
  unit_format(*args)
@@ -28,9 +28,12 @@ class Time
28
28
  DateTime.civil(1970,1,1)+(self.to_f+self.gmt_offset)/86400
29
29
  end
30
30
 
31
- def to_date
32
- x=(Date.civil(1970,1,1)+((self.to_f+self.gmt_offset)/86400.0)-0.5)
33
- Date.civil(x.year, x.month, x.day)
31
+ # ruby 1.8.6 has a reasonable implementation of this that works well, so let's use it.
32
+ if VERSION == "1.8.4"
33
+ def to_date
34
+ x=(Date.civil(1970,1,1)+((self.to_f+self.gmt_offset)/86400.0)-0.5)
35
+ Date.civil(x.year, x.month, x.day )
36
+ end
34
37
  end
35
38
 
36
39
  def +(other)
@@ -64,7 +64,7 @@ UNIT_DEFINITIONS = {
64
64
  '<short-ton>' => [%w{tn ton}, 907.18474, :mass, %w{<kilogram>}],
65
65
  '<metric-ton>'=>[%w{tonne}, 1000, :mass, %w{<kilogram>}],
66
66
  '<carat>' => [%w{ct carat carats}, 0.0002, :mass, %w{<kilogram>}],
67
- '<pound-mass>' => [%w{lbs lb pound pounds #}, 0.45359237, :mass, %w{<kilogram>}],
67
+ '<pound>' => [%w{lbs lb pound pounds #}, 0.45359237, :mass, %w{<kilogram>}],
68
68
  '<ounce>' => [%w{oz ounce ounces}, 0.0283495231, :mass, %w{<kilogram>}],
69
69
  '<gram>' => [%w{g gram grams gramme grammes},1e-3,:mass, %w{<kilogram>}],
70
70
 
@@ -1,11 +1,9 @@
1
1
  require 'test/unit'
2
2
  require 'ruby-units'
3
3
  require 'rubygems'
4
- require 'uncertain'
4
+ require 'uncertain' if Gem::GemPathSearcher.new.find('uncertain')
5
5
  require 'yaml'
6
- require 'chronic'
7
-
8
-
6
+ require 'chronic' if Gem::GemPathSearcher.new.find('chronic')
9
7
 
10
8
  class Unit < Numeric
11
9
  @@USER_DEFINITIONS = {'<inchworm>' => [%w{inworm inchworm}, 0.0254, :length, %w{<meter>} ],
@@ -15,6 +13,7 @@ end
15
13
 
16
14
  class Time
17
15
  @@forced_now = nil
16
+ @@forced_gmt = nil
18
17
  class << self
19
18
  alias :unforced_now :now
20
19
  def forced_now
@@ -25,8 +24,18 @@ class Time
25
24
  def forced_now=(now)
26
25
  @@forced_now = now
27
26
  end
27
+ end
28
28
 
29
+ alias :unforced_gmt :gmt_offset
30
+ def forced_gmt
31
+ return @@forced_gmt ? @@forced_gmt : unforced_gmt
32
+ end
33
+ alias :gmt_offset :forced_gmt
34
+
35
+ def forced_gmt=(gmt)
36
+ @@forced_gmt = now
29
37
  end
38
+
30
39
  end
31
40
 
32
41
  class DateTime
@@ -746,7 +755,7 @@ class TestRubyUnits < Test::Unit::TestCase
746
755
  a = '1 +/- 1 mm'.unit
747
756
  assert_equal a.to_s, '1 +/- 1 mm'
748
757
  else
749
- fail "Can't test Uncertain Units unless 'Uncertain' gem is installed"
758
+ puts "Can't test Uncertain Units unless 'Uncertain' gem is installed"
750
759
  end
751
760
  end
752
761
 
@@ -869,7 +878,25 @@ class TestRubyUnits < Test::Unit::TestCase
869
878
 
870
879
  def test_to_date
871
880
  a = Time.now
872
- assert_equal a.to_date, Date.today
881
+ assert_equal a.send(:to_date), Date.today
882
+ end
883
+
884
+ def test_natural_language
885
+ assert_equal Unit.parse("10 mm in cm"), '10 mm'.unit.to('cm')
873
886
  end
887
+
888
+ def test_round_pounds
889
+ assert_equal '1 lbs'.unit, '1.1 lbs'.unit.round
890
+ end
891
+
892
+ def test_explicit_init
893
+ assert_equal '1 lbf'.unit, '1 <pound-force>'.unit
894
+ assert_equal '1 lbs'.unit, '1 <pound>'.unit
895
+ end
896
+
897
+ def test_format_nil_string
898
+ assert_nothing_raised {"" % nil}
899
+ end
900
+
874
901
  end
875
902
 
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.1
2
+ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: ruby-units
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.1.0
7
- date: 2007-01-28 00:00:00 -05:00
6
+ version: 1.1.2
7
+ date: 2007-12-13 00:00:00 -05:00
8
8
  summary: A model that performs unit conversions and unit math
9
9
  require_paths:
10
10
  - lib
@@ -49,10 +49,14 @@ files:
49
49
  - test/test_ruby-units.rb
50
50
  test_files:
51
51
  - test/test_ruby-units.rb
52
- rdoc_options: []
53
-
54
- extra_rdoc_files: []
55
-
52
+ rdoc_options:
53
+ - --main
54
+ - README.txt
55
+ extra_rdoc_files:
56
+ - CHANGELOG.txt
57
+ - Manifest.txt
58
+ - README.txt
59
+ - LICENSE.txt
56
60
  executables: []
57
61
 
58
62
  extensions: []
@@ -67,5 +71,5 @@ dependencies:
67
71
  requirements:
68
72
  - - ">="
69
73
  - !ruby/object:Gem::Version
70
- version: 1.1.7
74
+ version: 1.3.0
71
75
  version: