ruby-units 1.4.5 → 2.0.0

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.
@@ -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