ruby-units 1.4.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,86 +6,22 @@ require './lib/ruby-units'
6
6
  begin
7
7
  require 'jeweler'
8
8
  Jeweler::Tasks.new do |gem|
9
- gem.name = "ruby-units"
10
- gem.summary = %Q{A class that performs unit conversions and unit math}
11
- gem.description = %Q{Provides classes and methods to perform unit math and conversions}
12
- gem.authors = ["Kevin Olbrich, Ph.D."]
13
- gem.email = ["kevin.olbrich+ruby_units@gmail.com"]
14
- gem.homepage = "https://github.com/olbrich/ruby-units"
15
- gem.files.exclude(".*","test/**/*","spec/**/*","autotest/**/*", "Gemfile")
16
- gem.license = "MIT"
17
- gem.post_install_message = <<-EOS
18
- ====================
19
- Deprecation Warning
20
- ====================
21
-
22
- Several convenience methods that ruby-units added to the string class have
23
- been deprecated in this release. These methods include String#to, String#from, String#ago, String#before and others.
24
- If your code relies on these functions, they can be added back by adding this line to your code.
25
-
26
- require 'ruby-units/string/extras'
27
- # note that these methods do not play well with Rails, which is one of the reasons they are being removed.
28
-
29
- The extra functions mostly work the same, but will no longer properly handle cases when they are called with strings..
30
-
31
- 'min'.from("4-1-2011") # => Exception
32
-
33
- Pass in a Date, Time, or DateTime object to get the expected result.
34
-
35
- They will go away completely in the next release, so it would be a good idea to refactor your code
36
- to avoid using them. They will also throw deprecation warnings when they are used.
37
- EOS
9
+ gem.name = 'ruby-units'
10
+ gem.summary = 'A class that performs unit conversions and unit math'
11
+ gem.description = 'Provides classes and methods to perform unit math and conversions'
12
+ gem.authors = ['Kevin Olbrich, Ph.D.']
13
+ gem.email = ['kevin.olbrich+ruby_units@gmail.com']
14
+ gem.homepage = 'https://github.com/olbrich/ruby-units'
15
+ gem.files.exclude('.*', 'test/**/*', 'spec/**/*', 'Gemfile', 'Guardfile')
16
+ gem.license = 'MIT'
38
17
  end
39
18
  Jeweler::GemcutterTasks.new
40
19
  rescue LoadError
41
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
42
- end
43
-
44
- begin
45
- require 'simplecov'
46
- desc "code coverage report using simplecov (ruby 1.9+)"
47
- task :simplecov do
48
- ENV['COVERAGE']='true'
49
- Rake::Task['spec'].invoke
50
- end
51
- rescue LoadError
52
- end
53
-
54
- begin
55
- require 'rspec/core/rake_task'
56
-
57
- desc "Run specs"
58
- RSpec::Core::RakeTask.new do |spec|
59
- puts
60
- # puts %x{rvm current}
61
- puts
62
- end
63
-
64
- desc "Run all specs with rcov"
65
- RSpec::Core::RakeTask.new("spec:rcov") do |t|
66
- t.rcov = true
67
- t.rcov_opts = %w{--exclude osx\/objc,gems\/,spec\/,features\/}
68
- end
69
- rescue LoadError
70
- end
71
-
72
- task :specs => :spec
73
-
74
- rubies = {
75
- "ruby-1.8.7" => %w{ruby-1.8.7-p357@ruby-units ruby-1.8.7-p357@ruby-units-with-chronic},
76
- "ruby-1.9.2" => %w{ruby-1.9.2-p290@ruby-units ruby-1.9.2-p290@ruby-units-with-chronic},
77
- "rbx" => %w{rbx-head@ruby-units},
78
- "jruby" => %w{jruby-1.6.7@ruby-units}
79
- }
80
-
81
- rubies.each do |name, ruby|
82
- desc "Run Spec against #{name}"
83
- task "spec:#{name}" do
84
- sh "rvm #{ruby.join(',')} do rake spec"
85
- end
20
+ puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler'
86
21
  end
87
22
 
88
- desc "Run specs against several ruby versions, requires rvm"
89
- task "spec:all" => rubies.keys.map {|name| "spec:#{name}"}
23
+ require 'rspec/core/rake_task'
24
+ desc 'Run specs'
25
+ RSpec::Core::RakeTask.new
90
26
 
91
- task :default => :spec
27
+ task default: :spec
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.5
1
+ 2.0.0
@@ -1,9 +1,3 @@
1
1
  $LOAD_PATH << File.dirname(__FILE__)
2
-
3
2
  require_relative 'ruby_units/namespaced'
4
-
5
- # only include the Unit('unit') helper if we aren't fully namespaced
6
- require_relative 'ruby_units/object'
7
-
8
-
9
3
  Unit = RubyUnits::Unit
@@ -1,11 +1,9 @@
1
1
  class Array
2
2
  # Construct a unit from an array
3
- # @example [1, 'mm'].to_unit => RubyUnits::Unit("1 mm")
3
+ # @example [1, 'mm'].to_unit => RubyUnits::Unit.new("1 mm")
4
4
  # @return (see RubyUnits::Unit#initialize)
5
5
  # @param [Object] other convert to same units as passed
6
6
  def to_unit(other = nil)
7
7
  other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self)
8
8
  end
9
- alias :unit :to_unit
10
- alias :u :to_unit
11
9
  end
@@ -1,66 +1,64 @@
1
1
  require 'date'
2
2
 
3
3
  # Allow date objects to do offsets by a time unit
4
- # Date.today + U"1 week" => gives today+1 week
4
+ # Date.today + Unit.new("1 week") => gives today+1 week
5
5
  class Date
6
- alias :unit_date_add :+
7
- # @param [Object] unit
6
+ alias_method :unit_date_add, :+
7
+ # @param [Object] other
8
8
  # @return [Unit]
9
- def +(unit)
10
- case unit
11
- when Unit
12
- unit = unit.convert_to('d').round if ['y', 'decade', 'century'].include? unit.units
13
- unit_date_add(unit.convert_to('day').scalar)
9
+ def +(other)
10
+ case other
11
+ when RubyUnits::Unit
12
+ other = other.convert_to('d').round if %w(y decade century).include? other.units
13
+ unit_date_add(other.convert_to('day').scalar)
14
14
  else
15
- unit_date_add(unit)
15
+ unit_date_add(other)
16
16
  end
17
17
  end
18
-
19
- alias :unit_date_sub :-
20
- # @param [Object] unit
18
+
19
+ alias_method :unit_date_sub, :-
20
+ # @param [Object] other
21
21
  # @return [Unit]
22
- def -(unit)
23
- case unit
24
- when Unit
25
- unit = unit.convert_to('d').round if ['y', 'decade', 'century'].include? unit.units
26
- unit_date_sub(unit.convert_to('day').scalar)
22
+ def -(other)
23
+ case other
24
+ when RubyUnits::Unit
25
+ other = other.convert_to('d').round if %w(y decade century).include? other.units
26
+ unit_date_sub(other.convert_to('day').scalar)
27
27
  else
28
- unit_date_sub(unit)
28
+ unit_date_sub(other)
29
29
  end
30
30
  end
31
-
31
+
32
32
  # Construct a unit from a Date
33
33
  # @example Date.today.to_unit => Unit
34
34
  # @return (see Unit#initialize)
35
35
  # @param [Object] other convert to same units as passed
36
36
  def to_unit(other = nil)
37
- other ? Unit.new(self).convert_to(other) : Unit.new(self)
37
+ other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self)
38
38
  end
39
- alias :unit :to_unit
40
-
39
+
41
40
  # :nocov_19:
42
41
  unless Date.instance_methods.include?(:to_time)
43
42
  # @return [Time]
44
43
  def to_time
45
- Time.local(*ParseDate.parsedate(self.to_s))
44
+ Time.local(*ParseDate.parsedate(to_s))
46
45
  end
47
46
  end
48
47
  # :nocov_19:
49
-
50
- alias :units_datetime_inspect :inspect
48
+
49
+ alias_method :units_datetime_inspect, :inspect
51
50
  # @deprecated
52
- def inspect(raw = false)
53
- return self.units_datetime_inspect if raw
54
- self.to_s
51
+ def inspect(dump = false)
52
+ return units_datetime_inspect if dump
53
+ to_s
55
54
  end
56
-
55
+
57
56
  unless Date.instance_methods.include?(:to_date)
58
57
  # :nocov_19:
59
58
  # @return [Date]
60
59
  def to_date
61
- Date.civil(self.year, self.month, self.day)
60
+ Date.civil(year, month, day)
62
61
  end
63
62
  # :nocov_19:
64
63
  end
65
-
66
- end
64
+ end
@@ -2,32 +2,32 @@ class RubyUnits::Unit < Numeric
2
2
 
3
3
  # Handle the definition of units
4
4
  class Definition
5
-
5
+
6
6
  # @return [Array]
7
7
  attr_writer :aliases
8
-
8
+
9
9
  # @return [Symbol]
10
10
  attr_accessor :kind
11
-
11
+
12
12
  # @return [Numeric]
13
13
  attr_accessor :scalar
14
-
14
+
15
15
  # @return [Array]
16
16
  attr_accessor :numerator
17
17
 
18
18
  # @return [Array]
19
19
  attr_accessor :denominator
20
-
20
+
21
21
  # @return [String]
22
22
  attr_accessor :display_name
23
-
23
+
24
24
  # @example Raw definition from a hash
25
25
  # Unit::Definition.new("rack-unit",[%w{U rack-U}, (6405920109971793/144115188075855872), :length, %w{<meter>} ])
26
- #
26
+ #
27
27
  # @example Block form
28
28
  # Unit::Definition.new("rack-unit") do |unit|
29
29
  # unit.aliases = %w{U rack-U}
30
- # unit.definition = Unit("7/4 inches")
30
+ # unit.definition = RubyUnits::Unit.new("7/4 inches")
31
31
  # end
32
32
  #
33
33
  def initialize(_name, _definition = [], &block)
@@ -40,7 +40,7 @@ class RubyUnits::Unit < Numeric
40
40
  @denominator ||= _definition[4] || RubyUnits::Unit::UNITY_ARRAY
41
41
  @display_name ||= @aliases.first
42
42
  end
43
-
43
+
44
44
  # name of the unit
45
45
  # nil if name is not set, adds '<' and '>' around the name
46
46
  # @return [String, nil]
@@ -48,14 +48,14 @@ class RubyUnits::Unit < Numeric
48
48
  def name
49
49
  "<#{@name}>" if (defined?(@name) && @name)
50
50
  end
51
-
51
+
52
52
  # set the name, strip off '<' and '>'
53
53
  # @param [String]
54
54
  # @return [String]
55
55
  def name=(_name)
56
56
  @name = _name.gsub(/[<>]/,'')
57
57
  end
58
-
58
+
59
59
  # alias array must contain the name of the unit and entries must be unique
60
60
  # @return [Array]
61
61
  def aliases
@@ -79,13 +79,13 @@ class RubyUnits::Unit < Numeric
79
79
  def prefix?
80
80
  self.kind == :prefix
81
81
  end
82
-
82
+
83
83
  # Is this definition the unity definition?
84
84
  # @return [Boolean]
85
85
  def unity?
86
86
  self.prefix? && self.scalar == 1
87
87
  end
88
-
88
+
89
89
  # is this a base unit?
90
90
  # units are base units if the scalar is one, and the unit is defined in terms of itself.
91
91
  # @return [Boolean]
@@ -12,5 +12,4 @@ require_relative 'math'
12
12
  require_relative 'numeric'
13
13
  require_relative 'string'
14
14
  require_relative 'unit'
15
- require_relative 'fixnum'
16
15
  require_relative 'unit_definitions'
@@ -4,6 +4,4 @@ class Numeric
4
4
  def to_unit(other = nil)
5
5
  other ? RubyUnits::Unit.new(self, other) : RubyUnits::Unit.new(self)
6
6
  end
7
- alias :unit :to_unit
8
- alias :u :to_unit
9
7
  end
@@ -5,31 +5,24 @@ class String
5
5
  def to_unit(other = nil)
6
6
  other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self)
7
7
  end
8
- alias :unit :to_unit
9
- alias :u :to_unit
10
8
 
11
-
12
- alias :unit_format :%
13
- # format unit output using formating codes
14
- # @example '%0.2f' % '1 mm'.unit => '1.00 mm'
9
+ alias_method :original_format, :%
10
+ # format unit output using formating codes
11
+ # @example '%0.2f' % '1 mm'.to_unit => '1.00 mm'
15
12
  # @return [String]
16
- def %(*args)
17
- return "" if self.empty?
18
- case
19
- when args.first.is_a?(RubyUnits::Unit)
20
- args.first.to_s(self)
21
- when (!defined?(Uncertain).nil? && args.first.is_a?(Uncertain))
22
- args.first.to_s(self)
23
- when args.first.is_a?(Complex)
24
- args.first.to_s
13
+ def format_with_unit(*other)
14
+ case
15
+ when other.first.is_a?(RubyUnits::Unit)
16
+ other.first.to_s(self)
25
17
  else
26
- unit_format(*args)
18
+ original_format(*other)
27
19
  end
28
20
  end
29
-
21
+ alias_method :%, :format_with_unit
22
+
30
23
  # @param (see RubyUnits::Unit#convert_to)
31
24
  # @return (see RubyUnits::Unit#convert_to)
32
25
  def convert_to(other)
33
- self.unit.convert_to(other)
26
+ to_unit.convert_to(other)
34
27
  end
35
28
  end
@@ -2,15 +2,15 @@ require 'time'
2
2
  #
3
3
  # Time math is handled slightly differently. The difference is considered to be an exact duration if
4
4
  # the subtracted value is in hours, minutes, or seconds. It is rounded to the nearest day if the offset
5
- # is in years, decades, or centuries. This leads to less precise values, but ones that match the
5
+ # is in years, decades, or centuries. This leads to less precise values, but ones that match the
6
6
  # calendar better.
7
7
  class Time
8
-
8
+
9
9
  class << self
10
10
  alias unit_time_at at
11
11
  end
12
-
13
- # Convert a duration to a Time value by considering the duration to be the number of seconds since the
12
+
13
+ # Convert a duration to a Time value by considering the duration to be the number of seconds since the
14
14
  # epoch
15
15
  # @param [Time] arg
16
16
  # @param [Integer] ms
@@ -34,21 +34,19 @@ class Time
34
34
  def to_unit(other = nil)
35
35
  other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self)
36
36
  end
37
- alias :unit :to_unit
38
- alias :u :to_unit
39
37
 
40
38
  unless Time.public_method_defined?(:to_date)
41
39
  # :nocov_19:
42
40
  public :to_date
43
41
  # :nocov_19:
44
42
  end
45
-
43
+
46
44
  alias :unit_add :+
47
45
  # @return [RubyUnits::Unit, Time]
48
46
  def +(other)
49
47
  case other
50
48
  when RubyUnits::Unit
51
- other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units
49
+ other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units
52
50
  begin
53
51
  unit_add(other.convert_to('s').scalar)
54
52
  rescue RangeError
@@ -58,21 +56,21 @@ class Time
58
56
  unit_add(other)
59
57
  end
60
58
  end
61
-
59
+
62
60
  # @example
63
61
  # Time.in '5 min'
64
62
  # @return (see Time#+)
65
63
  def self.in(duration)
66
64
  Time.now + duration.to_unit
67
65
  end
68
-
66
+
69
67
  alias :unit_sub :-
70
-
68
+
71
69
  # @return [RubyUnits::Unit, Time]
72
70
  def -(other)
73
71
  case other
74
72
  when RubyUnits::Unit
75
- other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units
73
+ other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units
76
74
  begin
77
75
  unit_sub(other.convert_to('s').scalar)
78
76
  rescue RangeError
@@ -1,13 +1,6 @@
1
1
  # encoding: utf-8
2
2
  require 'date'
3
- if RUBY_VERSION < "1.9"
4
- # :nocov_19:
5
- require 'parsedate'
6
- require 'rational'
7
- # :nocov_19:
8
- end
9
- # Copyright 2006-2012
10
- #
3
+ # Copyright 2006-2015
11
4
  # @author Kevin C. Olbrich, Ph.D.
12
5
  # @see https://github.com/olbrich/ruby-units
13
6
  #
@@ -28,10 +21,6 @@ end
28
21
  # unit.definition = RubyUnits::Unit.new("1 baz")
29
22
  # end
30
23
  #
31
- # @todo fix class variables so they conform to standard naming conventions and refactor away as many of them as possible
32
- # @todo pull caching out into its own class
33
- # @todo refactor internal representation of units
34
- # @todo method to determine best natural prefix
35
24
  module RubyUnits
36
25
  class Unit < Numeric
37
26
  VERSION = Unit::Version::STRING
@@ -44,9 +33,15 @@ module RubyUnits
44
33
  @@UNIT_MATCH_REGEX = nil
45
34
  UNITY = '<1>'
46
35
  UNITY_ARRAY = [UNITY]
47
- FEET_INCH_REGEX = /(\d+)\s*(?:'|ft|feet)\s*(\d+)\s*(?:"|in|inches)/
36
+ # ideally we would like to generate this regex from the alias for a 'feet' and 'inches', but they aren't
37
+ # defined at the point in the code where we need this regex.
38
+ FEET_INCH_UNITS_REGEX = /(?:'|ft|feet)\s*(\d+)\s*(?:"|in|inch(?:es)?)/
39
+ FEET_INCH_REGEX = /(\d+)\s*#{FEET_INCH_UNITS_REGEX}/
40
+ # ideally we would like to generate this regex from the alias for a 'pound' and 'ounce', but they aren't
41
+ # defined at the point in the code where we need this regex.
42
+ LBS_OZ_UNIT_REGEX = /(?:#|lbs?|pounds?|pound-mass)+[\s,]*(\d+)\s*(?:ozs?|ounces?)/
43
+ LBS_OZ_REGEX = /(\d+)\s*#{LBS_OZ_UNIT_REGEX}/
48
44
  TIME_REGEX = /(\d+)*:(\d+)*:*(\d+)*[:,]*(\d+)*/
49
- LBS_OZ_REGEX = /(\d+)\s*(?:#|lbs|pounds|pound-mass)+[\s,]*(\d+)\s*(?:oz|ounces)/
50
45
  SCI_NUMBER = %r{([+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*)}
51
46
  RATIONAL_NUMBER = /\(?([+-])?(\d+[ -])?(\d+)\/(\d+)\)?/
52
47
  COMPLEX_NUMBER = /#{SCI_NUMBER}?#{SCI_NUMBER}i\b/
@@ -54,7 +49,7 @@ module RubyUnits
54
49
  UNIT_STRING_REGEX = /#{SCI_NUMBER}*\s*([^\/]*)\/*(.+)*/
55
50
  TOP_REGEX = /([^ \*]+)(?:\^|\*\*)([\d-]+)/
56
51
  BOTTOM_REGEX = /([^* ]+)(?:\^|\*\*)(\d+)/
57
- UNCERTAIN_REGEX = /#{SCI_NUMBER}\s*\+\/-\s*#{SCI_NUMBER}\s(.+)/
52
+ NUMBER_UNIT_REGEX = /#{SCI_NUMBER}?(.*)/
58
53
  COMPLEX_REGEX = /#{COMPLEX_NUMBER}\s?(.+)?/
59
54
  RATIONAL_REGEX = /#{RATIONAL_NUMBER}\s?(.+)?/
60
55
  KELVIN = ['<kelvin>']
@@ -199,11 +194,13 @@ module RubyUnits
199
194
  # @yield [RubyUnits::Unit::Definition]
200
195
  # @return (see RubyUnits::Unit.define)
201
196
  # Get the definition for a unit and allow it to be redefined
202
- def self.redefine!(name, &block)
203
- raise ArgumentError, "A block is required to redefine a unit" unless block_given?
204
- unit_definition = self.definition(name)
197
+ def self.redefine!(name)
198
+ fail ArgumentError, 'A block is required to redefine a unit' unless block_given?
199
+ unit_definition = definition(name)
205
200
  yield unit_definition
206
- self.define(unit_definition)
201
+ @@definitions.delete("<#{name}>")
202
+ define(unit_definition)
203
+ RubyUnits::Unit.setup
207
204
  end
208
205
 
209
206
  # @param [String] name of unit to undefine
@@ -264,31 +261,6 @@ module RubyUnits
264
261
  return self
265
262
  end
266
263
 
267
- if RUBY_VERSION < "1.9"
268
- # :nocov_19:
269
-
270
- # a list of properties to emit to yaml
271
- # @return [Array]
272
- def to_yaml_properties
273
- %w{@scalar @numerator @denominator @signature @base_scalar}
274
- end
275
-
276
- # basically a copy of the basic to_yaml. Needed because otherwise it ends up coercing the object to a string
277
- # before YAML'izing it.
278
- # @param [Hash] opts
279
- # @return [String]
280
- def to_yaml(opts = {})
281
- YAML::quick_emit(object_id, opts) do |out|
282
- out.map(taguri, to_yaml_style) do |map|
283
- for m in to_yaml_properties do
284
- map.add(m[1..-1], instance_variable_get(m))
285
- end
286
- end
287
- end
288
- end
289
- # :nocov_19:
290
- end
291
-
292
264
  # Create a new Unit object. Can be initialized using a String, a Hash, an Array, Time, DateTime
293
265
  #
294
266
  # @example Valid options include:
@@ -374,12 +346,14 @@ module RubyUnits
374
346
  unary_unit = self.units || ""
375
347
  if options.first.instance_of?(String)
376
348
  opt_scalar, opt_units = RubyUnits::Unit.parse_into_numbers_and_units(options[0])
377
- unless @@cached_units.keys.include?(opt_units) || (opt_units =~ /(#{RubyUnits::Unit.temp_regex})|(pounds|lbs[ ,]\d+ ounces|oz)|('\d+")|(ft|feet[ ,]\d+ in|inch|inches)|%|(#{TIME_REGEX})|i\s?(.+)?|&plusmn;|\+\/-/)
378
- @@cached_units[opt_units] = (self.scalar == 1 ? self : opt_units.unit) if opt_units && !opt_units.empty?
349
+ unless @@cached_units.keys.include?(opt_units) ||
350
+ (opt_units =~ %r{\D/[\d+\.]+}) ||
351
+ (opt_units =~ /(#{RubyUnits::Unit.temp_regex})|(#{LBS_OZ_UNIT_REGEX})|(#{FEET_INCH_UNITS_REGEX})|%|(#{TIME_REGEX})|i\s?(.+)?|&plusmn;|\+\/-/)
352
+ @@cached_units[opt_units] = (self.scalar == 1 ? self : opt_units.to_unit) if opt_units && !opt_units.empty?
379
353
  end
380
354
  end
381
355
  unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{RubyUnits::Unit.temp_regex}/) then
382
- @@cached_units[unary_unit] = (self.scalar == 1 ? self : unary_unit.unit)
356
+ @@cached_units[unary_unit] = (self.scalar == 1 ? self : unary_unit.to_unit)
383
357
  end
384
358
  [@scalar, @numerator, @denominator, @base_scalar, @signature, @is_base].each { |x| x.freeze }
385
359
  return self
@@ -419,7 +393,7 @@ module RubyUnits
419
393
  # @return [Unit]
420
394
  def self.parse(input)
421
395
  first, second = input.scan(/(.+)\s(?:in|to|as)\s(.+)/i).first
422
- return second.nil? ? first.unit : first.unit.convert_to(second)
396
+ second.nil? ? RubyUnits::Unit.new(first) : RubyUnits::Unit.new(first).convert_to(second)
423
397
  end
424
398
 
425
399
  # @return [Unit]
@@ -448,15 +422,7 @@ module RubyUnits
448
422
  def to_base
449
423
  return self if self.is_base?
450
424
  if @@UNIT_MAP[self.units] =~ /\A<(?:temp|deg)[CRF]>\Z/
451
- if RUBY_VERSION < "1.9"
452
- # :nocov_19:
453
- @signature = @@KINDS.index(:temperature)
454
- # :nocov_19:
455
- else
456
- #:nocov:
457
- @signature = @@KINDS.key(:temperature)
458
- #:nocov:
459
- end
425
+ @signature = @@KINDS.key(:temperature)
460
426
  base = case
461
427
  when self.is_temperature?
462
428
  self.convert_to('tempK')
@@ -494,7 +460,7 @@ module RubyUnits
494
460
  num = num.flatten.compact
495
461
  den = den.flatten.compact
496
462
  num = UNITY_ARRAY if num.empty?
497
- base = RubyUnits::Unit.new(RubyUnits::Unit.eliminate_terms(q, num, den))
463
+ base = RubyUnits::Unit.new(RubyUnits::Unit.eliminate_terms(q, num, den))
498
464
  @@base_unit_cache[self.units]=base
499
465
  return base * @scalar
500
466
  end
@@ -522,36 +488,38 @@ module RubyUnits
522
488
  return out
523
489
  else
524
490
  case target_units
525
- when :ft
526
- inches = self.convert_to("in").scalar.to_int
527
- out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\""
528
- when :lbs
529
- ounces = self.convert_to("oz").scalar.to_int
530
- out = "#{(ounces / 16).truncate} lbs, #{(ounces % 16).round} oz"
531
- when String
532
- out = case target_units
533
- when /(%[\-+\.\w#]+)\s*(.+)*/ #format string like '%0.2f in'
534
- begin
535
- if $2 #unit specified, need to convert
536
- self.convert_to($2).to_s($1)
537
- else
538
- "#{$1 % @scalar} #{$2 || self.units}".strip
539
- end
540
- rescue # parse it like a strftime format string
541
- (DateTime.new(0) + self).strftime(target_units)
542
- end
543
- when /(\S+)/ #unit only 'mm' or '1/mm'
544
- self.convert_to($1).to_s
491
+ when :ft
492
+ inches = self.convert_to("in").scalar.to_int
493
+ out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\""
494
+ when :lbs
495
+ ounces = self.convert_to("oz").scalar.to_int
496
+ out = "#{(ounces / 16).truncate} lbs, #{(ounces % 16).round} oz"
497
+ when String
498
+ out = case target_units.strip
499
+ when /\A\s*\Z/ # whitespace only
500
+ ''
501
+ when /(%[\-+\.\w#]+)\s*(.+)*/ #format string like '%0.2f in'
502
+ begin
503
+ if $2 #unit specified, need to convert
504
+ self.convert_to($2).to_s($1)
545
505
  else
546
- raise "unhandled case"
506
+ "#{$1 % @scalar} #{$2 || self.units}".strip
507
+ end
508
+ rescue # parse it like a strftime format string
509
+ (DateTime.new(0) + self).strftime(target_units)
547
510
  end
548
- else
549
- out = case @scalar
550
- when Rational
551
- "#{@scalar} #{self.units}"
552
- else
553
- "#{'%g' % @scalar} #{self.units}"
554
- end.strip
511
+ when /(\S+)/ #unit only 'mm' or '1/mm'
512
+ self.convert_to($1).to_s
513
+ else
514
+ raise "unhandled case"
515
+ end
516
+ else
517
+ out = case @scalar
518
+ when Rational, Complex
519
+ "#{@scalar} #{self.units}"
520
+ else
521
+ "#{'%g' % @scalar} #{self.units}"
522
+ end.strip
555
523
  end
556
524
  @output[target_units] = out
557
525
  return out
@@ -561,9 +529,9 @@ module RubyUnits
561
529
  # Normally pretty prints the unit, but if you really want to see the guts of it, pass ':dump'
562
530
  # @deprecated
563
531
  # @return [String]
564
- def inspect(option=nil)
565
- return super() if option == :dump
566
- return self.to_s
532
+ def inspect(dump = nil)
533
+ return super() if dump
534
+ to_s
567
535
  end
568
536
 
569
537
  # true if unit is a 'temperature', false if a 'degree' or anything else
@@ -584,7 +552,7 @@ module RubyUnits
584
552
  alias :degree? :is_degree?
585
553
 
586
554
  # returns the 'degree' unit associated with a temperature unit
587
- # @example '100 tempC'.unit.temperature_scale #=> 'degC'
555
+ # @example '100 tempC'.to_unit.temperature_scale #=> 'degC'
588
556
  # @return [String] possible values: degC, degF, degR, or degK
589
557
  def temperature_scale
590
558
  return nil unless self.is_temperature?
@@ -718,7 +686,7 @@ module RubyUnits
718
686
  RubyUnits::Unit.new(:scalar => (other.scalar + self.convert_to(other.temperature_scale).scalar), :numerator => other.numerator, :denominator => other.denominator, :signature => other.signature)
719
687
  end
720
688
  else
721
- @q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.unit.to_base.scalar))
689
+ @q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.to_unit.to_base.scalar))
722
690
  RubyUnits::Unit.new(:scalar => (self.base_scalar + other.base_scalar)*@q, :numerator => @numerator, :denominator => @denominator, :signature => @signature)
723
691
  end
724
692
  else
@@ -757,7 +725,7 @@ module RubyUnits
757
725
  when other.is_temperature?
758
726
  raise ArgumentError, "Cannot subtract a temperature from a differential degree unit"
759
727
  else
760
- @q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.unit.scalar/self.units.unit.to_base.scalar))
728
+ @q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.to_unit.scalar/self.units.to_unit.to_base.scalar))
761
729
  RubyUnits::Unit.new(:scalar => (self.base_scalar - other.base_scalar)*@q, :numerator => @numerator, :denominator => @denominator, :signature => @signature)
762
730
  end
763
731
  else
@@ -1120,18 +1088,10 @@ module RubyUnits
1120
1088
  return RubyUnits::Unit.new(@scalar.floor, @numerator, @denominator)
1121
1089
  end
1122
1090
 
1123
- if RUBY_VERSION < '1.9'
1124
- # @return [Numeric,Unit]
1125
- def round
1126
- return @scalar.round if self.unitless?
1127
- return RubyUnits::Unit.new(@scalar.round, @numerator, @denominator)
1128
- end
1129
- else
1130
- # @return [Numeric,Unit]
1131
- def round(ndigits = 0)
1132
- return @scalar.round(ndigits) if self.unitless?
1133
- return RubyUnits::Unit.new(@scalar.round(ndigits), @numerator, @denominator)
1134
- end
1091
+ # @return [Numeric,Unit]
1092
+ def round(ndigits = 0)
1093
+ return @scalar.round(ndigits) if self.unitless?
1094
+ return RubyUnits::Unit.new(@scalar.round(ndigits), @numerator, @denominator)
1135
1095
  end
1136
1096
 
1137
1097
  # @return [Numeric, Unit]
@@ -1140,7 +1100,7 @@ module RubyUnits
1140
1100
  return RubyUnits::Unit.new(@scalar.truncate, @numerator, @denominator)
1141
1101
  end
1142
1102
 
1143
- # returns next unit in a range. '1 mm'.unit.succ #=> '2 mm'.unit
1103
+ # returns next unit in a range. '1 mm'.to_unit.succ #=> '2 mm'.to_unit
1144
1104
  # only works when the scalar is an integer
1145
1105
  # @return [Unit]
1146
1106
  # @raise [ArgumentError] when scalar is not equal to an integer
@@ -1151,7 +1111,7 @@ module RubyUnits
1151
1111
 
1152
1112
  alias :next :succ
1153
1113
 
1154
- # returns previous unit in a range. '2 mm'.unit.pred #=> '1 mm'.unit
1114
+ # returns previous unit in a range. '2 mm'.to_unit.pred #=> '1 mm'.to_unit
1155
1115
  # only works when the scalar is an integer
1156
1116
  # @return [Unit]
1157
1117
  # @raise [ArgumentError] when scalar is not equal to an integer
@@ -1186,7 +1146,7 @@ module RubyUnits
1186
1146
  return self.base_scalar.zero?
1187
1147
  end
1188
1148
 
1189
- # @example '5 min'.unit.ago
1149
+ # @example '5 min'.to_unit.ago
1190
1150
  # @return [Unit]
1191
1151
  def ago
1192
1152
  return self.before
@@ -1211,12 +1171,12 @@ module RubyUnits
1211
1171
  # @raise [ArgumentError] when time point is not a Time, Date, or DateTime
1212
1172
  def since(time_point)
1213
1173
  case time_point
1214
- when Time
1215
- return (Time.now - time_point).unit('s').convert_to(self)
1216
- when DateTime, Date
1217
- return (DateTime.now - time_point).unit('d').convert_to(self)
1218
- else
1219
- raise ArgumentError, "Must specify a Time, Date, or DateTime"
1174
+ when Time
1175
+ return (Time.now - time_point).to_unit('s').convert_to(self)
1176
+ when DateTime, Date
1177
+ return (DateTime.now - time_point).to_unit('d').convert_to(self)
1178
+ else
1179
+ fail ArgumentError, 'Must specify a Time, Date, or DateTime'
1220
1180
  end
1221
1181
  end
1222
1182
 
@@ -1225,12 +1185,12 @@ module RubyUnits
1225
1185
  # @return [Unit]
1226
1186
  def until(time_point)
1227
1187
  case time_point
1228
- when Time
1229
- return (time_point - Time.now).unit('s').convert_to(self)
1230
- when DateTime, Date
1231
- return (time_point - DateTime.now).unit('d').convert_to(self)
1232
- else
1233
- raise ArgumentError, "Must specify a Time, Date, or DateTime"
1188
+ when Time
1189
+ return (time_point - Time.now).to_unit('s').convert_to(self)
1190
+ when DateTime, Date
1191
+ return (time_point - DateTime.now).to_unit('d').convert_to(self)
1192
+ else
1193
+ fail ArgumentError, 'Must specify a Time, Date, or DateTime'
1234
1194
  end
1235
1195
  end
1236
1196
 
@@ -1409,24 +1369,13 @@ module RubyUnits
1409
1369
  if unit_string =~ /\$\s*(#{NUMBER_REGEX})/
1410
1370
  unit_string = "#{$1} USD"
1411
1371
  end
1412
- unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if RUBY_VERSION >= '1.9' && unit_string.encoding == Encoding::UTF_8
1372
+ unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if unit_string.encoding == Encoding::UTF_8
1413
1373
 
1414
1374
  unit_string.gsub!(/%/, 'percent')
1415
1375
  unit_string.gsub!(/'/, 'feet')
1416
1376
  unit_string.gsub!(/"/, 'inch')
1417
1377
  unit_string.gsub!(/#/, 'pound')
1418
1378
 
1419
- #:nocov:
1420
- #:nocov_19:
1421
- if defined?(Uncertain) && unit_string =~ /(\+\/-|&plusmn;)/
1422
- value, uncertainty, unit_s = unit_string.scan(UNCERTAIN_REGEX)[0]
1423
- result = unit_s.unit * Uncertain.new(value.to_f, uncertainty.to_f)
1424
- copy(result)
1425
- return
1426
- end
1427
- #:nocov:
1428
- #:nocov_19:
1429
-
1430
1379
  if defined?(Complex) && unit_string =~ COMPLEX_NUMBER
1431
1380
  real, imaginary, unit_s = unit_string.scan(COMPLEX_REGEX)[0]
1432
1381
  result = RubyUnits::Unit.new(unit_s || '1') * Complex(real.to_f, imaginary.to_f)
@@ -1463,10 +1412,10 @@ module RubyUnits
1463
1412
  if unit_string =~ /:/
1464
1413
  hours, minutes, seconds, microseconds = unit_string.scan(TIME_REGEX)[0]
1465
1414
  raise ArgumentError, "Invalid Duration" if [hours, minutes, seconds, microseconds].all? { |x| x.nil? }
1466
- result = "#{hours || 0} h".unit +
1467
- "#{minutes || 0} minutes".unit +
1468
- "#{seconds || 0} seconds".unit +
1469
- "#{microseconds || 0} usec".unit
1415
+ result = RubyUnits::Unit.new("#{hours || 0} h") +
1416
+ RubyUnits::Unit.new("#{minutes || 0} minutes") +
1417
+ RubyUnits::Unit.new("#{seconds || 0} seconds") +
1418
+ RubyUnits::Unit.new("#{microseconds || 0} usec")
1470
1419
  copy(result)
1471
1420
  return
1472
1421
  end
@@ -1502,11 +1451,25 @@ module RubyUnits
1502
1451
  bottom = "#{bottom} #{x * -n}"; top.gsub!(/#{item[0]}(\^|\*\*)#{n}/, "")
1503
1452
  end
1504
1453
  end
1505
- bottom.gsub!(BOTTOM_REGEX) { |s| "#{$1} " * $2.to_i } if bottom
1454
+ if bottom
1455
+ bottom.gsub!(BOTTOM_REGEX) { |s| "#{$1} " * $2.to_i }
1456
+ # Separate leading decimal from denominator, if any
1457
+ bottom_scalar, bottom = bottom.scan(NUMBER_UNIT_REGEX)[0]
1458
+ end
1459
+
1506
1460
  @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty?
1507
1461
  @scalar = 1 unless @scalar.kind_of? Numeric
1508
1462
  @scalar = @scalar.to_int if (@scalar.to_int == @scalar)
1509
1463
 
1464
+ case
1465
+ when bottom_scalar.nil? || bottom_scalar.empty?
1466
+ when bottom_scalar.to_i == bottom_scalar
1467
+ @scalar /= bottom_scalar.to_i
1468
+ else
1469
+ @scalar /= bottom_scalar.to_f
1470
+ end
1471
+
1472
+
1510
1473
  @numerator ||= UNITY_ARRAY
1511
1474
  @denominator ||= UNITY_ARRAY
1512
1475
  @numerator = top.scan(RubyUnits::Unit.unit_match_regex).delete_if { |x| x.empty? }.compact if top
@@ -1537,6 +1500,7 @@ module RubyUnits
1537
1500
  end
1538
1501
 
1539
1502
  # parse a string consisting of a number and a unit string
1503
+ # NOTE: This does not properly handle units formatted like '12mg/6ml'
1540
1504
  # @param [String] string
1541
1505
  # @return [Array] consisting of [Numeric, "unit"]
1542
1506
  # @private
@@ -1547,7 +1511,8 @@ module RubyUnits
1547
1511
  rational = %r{\(?[+-]?(?:\d+[ -])?\d+\/\d+\)?}
1548
1512
  # complex numbers... -1.2+3i, +1.2-3.3i
1549
1513
  complex = %r{#{sci}{2,2}i}
1550
- anynumber = %r{(?:(#{complex}|#{rational}|#{sci})\b)?\s?([^-\d\.].*)?}
1514
+ anynumber = %r{(?:(#{complex}|#{rational}|#{sci}))?\s?([^-\d\.].*)?}
1515
+
1551
1516
  num, unit = string.scan(anynumber).first
1552
1517
 
1553
1518
  return [case num