ruby-units 2.4.1 → 4.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/.github/workflows/codeql-analysis.yml +3 -3
- data/.github/workflows/tests.yml +3 -1
- data/.rubocop.yml +2 -0
- data/.ruby-version +1 -1
- data/.solargraph.yml +1 -1
- data/.tool-versions +2 -0
- data/CHANGELOG.txt +3 -1
- data/Gemfile +16 -1
- data/Gemfile.lock +91 -66
- data/README.md +2 -0
- data/lib/ruby_units/array.rb +17 -7
- data/lib/ruby_units/cache.rb +27 -14
- data/lib/ruby_units/configuration.rb +8 -8
- data/lib/ruby_units/date.rb +46 -53
- data/lib/ruby_units/math.rb +136 -113
- data/lib/ruby_units/numeric.rb +21 -5
- data/lib/ruby_units/string.rb +34 -21
- data/lib/ruby_units/time.rb +76 -69
- data/lib/ruby_units/unit.rb +442 -340
- data/lib/ruby_units/version.rb +1 -1
- data/ruby-units.gemspec +2 -14
- metadata +8 -175
data/lib/ruby_units/math.rb
CHANGED
@@ -1,125 +1,148 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
module RubyUnits
|
2
|
+
# Math will convert unit objects to radians and then attempt to use the value for
|
3
|
+
# trigonometric functions.
|
4
|
+
module Math
|
5
|
+
# Take the square root of a unit or number
|
6
|
+
#
|
7
|
+
# @param number [Numeric, RubyUnits::Unit]
|
8
|
+
# @return [Numeric, RubyUnits::Unit]
|
9
|
+
def sqrt(number)
|
10
|
+
if number.is_a?(RubyUnits::Unit)
|
11
|
+
(number**Rational(1, 2)).to_unit
|
12
|
+
else
|
13
|
+
super
|
14
|
+
end
|
11
15
|
end
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
|
17
|
+
# Take the cube root of a unit or number
|
18
|
+
#
|
19
|
+
# @param number [Numeric, RubyUnits::Unit]
|
20
|
+
# @return [Numeric, RubyUnits::Unit]
|
21
|
+
def cbrt(number)
|
22
|
+
if number.is_a?(RubyUnits::Unit)
|
23
|
+
(number**Rational(1, 3)).to_unit
|
24
|
+
else
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param angle [Numeric, RubyUnits::Unit]
|
21
30
|
# @return [Numeric]
|
22
|
-
def
|
23
|
-
|
24
|
-
|
31
|
+
def sin(angle)
|
32
|
+
angle.is_a?(RubyUnits::Unit) ? super(angle.convert_to('radian').scalar) : super
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param number [Numeric, RubyUnits::Unit]
|
36
|
+
# @return [Numeric, RubyUnits::Unit]
|
37
|
+
def asin(number)
|
38
|
+
if number.is_a?(RubyUnits::Unit)
|
39
|
+
[super(number), 'radian'].to_unit
|
25
40
|
else
|
26
|
-
|
41
|
+
super
|
27
42
|
end
|
28
43
|
end
|
44
|
+
|
45
|
+
# @param angle [Numeric, RubyUnits::Unit]
|
29
46
|
# @return [Numeric]
|
30
|
-
|
47
|
+
def cos(angle)
|
48
|
+
angle.is_a?(RubyUnits::Unit) ? super(angle.convert_to('radian').scalar) : super
|
49
|
+
end
|
50
|
+
|
51
|
+
# @param number [Numeric, RubyUnits::Unit]
|
52
|
+
# @return [Numeric, RubyUnits::Unit]
|
53
|
+
def acos(number)
|
54
|
+
if number.is_a?(RubyUnits::Unit)
|
55
|
+
[super(number), 'radian'].to_unit
|
56
|
+
else
|
57
|
+
super
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# @param number [Numeric, RubyUnits::Unit]
|
31
62
|
# @return [Numeric]
|
32
|
-
|
33
|
-
|
34
|
-
|
63
|
+
def sinh(number)
|
64
|
+
number.is_a?(RubyUnits::Unit) ? super(number.convert_to('radian').scalar) : super
|
65
|
+
end
|
35
66
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
41
|
-
# @return [Numeric]
|
42
|
-
module_function :unit_sin
|
43
|
-
# @return [Numeric]
|
44
|
-
module_function :sin
|
45
|
-
|
46
|
-
alias unit_cos cos
|
47
|
-
# @return [Numeric]
|
48
|
-
def cos(n)
|
49
|
-
RubyUnits::Unit === n ? unit_cos(n.convert_to('radian').scalar) : unit_cos(n)
|
50
|
-
end
|
51
|
-
# @return [Numeric]
|
52
|
-
module_function :unit_cos
|
53
|
-
# @return [Numeric]
|
54
|
-
module_function :cos
|
55
|
-
|
56
|
-
alias unit_sinh sinh
|
57
|
-
# @return [Numeric]
|
58
|
-
def sinh(n)
|
59
|
-
RubyUnits::Unit === n ? unit_sinh(n.convert_to('radian').scalar) : unit_sinh(n)
|
60
|
-
end
|
61
|
-
# @return [Numeric]
|
62
|
-
module_function :unit_sinh
|
63
|
-
# @return [Numeric]
|
64
|
-
module_function :sinh
|
65
|
-
|
66
|
-
alias unit_cosh cosh
|
67
|
-
# @return [Numeric]
|
68
|
-
def cosh(n)
|
69
|
-
RubyUnits::Unit === n ? unit_cosh(n.convert_to('radian').scalar) : unit_cosh(n)
|
70
|
-
end
|
71
|
-
# @return [Numeric]
|
72
|
-
module_function :unit_cosh
|
73
|
-
# @return [Numeric]
|
74
|
-
module_function :cosh
|
75
|
-
|
76
|
-
alias unit_tan tan
|
77
|
-
# @return [Numeric]
|
78
|
-
def tan(n)
|
79
|
-
RubyUnits::Unit === n ? unit_tan(n.convert_to('radian').scalar) : unit_tan(n)
|
80
|
-
end
|
81
|
-
# @return [Numeric]
|
82
|
-
module_function :tan
|
83
|
-
# @return [Numeric]
|
84
|
-
module_function :unit_tan
|
85
|
-
|
86
|
-
alias unit_tanh tanh
|
87
|
-
# @return [Numeric]
|
88
|
-
def tanh(n)
|
89
|
-
RubyUnits::Unit === n ? unit_tanh(n.convert_to('radian').scalar) : unit_tanh(n)
|
90
|
-
end
|
91
|
-
# @return [Numeric]
|
92
|
-
module_function :unit_tanh
|
93
|
-
# @return [Numeric]
|
94
|
-
module_function :tanh
|
95
|
-
|
96
|
-
alias unit_hypot hypot
|
97
|
-
# Convert parameters to consistent units and perform the function
|
98
|
-
# @return [Numeric]
|
99
|
-
def hypot(x, y)
|
100
|
-
if RubyUnits::Unit === x && RubyUnits::Unit === y
|
101
|
-
(x**2 + y**2)**Rational(1, 2)
|
102
|
-
else
|
103
|
-
unit_hypot(x, y)
|
67
|
+
# @param number [Numeric, RubyUnits::Unit]
|
68
|
+
# @return [Numeric]
|
69
|
+
def cosh(number)
|
70
|
+
number.is_a?(RubyUnits::Unit) ? super(number.convert_to('radian').scalar) : super
|
104
71
|
end
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
72
|
+
|
73
|
+
# @param angle [Numeric, RubyUnits::Unit]
|
74
|
+
# @return [Numeric]
|
75
|
+
def tan(angle)
|
76
|
+
angle.is_a?(RubyUnits::Unit) ? super(angle.convert_to('radian').scalar) : super
|
77
|
+
end
|
78
|
+
|
79
|
+
# @param number [Numeric, RubyUnits::Unit]
|
80
|
+
# @return [Numeric]
|
81
|
+
def tanh(number)
|
82
|
+
number.is_a?(RubyUnits::Unit) ? super(number.convert_to('radian').scalar) : super
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param x [Numeric, RubyUnits::Unit]
|
86
|
+
# @param y [Numeric, RubyUnits::Unit]
|
87
|
+
# @return [Numeric]
|
88
|
+
def hypot(x, y)
|
89
|
+
if x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)
|
90
|
+
((x**2) + (y**2))**Rational(1, 2)
|
91
|
+
else
|
92
|
+
super
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# @param number [Numeric, RubyUnits::Unit]
|
97
|
+
# @return [Numeric] if argument is a number
|
98
|
+
# @return [RubyUnits::Unit] if argument is a unit
|
99
|
+
def atan(number)
|
100
|
+
if number.is_a?(RubyUnits::Unit)
|
101
|
+
[super(number), 'radian'].to_unit
|
102
|
+
else
|
103
|
+
super
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# @param x [Numeric, RubyUnits::Unit]
|
108
|
+
# @param y [Numeric, RubyUnits::Unit]
|
109
|
+
# @return [Numeric] if all parameters are numbers
|
110
|
+
# @return [RubyUnits::Unit] if parameters are units
|
111
|
+
# @raise [ArgumentError] if parameters are not numbers or compatible units
|
112
|
+
def atan2(x, y)
|
113
|
+
raise ArgumentError, 'Incompatible RubyUnits::Units' if (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && !x.compatible?(y)
|
114
|
+
|
115
|
+
if (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && x.compatible?(y)
|
116
|
+
[super(x.base_scalar, y.base_scalar), 'radian'].to_unit
|
117
|
+
else
|
118
|
+
super
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# @param number [Numeric, RubyUnits::Unit]
|
123
|
+
# @return [Numeric]
|
124
|
+
def log10(number)
|
125
|
+
if number.is_a?(RubyUnits::Unit)
|
126
|
+
super(number.to_f)
|
127
|
+
else
|
128
|
+
super
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# @param number [Numeric, RubyUnits::Unit]
|
133
|
+
# @param base [Numeric]
|
134
|
+
# @return [Numeric]
|
135
|
+
def log(number, base = ::Math::E)
|
136
|
+
if number.is_a?(RubyUnits::Unit)
|
137
|
+
super(number.to_f, base)
|
138
|
+
else
|
139
|
+
super
|
140
|
+
end
|
119
141
|
end
|
120
142
|
end
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
143
|
+
end
|
144
|
+
|
145
|
+
# @see https://github.com/lsegal/yard/issues/1353
|
146
|
+
module Math
|
147
|
+
singleton_class.prepend(RubyUnits::Math)
|
125
148
|
end
|
data/lib/ruby_units/numeric.rb
CHANGED
@@ -1,7 +1,23 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
module RubyUnits
|
2
|
+
# Extra methods for [::Numeric] to allow it to be used as a [RubyUnits::Unit]
|
3
|
+
module Numeric
|
4
|
+
# Make a unitless unit with a given scalar.
|
5
|
+
# > In ruby-units <= 2.3.2 this method would create a new [RubyUnits::Unit]
|
6
|
+
# > with the scalar and passed in units. This was changed to be more
|
7
|
+
# > consistent with the behavior of [#to_unit]. Specifically the argument is
|
8
|
+
# > used as a convenience method to convert the unitless scalar unit to a
|
9
|
+
# > compatible unitless unit.
|
10
|
+
#
|
11
|
+
# @param other [RubyUnits::Unit, String] convert to same units as passed
|
12
|
+
# @return [RubyUnits::Unit]
|
13
|
+
def to_unit(other = nil)
|
14
|
+
other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self)
|
15
|
+
end
|
6
16
|
end
|
7
17
|
end
|
18
|
+
|
19
|
+
# @note Do this instead of Numeric.prepend(RubyUnits::Numeric) to avoid YARD warnings
|
20
|
+
# @see https://github.com/lsegal/yard/issues/1353
|
21
|
+
class Numeric
|
22
|
+
prepend(RubyUnits::Numeric)
|
23
|
+
end
|
data/lib/ruby_units/string.rb
CHANGED
@@ -1,27 +1,40 @@
|
|
1
1
|
require 'time'
|
2
|
-
class String
|
3
|
-
# make a string into a unit
|
4
|
-
# @return (see RubyUnits::Unit#initialize)
|
5
|
-
def to_unit(other = nil)
|
6
|
-
other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self)
|
7
|
-
end
|
8
2
|
|
9
|
-
|
10
|
-
#
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
3
|
+
module RubyUnits
|
4
|
+
# Extra methods for converting [String] objects to [RubyUnits::Unit] objects
|
5
|
+
# and using string formatting with Units.
|
6
|
+
module String
|
7
|
+
# Make a string into a unit
|
8
|
+
#
|
9
|
+
# @param other [RubyUnits::Unit, String] unit to convert to
|
10
|
+
# @return [RubyUnits::Unit]
|
11
|
+
def to_unit(other = nil)
|
12
|
+
other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Format unit output using formatting codes
|
16
|
+
# @example '%0.2f' % '1 mm'.to_unit => '1.00 mm'
|
17
|
+
#
|
18
|
+
# @param other [RubyUnits::Unit, Object]
|
19
|
+
# @return [String]
|
20
|
+
def %(*other)
|
21
|
+
if other.first.is_a?(RubyUnits::Unit)
|
22
|
+
other.first.to_s(self)
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
18
26
|
end
|
19
|
-
end
|
20
|
-
alias % format_with_unit
|
21
27
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
28
|
+
# @param (see RubyUnits::Unit#convert_to)
|
29
|
+
# @return (see RubyUnits::Unit#convert_to)
|
30
|
+
def convert_to(other)
|
31
|
+
to_unit.convert_to(other)
|
32
|
+
end
|
26
33
|
end
|
27
34
|
end
|
35
|
+
|
36
|
+
# @note Do this instead of String.prepend(RubyUnits::String) to avoid YARD warnings
|
37
|
+
# @see https://github.com/lsegal/yard/issues/1353
|
38
|
+
class String
|
39
|
+
prepend(RubyUnits::String)
|
40
|
+
end
|
data/lib/ruby_units/time.rb
CHANGED
@@ -1,82 +1,89 @@
|
|
1
1
|
require 'time'
|
2
|
-
#
|
3
|
-
# Time math is handled slightly differently. The difference is considered to be an exact duration if
|
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
|
6
|
-
# calendar better.
|
7
|
-
class Time
|
8
|
-
class << self
|
9
|
-
alias unit_time_at at
|
10
|
-
end
|
11
2
|
|
12
|
-
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
3
|
+
module RubyUnits
|
4
|
+
# Time math is handled slightly differently. The difference is considered to be an exact duration if
|
5
|
+
# the subtracted value is in hours, minutes, or seconds. It is rounded to the nearest day if the offset
|
6
|
+
# is in years, decades, or centuries. This leads to less precise values, but ones that match the
|
7
|
+
# calendar better.
|
8
|
+
module Time
|
9
|
+
# Class methods for [Time] objects
|
10
|
+
module ClassMethods
|
11
|
+
# Convert a duration to a [::Time] object by considering the duration to be
|
12
|
+
# the number of seconds since the epoch
|
13
|
+
#
|
14
|
+
# @param [Array<RubyUnits::Unit, Numeric, Symbol, Hash>] args
|
15
|
+
# @return [::Time]
|
16
|
+
def at(*args, **kwargs)
|
17
|
+
case args.first
|
18
|
+
when RubyUnits::Unit
|
19
|
+
options = args.last.is_a?(Hash) ? args.pop : kwargs
|
20
|
+
secondary_unit = args[2] || 'microsecond'
|
21
|
+
case args[1]
|
22
|
+
when Numeric
|
23
|
+
super((args.first + RubyUnits::Unit.new(args[1], secondary_unit.to_s)).convert_to('second').scalar, **options)
|
24
|
+
else
|
25
|
+
super(args.first.convert_to('second').scalar, **options)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
super(*args, **kwargs)
|
29
|
+
end
|
26
30
|
end
|
27
|
-
else
|
28
|
-
ms.nil? ? unit_time_at(arg) : unit_time_at(arg, ms)
|
29
|
-
end
|
30
|
-
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
# :nocov_19:
|
39
|
-
public :to_date
|
40
|
-
# :nocov_19:
|
41
|
-
end
|
42
|
-
|
43
|
-
alias unit_add +
|
44
|
-
# @return [RubyUnits::Unit, Time]
|
45
|
-
def +(other)
|
46
|
-
case other
|
47
|
-
when RubyUnits::Unit
|
48
|
-
other = other.convert_to('d').round.convert_to('s') if %w[y decade century].include? other.units
|
49
|
-
begin
|
50
|
-
unit_add(other.convert_to('s').scalar)
|
51
|
-
rescue RangeError
|
52
|
-
to_datetime + other
|
32
|
+
# @example
|
33
|
+
# Time.in '5 min'
|
34
|
+
# @param duration [#to_unit]
|
35
|
+
# @return [::Time]
|
36
|
+
def in(duration)
|
37
|
+
::Time.now + duration.to_unit
|
53
38
|
end
|
54
|
-
else
|
55
|
-
unit_add(other)
|
56
39
|
end
|
57
|
-
end
|
58
40
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
41
|
+
# Convert a [::Time] object to a [RubyUnits::Unit] object. The time is
|
42
|
+
# considered to be a duration with the number of seconds since the epoch.
|
43
|
+
#
|
44
|
+
# @param other [String, RubyUnits::Unit]
|
45
|
+
# @return [RubyUnits::Unit]
|
46
|
+
def to_unit(other = nil)
|
47
|
+
other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self)
|
48
|
+
end
|
65
49
|
|
66
|
-
|
50
|
+
# @param other [::Time, RubyUnits::Unit]
|
51
|
+
# @return [RubyUnits::Unit, ::Time]
|
52
|
+
def +(other)
|
53
|
+
case other
|
54
|
+
when RubyUnits::Unit
|
55
|
+
other = other.convert_to('d').round.convert_to('s') if %w[y decade century].include? other.units
|
56
|
+
begin
|
57
|
+
super(other.convert_to('s').scalar)
|
58
|
+
rescue RangeError
|
59
|
+
to_datetime + other
|
60
|
+
end
|
61
|
+
else
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
67
65
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
66
|
+
# @param other [::Time, RubyUnits::Unit]
|
67
|
+
# @return [RubyUnits::Unit, ::Time]
|
68
|
+
def -(other)
|
69
|
+
case other
|
70
|
+
when RubyUnits::Unit
|
71
|
+
other = other.convert_to('d').round.convert_to('s') if %w[y decade century].include? other.units
|
72
|
+
begin
|
73
|
+
super(other.convert_to('s').scalar)
|
74
|
+
rescue RangeError
|
75
|
+
public_send(:to_datetime) - other
|
76
|
+
end
|
77
|
+
else
|
78
|
+
super
|
77
79
|
end
|
78
|
-
else
|
79
|
-
unit_sub(other)
|
80
80
|
end
|
81
81
|
end
|
82
82
|
end
|
83
|
+
|
84
|
+
# @note Do this instead of Time.prepend(RubyUnits::Time) to avoid YARD warnings
|
85
|
+
# @see https://github.com/lsegal/yard/issues/1353
|
86
|
+
class Time
|
87
|
+
prepend(RubyUnits::Time)
|
88
|
+
singleton_class.prepend(RubyUnits::Time::ClassMethods)
|
89
|
+
end
|