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