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.
- checksums.yaml +4 -4
- data/CHANGELOG.txt +45 -44
- data/README.md +190 -129
- data/Rakefile.rb +13 -77
- data/VERSION +1 -1
- data/lib/ruby-units.rb +0 -6
- data/lib/ruby_units/array.rb +1 -3
- data/lib/ruby_units/date.rb +30 -32
- data/lib/ruby_units/definition.rb +13 -13
- data/lib/ruby_units/namespaced.rb +0 -1
- data/lib/ruby_units/numeric.rb +0 -2
- data/lib/ruby_units/string.rb +11 -18
- data/lib/ruby_units/time.rb +10 -12
- data/lib/ruby_units/unit.rb +102 -137
- data/lib/ruby_units/unit_definitions/prefix.rb +30 -30
- data/lib/ruby_units/unit_definitions/standard.rb +11 -1
- data/ruby-units.gemspec +9 -14
- metadata +6 -29
- data/TODO +0 -3
- data/lib/ruby_units.rb +0 -9
- data/lib/ruby_units/fixnum.rb +0 -22
- data/lib/ruby_units/object.rb +0 -15
data/Rakefile.rb
CHANGED
@@ -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 =
|
10
|
-
gem.summary =
|
11
|
-
gem.description =
|
12
|
-
gem.authors = [
|
13
|
-
gem.email = [
|
14
|
-
gem.homepage =
|
15
|
-
gem.files.exclude(
|
16
|
-
gem.license =
|
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
|
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
|
-
|
89
|
-
|
23
|
+
require 'rspec/core/rake_task'
|
24
|
+
desc 'Run specs'
|
25
|
+
RSpec::Core::RakeTask.new
|
90
26
|
|
91
|
-
task :
|
27
|
+
task default: :spec
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.0.0
|
data/lib/ruby-units.rb
CHANGED
data/lib/ruby_units/array.rb
CHANGED
@@ -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
|
data/lib/ruby_units/date.rb
CHANGED
@@ -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 +
|
4
|
+
# Date.today + Unit.new("1 week") => gives today+1 week
|
5
5
|
class Date
|
6
|
-
|
7
|
-
# @param [Object]
|
6
|
+
alias_method :unit_date_add, :+
|
7
|
+
# @param [Object] other
|
8
8
|
# @return [Unit]
|
9
|
-
def +(
|
10
|
-
case
|
11
|
-
when Unit
|
12
|
-
|
13
|
-
unit_date_add(
|
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(
|
15
|
+
unit_date_add(other)
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
19
|
-
|
20
|
-
# @param [Object]
|
18
|
+
|
19
|
+
alias_method :unit_date_sub, :-
|
20
|
+
# @param [Object] other
|
21
21
|
# @return [Unit]
|
22
|
-
def -(
|
23
|
-
case
|
24
|
-
when Unit
|
25
|
-
|
26
|
-
unit_date_sub(
|
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(
|
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
|
-
|
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(
|
44
|
+
Time.local(*ParseDate.parsedate(to_s))
|
46
45
|
end
|
47
46
|
end
|
48
47
|
# :nocov_19:
|
49
|
-
|
50
|
-
|
48
|
+
|
49
|
+
alias_method :units_datetime_inspect, :inspect
|
51
50
|
# @deprecated
|
52
|
-
def inspect(
|
53
|
-
return
|
54
|
-
|
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(
|
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]
|
data/lib/ruby_units/numeric.rb
CHANGED
data/lib/ruby_units/string.rb
CHANGED
@@ -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
|
-
|
13
|
-
#
|
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
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
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
|
-
|
26
|
+
to_unit.convert_to(other)
|
34
27
|
end
|
35
28
|
end
|
data/lib/ruby_units/time.rb
CHANGED
@@ -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
|
data/lib/ruby_units/unit.rb
CHANGED
@@ -1,13 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'date'
|
3
|
-
|
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
|
-
|
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
|
-
|
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
|
203
|
-
|
204
|
-
unit_definition =
|
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
|
-
|
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) ||
|
378
|
-
|
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?(.+)?|±|\+\/-/)
|
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.
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
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
|
-
|
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
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
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(
|
565
|
-
return super() if
|
566
|
-
|
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'.
|
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.
|
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.
|
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
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
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'.
|
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'.
|
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'.
|
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
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
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
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
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
|
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 =~ /(\+\/-|±)/
|
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"
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
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
|
-
|
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})
|
1514
|
+
anynumber = %r{(?:(#{complex}|#{rational}|#{sci}))?\s?([^-\d\.].*)?}
|
1515
|
+
|
1551
1516
|
num, unit = string.scan(anynumber).first
|
1552
1517
|
|
1553
1518
|
return [case num
|