duration.rb 0.3.6 → 0.4.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 +26 -1
- data/README.md +70 -49
- data/lib/Duration/Common.rb +26 -4
- data/lib/Duration/Days.rb +17 -3
- data/lib/Duration/Hours.rb +17 -3
- data/lib/Duration/Microseconds.rb +68 -0
- data/lib/Duration/Milliseconds.rb +18 -3
- data/lib/Duration/Minutes.rb +17 -3
- data/lib/Duration/Months.rb +25 -3
- data/lib/Duration/Nanoseconds.rb +67 -0
- data/lib/Duration/Numeric.rb +12 -0
- data/lib/Duration/Relative.rb +14 -0
- data/lib/Duration/Seconds.rb +17 -3
- data/lib/Duration/VERSION.rb +1 -1
- data/lib/Duration/Weeks.rb +17 -3
- data/lib/duration-numeric.rb +4 -0
- data/lib/{Duration.rb → duration.rb} +2 -1
- data/test/Duration/Common_test.rb +61 -0
- data/test/Duration/Microseconds_test.rb +68 -0
- data/test/Duration/Months_test.rb +6 -6
- data/test/Duration/Nanoseconds_test.rb +68 -0
- data/test/Duration/Numeric_test.rb +29 -0
- data/test/Duration/Seconds_test.rb +12 -0
- data/test/test_helper.rb +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9f7d0f0552f3ce6cb16fd75947bad208ccf403bd8e572b23ae262d4b6aada58f
|
|
4
|
+
data.tar.gz: 7423385510fa2bb3769521892430705fb036eb12b1a40c276a9b4b5445b7bc94
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: be48eabdcaddff69c28452886f068623646af55255ea06f17809e38b2fafd0c343ccc7592478952bb1a7879ef60b10433ad074fbbfa0d47ee0c54405b0066723
|
|
7
|
+
data.tar.gz: 852569a9d5a66c7e576c9c33310c549e6846e369bf934da1eae13d9c54a343a9c6bc06e0dcdbb5da12768fc24f0feabf9c20a1c1b0d3c405b6a40b7f299d9af3
|
data/CHANGELOG
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 20260718
|
|
4
|
+
|
|
5
|
+
0.4.0: + Nanoseconds and Microseconds, arithmetic and comparison, exact conversions without a base, and the Numeric monkeypatch made opt-in.
|
|
6
|
+
|
|
7
|
+
1. + Duration::Nanoseconds
|
|
8
|
+
2. + Duration::Microseconds: This and Nanoseconds are the two units the clock actually speaks, Process.clock_gettime taking :nanosecond and :microsecond directly. Milliseconds was the floor, which left nothing beneath it.
|
|
9
|
+
3. ~ Duration::Common: + #+, #-, and Comparable via #<=>. Arithmetic and comparison happen in the receiver's own unit, so 5.minutes + 30.seconds is 5.5 minutes rather than any number of seconds, and no unit is privileged. Combining with a non-duration raises TypeError, since a bare number has no unit. Comparing with a non-duration returns nil rather than raising, so that == is false.
|
|
10
|
+
4. ~ lib/Duration/*.rb: - the coercion to Float in initialize. The value is held as given, so an Integer stays an Integer and a Rational stays a Rational. A Float stays a Float: the library neither manufactures precision nor discards it.
|
|
11
|
+
5. ~ lib/Duration/*.rb: Conversions divide by a Rational literal (60r, 1000r) rather than an Integer, so a conversion is exact for an exact input. 5.minutes.to_hours holds 1/12, not 0.0833..., and (1.hour - 50.minutes).to_minutes.to_f is 10.0 rather than 9.999999999999998. There is no base and no Float floor in the interior; to_f is the edge where a Float is asked for.
|
|
12
|
+
6. + Duration::Relative#ago, #hence, moved here from Common. Every unit includes it, Months among them, so 1.month.ago remains: it displaces by the mean month, approximate rather than calendar-correct (see 0.3.5's note), as 1.month.to_days is a mean.
|
|
13
|
+
7. + lib/Duration/*.rb: A private #unit per class, naming the unit as a symbol, which Common uses to reach the quantity and to convert the other operand. Explicit rather than reflected from the class name.
|
|
14
|
+
8. ~ lib/Duration.rb: + require the two new classes
|
|
15
|
+
9. ~ lib/Duration.rb: - require Duration/Numeric. BREAKING: require 'Duration' no longer monkeypatches Numeric, so 30.minutes is not available until Duration/Numeric is required. A duration library used directly may want the sugar, but a gem depending on this one should not have Numeric extended from under it.
|
|
16
|
+
10. ~ lib/Duration/Numeric.rb: + require the classes, so require 'Duration/Numeric' stands alone, + nanoseconds and microseconds with their singular aliases.
|
|
17
|
+
11. + test/Duration/Nanoseconds_test.rb, test/Duration/Microseconds_test.rb, test/Duration/Common_test.rb: The new units, and the arithmetic, comparison and exactness.
|
|
18
|
+
12. ~ test/Duration/Numeric_test.rb: + require Duration/Numeric, since it is no longer loaded by default, + the nanosecond and microsecond extensions.
|
|
19
|
+
13. ~ test/Duration/Seconds_test.rb: + that an Integer and a Rational are held without coercion.
|
|
20
|
+
14. ~ lib/Duration.rb --> lib/duration.rb: The one file required from outside the gem, lowercased to match the gem name so require 'duration' resolves on a case-sensitive filesystem and not only on a case-insensitive one. The Duration/ subtree stays PascalCase, reached by exact-case require_relative.
|
|
21
|
+
15. ~ lib/Duration/Numeric.rb: /require_relative '../Duration'/require_relative '../duration'/. The one interior reference reaching back up to the load file, which would otherwise have failed on a case-sensitive filesystem after the rename.
|
|
22
|
+
16. + lib/duration-numeric.rb: A lowercase top-level shim that require_relatives Duration/Numeric, so the sugar opts in via require 'duration-numeric' rather than reaching into the PascalCase namespace with require 'Duration/Numeric'. A file rather than a duration/ directory, so it does not collide with Duration/ where the filesystem is case-insensitive.
|
|
23
|
+
17. ~ test/test_helper.rb: /require_relative '../lib/Duration'/require_relative '../lib/duration'/, following the rename.
|
|
24
|
+
18. ~ README.md: + Philosophy and Loading sections, + the new units, arithmetic and comparison, and the exactness through Rational.
|
|
25
|
+
19. ~ README.md: /require 'Duration'/require 'duration'/, and /require 'Duration/Numeric'/require 'duration-numeric'/ in the Loading section.
|
|
26
|
+
20. ~ Duration::VERSION: /0.3.6/0.4.0/
|
|
3
27
|
|
|
4
28
|
## 20260717
|
|
5
29
|
|
|
@@ -11,7 +35,8 @@
|
|
|
11
35
|
4. ~ duration.rb.gemspec: + Gem::Specification#development_dependencies=
|
|
12
36
|
5. ~ duration.rb.gemspec: + development_dependencies
|
|
13
37
|
6. - test/test_all.rb
|
|
14
|
-
|
|
38
|
+
7. ~ Duration::VERSION: /0.3.5/0.3.6/
|
|
39
|
+
|
|
15
40
|
|
|
16
41
|
## 20260717
|
|
17
42
|
|
data/README.md
CHANGED
|
@@ -21,90 +21,111 @@ Or install directly:
|
|
|
21
21
|
$ gem install duration.rb
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
## Philosophy
|
|
25
|
+
|
|
26
|
+
This is the anti-`ActiveSupport::Duration`. There, every duration is really a
|
|
27
|
+
number of seconds and the unit is decoration: `1.hour == 3600`. Here the unit
|
|
28
|
+
*is* the class. A `Minutes` holds minutes — not seconds it renders as minutes —
|
|
29
|
+
so `30.minutes.to_i` is `30`, not `1800`. No unit is privileged; there is no
|
|
30
|
+
base. Conversion is a behaviour (`to_hours`), not a representation.
|
|
31
|
+
|
|
32
|
+
Because nothing is normalised at construction, exactness is yours to keep: hand
|
|
33
|
+
a constructor an `Integer` or a `Rational` and it stays exact all the way
|
|
34
|
+
through, since conversions divide by exact ratios rather than through a float.
|
|
35
|
+
Hand it a `Float` and it stays a `Float` — the library never manufactures
|
|
36
|
+
precision and never silently discards it.
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
Duration::Minutes.new(5).to_hours.to_f # => 0.08333333333333333
|
|
40
|
+
Duration::Minutes.new(5).to_hours # holds exactly 1/12, not 0.0833...
|
|
41
|
+
(Duration::Hours.new(1) - Duration::Minutes.new(50)).to_minutes.to_f
|
|
42
|
+
# => 10.0 exactly (no float drift)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Loading
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
require 'duration' # the duration classes only
|
|
49
|
+
|
|
50
|
+
require 'duration-numeric' # opt in to the Numeric sugar (5.minutes, etc.),
|
|
51
|
+
# which monkeypatches Numeric
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The examples below use the `Numeric` sugar, so they assume
|
|
55
|
+
`require 'duration-numeric'`. Without it, construct durations directly with
|
|
56
|
+
`Duration::Minutes.new(5)` and friends.
|
|
57
|
+
|
|
24
58
|
## Usage
|
|
25
59
|
|
|
26
60
|
### Basic Duration Creation
|
|
27
61
|
```ruby
|
|
28
62
|
# Create durations using convenience methods
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
63
|
+
500.nanoseconds # => #<Nanoseconds @nanoseconds=500>
|
|
64
|
+
500.microseconds # => #<Microseconds @microseconds=500>
|
|
65
|
+
200.milliseconds # => #<Milliseconds @milliseconds=200>
|
|
66
|
+
1.second # => #<Seconds @seconds=1>
|
|
67
|
+
30.minutes # => #<Minutes @minutes=30>
|
|
68
|
+
2.hours # => #<Hours @hours=2>
|
|
69
|
+
7.days # => #<Days @days=7>
|
|
70
|
+
4.weeks # => #<Weeks @weeks=4>
|
|
71
|
+
6.months # => #<Months @months=6>
|
|
36
72
|
```
|
|
37
73
|
|
|
38
74
|
### Conversions
|
|
39
75
|
```ruby
|
|
40
|
-
#
|
|
41
|
-
|
|
42
|
-
1.second.to_i # => 1
|
|
43
|
-
30.minutes.to_i # => 30
|
|
44
|
-
2.hours.to_i # => 2
|
|
45
|
-
7.days.to_i # => 7
|
|
46
|
-
4.weeks.to_i # => 4
|
|
47
|
-
6.months.to_i # => 6
|
|
48
|
-
|
|
49
|
-
# Convert to floats
|
|
50
|
-
200.milliseconds.to_f # => 200.0
|
|
51
|
-
1.second.to_f # => 1.0
|
|
76
|
+
# The number is in the unit's own terms, not a base:
|
|
77
|
+
30.minutes.to_i # => 30 (not 1800)
|
|
52
78
|
30.minutes.to_f # => 30.0
|
|
53
|
-
2.hours.to_f # => 2.0
|
|
54
|
-
7.days.to_f # => 7.0
|
|
55
|
-
4.weeks.to_f # => 4.0
|
|
56
|
-
6.months.to_f # => 6.0
|
|
57
|
-
|
|
58
|
-
# Convert between units
|
|
59
|
-
90.minutes.to_hours # => #<Hours: @hours=1.5>
|
|
60
|
-
1.5.hours.to_minutes # => #<Minutes: @minutes=90>
|
|
61
|
-
1.day.to_seconds # => #<Seconds: @seconds=86400>
|
|
62
79
|
|
|
63
|
-
#
|
|
80
|
+
# Convert between units. The result is exact (a Rational internally) when the
|
|
81
|
+
# input is exact; call to_f at the edge for a float.
|
|
82
|
+
90.minutes.to_hours # => #<Hours @hours=(3/2)>
|
|
64
83
|
90.minutes.to_hours.to_f # => 1.5
|
|
65
84
|
1.5.hours.to_minutes.to_i # => 90
|
|
66
85
|
1.day.to_seconds.to_i # => 86400
|
|
86
|
+
5.minutes.to_hours.to_f # => 0.08333333333333333
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Arithmetic and Comparison
|
|
90
|
+
```ruby
|
|
91
|
+
# Durations add and subtract, with the left operand's unit deciding the result:
|
|
92
|
+
5.minutes + 30.seconds # => #<Minutes @minutes=(11/2)> (5.5 minutes)
|
|
93
|
+
5.minutes - 30.seconds # => #<Minutes @minutes=(9/2)> (4.5 minutes)
|
|
94
|
+
5.minutes + 30 # => TypeError (a bare number has no unit)
|
|
95
|
+
|
|
96
|
+
# Durations are Comparable, across units and exactly:
|
|
97
|
+
5.minutes == 300.seconds # => true
|
|
98
|
+
90.seconds > 1.minute # => true
|
|
99
|
+
[1.hour, 30.seconds, 5.minutes].sort
|
|
100
|
+
# => [30.seconds, 5.minutes, 1.hour]
|
|
67
101
|
```
|
|
68
102
|
|
|
69
103
|
### Time Calculations
|
|
70
104
|
```ruby
|
|
71
105
|
# The past
|
|
72
|
-
1.millisecond.ago # => #<Time:> (now - 1.millisecond.to_seconds.to_f)
|
|
73
106
|
2.seconds.ago # => #<Time:> (now - 2.seconds.to_seconds.to_f)
|
|
74
107
|
3.minutes.ago # => #<Time:> (now - 3.minutes.to_seconds.to_f)
|
|
75
108
|
4.hours.ago # => #<Time:> (now - 4.hours.to_seconds.to_f)
|
|
76
109
|
5.days.ago # => #<Time:> (now - 5.days.to_seconds.to_f)
|
|
77
110
|
6.weeks.ago # => #<Time:> (now - 6.weeks.to_seconds.to_f)
|
|
78
|
-
7.months.ago # => #<Time:> (now - 7.months.to_seconds.to_f)
|
|
79
111
|
|
|
80
112
|
# The future
|
|
81
|
-
1.millisecond.hence # => #<Time:> (now + 1.millisecond.to_seconds.to_f)
|
|
82
113
|
2.seconds.hence # => #<Time:> (now + 2.seconds.to_seconds.to_f)
|
|
83
114
|
3.minutes.hence # => #<Time:> (now + 3.minutes.to_seconds.to_f)
|
|
84
115
|
4.hours.hence # => #<Time:> (now + 4.hours.to_seconds.to_f)
|
|
85
116
|
5.days.hence # => #<Time:> (now + 5.days.to_seconds.to_f)
|
|
86
117
|
6.weeks.hence # => #<Time:> (now + 6.weeks.to_seconds.to_f)
|
|
87
|
-
7.months.hence # => #<Time:> (now + 7.months.to_seconds.to_f)
|
|
88
118
|
```
|
|
89
119
|
|
|
90
120
|
### A Note on Months
|
|
91
|
-
|
|
92
121
|
`Months` is the odd one out. Every other unit is a fixed quantity with an exact
|
|
93
|
-
ratio to every other
|
|
94
|
-
|
|
95
|
-
so they are honest only as a statistical average
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
Two actual calendar months are anywhere from 59 to 62 days, while the mean gives
|
|
102
|
-
about 60.87 — no particular pair of months. No single constant can be right.
|
|
103
|
-
|
|
104
|
-
For the same reason `ago` and `hence` are not calendar-correct on `Months`: one
|
|
105
|
-
month before the 15th of March is the 15th of February to a calendar, but the
|
|
106
|
-
mean lands on the 12th. Where the calendar matters, reach for a date-anchored
|
|
107
|
-
type such as month.rb.
|
|
122
|
+
ratio to every other; a month is a calendar operation whose length depends on
|
|
123
|
+
the calendar. Its conversions use the Gregorian mean month (2629746 seconds),
|
|
124
|
+
so they are honest only as a statistical average, never as calendar-correct
|
|
125
|
+
arithmetic. Its `ago`/`hence` inherit this — they displace by the mean month,
|
|
126
|
+
so they are approximate rather than calendar-correct; reach for a
|
|
127
|
+
calendar-anchored type such as `month.rb` when that matters. `Months` is slated
|
|
128
|
+
for removal in 0.5.0.
|
|
108
129
|
|
|
109
130
|
## Contributing
|
|
110
131
|
|
data/lib/Duration/Common.rb
CHANGED
|
@@ -3,12 +3,34 @@
|
|
|
3
3
|
|
|
4
4
|
module Duration
|
|
5
5
|
module Common
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
include Comparable
|
|
7
|
+
|
|
8
|
+
def +(other)
|
|
9
|
+
combine(:+, other)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def -(other)
|
|
13
|
+
combine(:-, other)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def <=>(other)
|
|
17
|
+
return nil unless other.is_a?(Duration::Common)
|
|
18
|
+
quantity <=> other.send(:"to_#{unit}").quantity
|
|
8
19
|
end
|
|
9
20
|
|
|
10
|
-
|
|
11
|
-
|
|
21
|
+
protected
|
|
22
|
+
|
|
23
|
+
def quantity
|
|
24
|
+
instance_variable_get(:"@#{unit}")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def combine(operator, other)
|
|
30
|
+
unless other.is_a?(Duration::Common)
|
|
31
|
+
raise TypeError, "can't combine #{self.class} with #{other.class}"
|
|
32
|
+
end
|
|
33
|
+
self.class.new(quantity.send(operator, other.send(:"to_#{unit}").quantity))
|
|
12
34
|
end
|
|
13
35
|
end
|
|
14
36
|
end
|
data/lib/Duration/Days.rb
CHANGED
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
# Duration::Days
|
|
3
3
|
|
|
4
4
|
require_relative './Common'
|
|
5
|
+
require_relative './Relative'
|
|
5
6
|
require_relative './Hours'
|
|
6
7
|
require_relative './Weeks'
|
|
7
8
|
|
|
8
9
|
module Duration
|
|
9
10
|
class Days
|
|
10
11
|
include Common
|
|
12
|
+
include Relative
|
|
13
|
+
|
|
14
|
+
def to_nanoseconds
|
|
15
|
+
to_hours.to_nanoseconds
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_microseconds
|
|
19
|
+
to_hours.to_microseconds
|
|
20
|
+
end
|
|
11
21
|
|
|
12
22
|
def to_milliseconds
|
|
13
23
|
to_hours.to_milliseconds
|
|
@@ -30,7 +40,7 @@ module Duration
|
|
|
30
40
|
end
|
|
31
41
|
|
|
32
42
|
def to_weeks
|
|
33
|
-
Duration::Weeks.new(@days/
|
|
43
|
+
Duration::Weeks.new(@days / 7r)
|
|
34
44
|
end
|
|
35
45
|
|
|
36
46
|
def to_months
|
|
@@ -42,13 +52,17 @@ module Duration
|
|
|
42
52
|
end
|
|
43
53
|
|
|
44
54
|
def to_f
|
|
45
|
-
@days
|
|
55
|
+
@days.to_f
|
|
46
56
|
end
|
|
47
57
|
|
|
48
58
|
private
|
|
49
59
|
|
|
50
60
|
def initialize(days = nil)
|
|
51
|
-
@days = days
|
|
61
|
+
@days = days
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def unit
|
|
65
|
+
:days
|
|
52
66
|
end
|
|
53
67
|
end
|
|
54
68
|
end
|
data/lib/Duration/Hours.rb
CHANGED
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
# Duration::Hours
|
|
3
3
|
|
|
4
4
|
require_relative './Common'
|
|
5
|
+
require_relative './Relative'
|
|
5
6
|
require_relative './Minutes'
|
|
6
7
|
require_relative './Days'
|
|
7
8
|
|
|
8
9
|
module Duration
|
|
9
10
|
class Hours
|
|
10
11
|
include Common
|
|
12
|
+
include Relative
|
|
13
|
+
|
|
14
|
+
def to_nanoseconds
|
|
15
|
+
to_minutes.to_nanoseconds
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_microseconds
|
|
19
|
+
to_minutes.to_microseconds
|
|
20
|
+
end
|
|
11
21
|
|
|
12
22
|
def to_milliseconds
|
|
13
23
|
to_minutes.to_milliseconds
|
|
@@ -26,7 +36,7 @@ module Duration
|
|
|
26
36
|
end
|
|
27
37
|
|
|
28
38
|
def to_days
|
|
29
|
-
Duration::Days.new(@hours/
|
|
39
|
+
Duration::Days.new(@hours / 24r)
|
|
30
40
|
end
|
|
31
41
|
|
|
32
42
|
def to_weeks
|
|
@@ -42,13 +52,17 @@ module Duration
|
|
|
42
52
|
end
|
|
43
53
|
|
|
44
54
|
def to_f
|
|
45
|
-
@hours
|
|
55
|
+
@hours.to_f
|
|
46
56
|
end
|
|
47
57
|
|
|
48
58
|
private
|
|
49
59
|
|
|
50
60
|
def initialize(hours = nil)
|
|
51
|
-
@hours = hours
|
|
61
|
+
@hours = hours
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def unit
|
|
65
|
+
:hours
|
|
52
66
|
end
|
|
53
67
|
end
|
|
54
68
|
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Duration/Microseconds.rb
|
|
2
|
+
# Duration::Microseconds
|
|
3
|
+
|
|
4
|
+
require_relative './Common'
|
|
5
|
+
require_relative './Relative'
|
|
6
|
+
require_relative './Nanoseconds'
|
|
7
|
+
require_relative './Milliseconds'
|
|
8
|
+
|
|
9
|
+
module Duration
|
|
10
|
+
class Microseconds
|
|
11
|
+
include Common
|
|
12
|
+
include Relative
|
|
13
|
+
|
|
14
|
+
def to_nanoseconds
|
|
15
|
+
Duration::Nanoseconds.new(@microseconds * 1000)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_microseconds
|
|
19
|
+
self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_milliseconds
|
|
23
|
+
Duration::Milliseconds.new(@microseconds / 1000r)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_seconds
|
|
27
|
+
to_milliseconds.to_seconds
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_minutes
|
|
31
|
+
to_milliseconds.to_minutes
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_hours
|
|
35
|
+
to_milliseconds.to_hours
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def to_days
|
|
39
|
+
to_milliseconds.to_days
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_weeks
|
|
43
|
+
to_milliseconds.to_weeks
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def to_months
|
|
47
|
+
to_milliseconds.to_months
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_i
|
|
51
|
+
@microseconds.to_i
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def to_f
|
|
55
|
+
@microseconds.to_f
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def initialize(microseconds = nil)
|
|
61
|
+
@microseconds = microseconds
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def unit
|
|
65
|
+
:microseconds
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -2,18 +2,29 @@
|
|
|
2
2
|
# Duration::Milliseconds
|
|
3
3
|
|
|
4
4
|
require_relative './Common'
|
|
5
|
+
require_relative './Relative'
|
|
6
|
+
require_relative './Microseconds'
|
|
5
7
|
require_relative './Seconds'
|
|
6
8
|
|
|
7
9
|
module Duration
|
|
8
10
|
class Milliseconds
|
|
9
11
|
include Common
|
|
12
|
+
include Relative
|
|
13
|
+
|
|
14
|
+
def to_nanoseconds
|
|
15
|
+
to_microseconds.to_nanoseconds
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_microseconds
|
|
19
|
+
Duration::Microseconds.new(@milliseconds * 1000)
|
|
20
|
+
end
|
|
10
21
|
|
|
11
22
|
def to_milliseconds
|
|
12
23
|
self
|
|
13
24
|
end
|
|
14
25
|
|
|
15
26
|
def to_seconds
|
|
16
|
-
Duration::Seconds.new(@milliseconds/
|
|
27
|
+
Duration::Seconds.new(@milliseconds / 1000r)
|
|
17
28
|
end
|
|
18
29
|
|
|
19
30
|
def to_minutes
|
|
@@ -41,13 +52,17 @@ module Duration
|
|
|
41
52
|
end
|
|
42
53
|
|
|
43
54
|
def to_f
|
|
44
|
-
@milliseconds
|
|
55
|
+
@milliseconds.to_f
|
|
45
56
|
end
|
|
46
57
|
|
|
47
58
|
private
|
|
48
59
|
|
|
49
60
|
def initialize(milliseconds = nil)
|
|
50
|
-
@milliseconds = milliseconds
|
|
61
|
+
@milliseconds = milliseconds
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def unit
|
|
65
|
+
:milliseconds
|
|
51
66
|
end
|
|
52
67
|
end
|
|
53
68
|
end
|
data/lib/Duration/Minutes.rb
CHANGED
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
# Duration::Minutes
|
|
3
3
|
|
|
4
4
|
require_relative './Common'
|
|
5
|
+
require_relative './Relative'
|
|
5
6
|
require_relative './Seconds'
|
|
6
7
|
require_relative './Hours'
|
|
7
8
|
|
|
8
9
|
module Duration
|
|
9
10
|
class Minutes
|
|
10
11
|
include Common
|
|
12
|
+
include Relative
|
|
13
|
+
|
|
14
|
+
def to_nanoseconds
|
|
15
|
+
to_seconds.to_nanoseconds
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_microseconds
|
|
19
|
+
to_seconds.to_microseconds
|
|
20
|
+
end
|
|
11
21
|
|
|
12
22
|
def to_milliseconds
|
|
13
23
|
to_seconds.to_milliseconds
|
|
@@ -22,7 +32,7 @@ module Duration
|
|
|
22
32
|
end
|
|
23
33
|
|
|
24
34
|
def to_hours
|
|
25
|
-
Duration::Hours.new(@minutes/
|
|
35
|
+
Duration::Hours.new(@minutes / 60r)
|
|
26
36
|
end
|
|
27
37
|
|
|
28
38
|
def to_days
|
|
@@ -42,13 +52,17 @@ module Duration
|
|
|
42
52
|
end
|
|
43
53
|
|
|
44
54
|
def to_f
|
|
45
|
-
@minutes
|
|
55
|
+
@minutes.to_f
|
|
46
56
|
end
|
|
47
57
|
|
|
48
58
|
private
|
|
49
59
|
|
|
50
60
|
def initialize(minutes = nil)
|
|
51
|
-
@minutes = minutes
|
|
61
|
+
@minutes = minutes
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def unit
|
|
65
|
+
:minutes
|
|
52
66
|
end
|
|
53
67
|
end
|
|
54
68
|
end
|
data/lib/Duration/Months.rb
CHANGED
|
@@ -2,11 +2,29 @@
|
|
|
2
2
|
# Duration::Months
|
|
3
3
|
|
|
4
4
|
require_relative './Common'
|
|
5
|
+
require_relative './Relative'
|
|
5
6
|
require_relative './Weeks'
|
|
6
7
|
|
|
7
8
|
module Duration
|
|
9
|
+
# A month is not a fixed quantity: its length depends on the calendar. The
|
|
10
|
+
# conversions below use the Gregorian mean month (2629746 seconds), so they
|
|
11
|
+
# are honest only as a statistical average, never as calendar-correct
|
|
12
|
+
# arithmetic. For that, reach for a calendar-anchored type such as month.rb.
|
|
13
|
+
#
|
|
14
|
+
# ago and hence (via Relative) inherit the same caveat: they displace by the
|
|
15
|
+
# mean month rather than an actual calendar month, so they are approximate,
|
|
16
|
+
# not calendar-correct. Months is slated for removal in 0.5.0.
|
|
8
17
|
class Months
|
|
9
18
|
include Common
|
|
19
|
+
include Relative
|
|
20
|
+
|
|
21
|
+
def to_nanoseconds
|
|
22
|
+
to_weeks.to_nanoseconds
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_microseconds
|
|
26
|
+
to_weeks.to_microseconds
|
|
27
|
+
end
|
|
10
28
|
|
|
11
29
|
def to_milliseconds
|
|
12
30
|
to_weeks.to_milliseconds
|
|
@@ -30,7 +48,7 @@ module Duration
|
|
|
30
48
|
|
|
31
49
|
def to_weeks
|
|
32
50
|
# A month is the Gregorian mean: 2629746 seconds against 604800 per week.
|
|
33
|
-
Duration::Weeks.new(@months * 2629746 /
|
|
51
|
+
Duration::Weeks.new(@months * 2629746 / 604800r)
|
|
34
52
|
end
|
|
35
53
|
|
|
36
54
|
def to_months
|
|
@@ -42,13 +60,17 @@ module Duration
|
|
|
42
60
|
end
|
|
43
61
|
|
|
44
62
|
def to_f
|
|
45
|
-
@months
|
|
63
|
+
@months.to_f
|
|
46
64
|
end
|
|
47
65
|
|
|
48
66
|
private
|
|
49
67
|
|
|
50
68
|
def initialize(months = nil)
|
|
51
|
-
@months = months
|
|
69
|
+
@months = months
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def unit
|
|
73
|
+
:months
|
|
52
74
|
end
|
|
53
75
|
end
|
|
54
76
|
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Duration/Nanoseconds.rb
|
|
2
|
+
# Duration::Nanoseconds
|
|
3
|
+
|
|
4
|
+
require_relative './Common'
|
|
5
|
+
require_relative './Relative'
|
|
6
|
+
require_relative './Microseconds'
|
|
7
|
+
|
|
8
|
+
module Duration
|
|
9
|
+
class Nanoseconds
|
|
10
|
+
include Common
|
|
11
|
+
include Relative
|
|
12
|
+
|
|
13
|
+
def to_nanoseconds
|
|
14
|
+
self
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_microseconds
|
|
18
|
+
Duration::Microseconds.new(@nanoseconds / 1000r)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_milliseconds
|
|
22
|
+
to_microseconds.to_milliseconds
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_seconds
|
|
26
|
+
to_microseconds.to_seconds
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_minutes
|
|
30
|
+
to_microseconds.to_minutes
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_hours
|
|
34
|
+
to_microseconds.to_hours
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def to_days
|
|
38
|
+
to_microseconds.to_days
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_weeks
|
|
42
|
+
to_microseconds.to_weeks
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def to_months
|
|
46
|
+
to_microseconds.to_months
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def to_i
|
|
50
|
+
@nanoseconds.to_i
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def to_f
|
|
54
|
+
@nanoseconds.to_f
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def initialize(nanoseconds = nil)
|
|
60
|
+
@nanoseconds = nanoseconds
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def unit
|
|
64
|
+
:nanoseconds
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/lib/Duration/Numeric.rb
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
# Duration/Numeric.rb
|
|
2
2
|
# Duration::Numeric
|
|
3
3
|
|
|
4
|
+
require_relative '../duration'
|
|
5
|
+
|
|
4
6
|
module Duration
|
|
5
7
|
module Numeric
|
|
8
|
+
def nanoseconds
|
|
9
|
+
Duration::Nanoseconds.new(self)
|
|
10
|
+
end
|
|
11
|
+
alias_method :nanosecond, :nanoseconds
|
|
12
|
+
|
|
13
|
+
def microseconds
|
|
14
|
+
Duration::Microseconds.new(self)
|
|
15
|
+
end
|
|
16
|
+
alias_method :microsecond, :microseconds
|
|
17
|
+
|
|
6
18
|
def milliseconds
|
|
7
19
|
Duration::Milliseconds.new(self)
|
|
8
20
|
end
|
data/lib/Duration/Seconds.rb
CHANGED
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
# Duration::Seconds
|
|
3
3
|
|
|
4
4
|
require_relative './Common'
|
|
5
|
+
require_relative './Relative'
|
|
5
6
|
require_relative './Milliseconds'
|
|
6
7
|
require_relative './Minutes'
|
|
7
8
|
|
|
8
9
|
module Duration
|
|
9
10
|
class Seconds
|
|
10
11
|
include Common
|
|
12
|
+
include Relative
|
|
13
|
+
|
|
14
|
+
def to_nanoseconds
|
|
15
|
+
to_milliseconds.to_nanoseconds
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_microseconds
|
|
19
|
+
to_milliseconds.to_microseconds
|
|
20
|
+
end
|
|
11
21
|
|
|
12
22
|
def to_milliseconds
|
|
13
23
|
Duration::Milliseconds.new(@seconds * 1000)
|
|
@@ -18,7 +28,7 @@ module Duration
|
|
|
18
28
|
end
|
|
19
29
|
|
|
20
30
|
def to_minutes
|
|
21
|
-
Duration::Minutes.new(@seconds/
|
|
31
|
+
Duration::Minutes.new(@seconds / 60r)
|
|
22
32
|
end
|
|
23
33
|
|
|
24
34
|
def to_hours
|
|
@@ -42,13 +52,17 @@ module Duration
|
|
|
42
52
|
end
|
|
43
53
|
|
|
44
54
|
def to_f
|
|
45
|
-
@seconds
|
|
55
|
+
@seconds.to_f
|
|
46
56
|
end
|
|
47
57
|
|
|
48
58
|
private
|
|
49
59
|
|
|
50
60
|
def initialize(seconds = nil)
|
|
51
|
-
@seconds = seconds
|
|
61
|
+
@seconds = seconds
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def unit
|
|
65
|
+
:seconds
|
|
52
66
|
end
|
|
53
67
|
end
|
|
54
68
|
end
|
data/lib/Duration/VERSION.rb
CHANGED
data/lib/Duration/Weeks.rb
CHANGED
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
# Duration::Weeks
|
|
3
3
|
|
|
4
4
|
require_relative './Common'
|
|
5
|
+
require_relative './Relative'
|
|
5
6
|
require_relative './Days'
|
|
6
7
|
require_relative './Months'
|
|
7
8
|
|
|
8
9
|
module Duration
|
|
9
10
|
class Weeks
|
|
10
11
|
include Common
|
|
12
|
+
include Relative
|
|
13
|
+
|
|
14
|
+
def to_nanoseconds
|
|
15
|
+
to_days.to_nanoseconds
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_microseconds
|
|
19
|
+
to_days.to_microseconds
|
|
20
|
+
end
|
|
11
21
|
|
|
12
22
|
def to_milliseconds
|
|
13
23
|
to_days.to_milliseconds
|
|
@@ -35,7 +45,7 @@ module Duration
|
|
|
35
45
|
|
|
36
46
|
def to_months
|
|
37
47
|
# A month is the Gregorian mean: 2629746 seconds against 604800 per week.
|
|
38
|
-
Duration::Months.new(@weeks * 604800 /
|
|
48
|
+
Duration::Months.new(@weeks * 604800 / 2629746r)
|
|
39
49
|
end
|
|
40
50
|
|
|
41
51
|
def to_i
|
|
@@ -43,13 +53,17 @@ module Duration
|
|
|
43
53
|
end
|
|
44
54
|
|
|
45
55
|
def to_f
|
|
46
|
-
@weeks
|
|
56
|
+
@weeks.to_f
|
|
47
57
|
end
|
|
48
58
|
|
|
49
59
|
private
|
|
50
60
|
|
|
51
61
|
def initialize(weeks = nil)
|
|
52
|
-
@weeks = weeks
|
|
62
|
+
@weeks = weeks
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def unit
|
|
66
|
+
:weeks
|
|
53
67
|
end
|
|
54
68
|
end
|
|
55
69
|
end
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
module Duration; end
|
|
5
5
|
|
|
6
|
+
require_relative 'Duration/Nanoseconds'
|
|
7
|
+
require_relative 'Duration/Microseconds'
|
|
6
8
|
require_relative 'Duration/Milliseconds'
|
|
7
9
|
require_relative 'Duration/Seconds'
|
|
8
10
|
require_relative 'Duration/Minutes'
|
|
@@ -10,5 +12,4 @@ require_relative 'Duration/Hours'
|
|
|
10
12
|
require_relative 'Duration/Days'
|
|
11
13
|
require_relative 'Duration/Weeks'
|
|
12
14
|
require_relative 'Duration/Months'
|
|
13
|
-
require_relative 'Duration/Numeric'
|
|
14
15
|
require_relative 'Duration/VERSION'
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# test/duration/common_test.rb
|
|
2
|
+
|
|
3
|
+
require_relative '../test_helper'
|
|
4
|
+
require_relative '../../lib/Duration/Numeric'
|
|
5
|
+
|
|
6
|
+
describe Duration::Common do
|
|
7
|
+
describe "addition" do
|
|
8
|
+
it "adds two durations of the same unit" do
|
|
9
|
+
result = 5.minutes + 3.minutes
|
|
10
|
+
_(result).must_be_instance_of Duration::Minutes
|
|
11
|
+
_(result.to_i).must_equal 8
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "adds across units in the left operand's unit" do
|
|
15
|
+
result = 5.minutes + 30.seconds
|
|
16
|
+
_(result).must_be_instance_of Duration::Minutes
|
|
17
|
+
_(result.to_f).must_equal 5.5
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "raises when combined with a non-duration" do
|
|
21
|
+
_{5.minutes + 30}.must_raise TypeError
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe "subtraction" do
|
|
26
|
+
it "subtracts across units in the left operand's unit" do
|
|
27
|
+
result = 5.minutes - 30.seconds
|
|
28
|
+
_(result).must_be_instance_of Duration::Minutes
|
|
29
|
+
_(result.to_f).must_equal 4.5
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "comparison" do
|
|
34
|
+
it "compares durations of different units exactly" do
|
|
35
|
+
_(5.minutes).must_equal 300.seconds
|
|
36
|
+
_(90.seconds).must_be :>, 1.minute
|
|
37
|
+
_(1.hour).must_be :<, 2.hours
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "sorts a mixed collection" do
|
|
41
|
+
sorted = [1.hour, 30.seconds, 5.minutes].sort
|
|
42
|
+
_(sorted).must_equal [30.seconds, 5.minutes, 1.hour]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "returns nil against a non-duration rather than raising" do
|
|
46
|
+
_(5.minutes <=> 30).must_be_nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "is not equal to a non-duration" do
|
|
50
|
+
_(5.minutes == 300).must_equal false
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe "exactness" do
|
|
55
|
+
it "converts without float drift" do
|
|
56
|
+
# 1/6 of an hour is exactly 10 minutes; a float round-trip would not
|
|
57
|
+
# land on 10.0.
|
|
58
|
+
_((1.hour - 50.minutes).to_minutes.to_f).must_equal 10.0
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# test/duration/microseconds_test.rb
|
|
2
|
+
|
|
3
|
+
require_relative '../test_helper'
|
|
4
|
+
|
|
5
|
+
describe Duration::Microseconds do
|
|
6
|
+
describe "initialization" do
|
|
7
|
+
it "holds an integer without coercing to a float" do
|
|
8
|
+
us = Duration::Microseconds.new(1500)
|
|
9
|
+
_(us.instance_variable_get(:@microseconds)).must_equal 1500
|
|
10
|
+
_(us.instance_variable_get(:@microseconds)).must_be_kind_of Integer
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "conversions" do
|
|
15
|
+
subject do
|
|
16
|
+
Duration::Microseconds.new(2_000_000)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "converts to nanoseconds" do
|
|
20
|
+
ns = subject.to_nanoseconds
|
|
21
|
+
_(ns).must_be_instance_of Duration::Nanoseconds
|
|
22
|
+
_(ns.to_i).must_equal 2_000_000_000
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "converts to milliseconds" do
|
|
26
|
+
ms = subject.to_milliseconds
|
|
27
|
+
_(ms).must_be_instance_of Duration::Milliseconds
|
|
28
|
+
_(ms.to_f).must_equal 2000.0
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "converts to seconds" do
|
|
32
|
+
secs = subject.to_seconds
|
|
33
|
+
_(secs).must_be_instance_of Duration::Seconds
|
|
34
|
+
_(secs.to_f).must_equal 2.0
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "converts to minutes" do
|
|
38
|
+
mins = subject.to_minutes
|
|
39
|
+
_(mins).must_be_instance_of Duration::Minutes
|
|
40
|
+
_(mins.to_f).must_be_close_to 0.0333, 0.0001
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "converts to milliseconds without truncating sub-millisecond precision" do
|
|
44
|
+
ms = Duration::Microseconds.new(1500).to_milliseconds
|
|
45
|
+
_(ms.to_f).must_equal 1.5
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "returns itself for to_microseconds" do
|
|
49
|
+
_((subject.to_microseconds).object_id).must_equal subject.object_id
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "time calculations" do
|
|
54
|
+
it "calculates ago from current time" do
|
|
55
|
+
us = Duration::Microseconds.new(1_000_000)
|
|
56
|
+
time_ago = us.ago
|
|
57
|
+
_(time_ago).must_be_instance_of Time
|
|
58
|
+
_(Time.now - time_ago).must_be_close_to 1.0, 1.0
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "calculates hence from current time" do
|
|
62
|
+
us = Duration::Microseconds.new(1_000_000)
|
|
63
|
+
time_hence = us.hence
|
|
64
|
+
_(time_hence).must_be_instance_of Time
|
|
65
|
+
_(time_hence - Time.now).must_be_close_to 1.0, 1.0
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -19,13 +19,13 @@ describe Duration::Months do
|
|
|
19
19
|
it "converts to milliseconds" do
|
|
20
20
|
ms = subject.to_milliseconds
|
|
21
21
|
_(ms).must_be_instance_of Duration::Milliseconds
|
|
22
|
-
_(ms.to_f).
|
|
22
|
+
_(ms.to_f).must_equal 5259492000.0
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
it "converts to seconds" do
|
|
26
26
|
secs = subject.to_seconds
|
|
27
27
|
_(secs).must_be_instance_of Duration::Seconds
|
|
28
|
-
_(secs.to_f).
|
|
28
|
+
_(secs.to_f).must_equal 5259492.0
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
it "converts to minutes" do
|
|
@@ -58,20 +58,20 @@ describe Duration::Months do
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
describe "time calculations" do
|
|
61
|
+
# ago and hence displace by the mean month, so they are approximate rather
|
|
62
|
+
# than calendar-correct. See month.rb for calendar-anchored work.
|
|
61
63
|
it "calculates ago from current time" do
|
|
62
64
|
months = Duration::Months.new(1)
|
|
63
65
|
time_ago = months.ago
|
|
64
66
|
_(time_ago).must_be_instance_of Time
|
|
65
|
-
|
|
66
|
-
_(Time.now - time_ago).must_be :>, 2500000.0
|
|
67
|
+
_(Time.now - time_ago).must_be_close_to 2629746.0, 1.0
|
|
67
68
|
end
|
|
68
69
|
|
|
69
70
|
it "calculates hence from current time" do
|
|
70
71
|
months = Duration::Months.new(1)
|
|
71
72
|
time_hence = months.hence
|
|
72
73
|
_(time_hence).must_be_instance_of Time
|
|
73
|
-
|
|
74
|
-
_(time_hence - Time.now).must_be :>, 2500000.0
|
|
74
|
+
_(time_hence - Time.now).must_be_close_to 2629746.0, 1.0
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# test/duration/nanoseconds_test.rb
|
|
2
|
+
|
|
3
|
+
require_relative '../test_helper'
|
|
4
|
+
|
|
5
|
+
describe Duration::Nanoseconds do
|
|
6
|
+
describe "initialization" do
|
|
7
|
+
it "holds an integer without coercing to a float" do
|
|
8
|
+
ns = Duration::Nanoseconds.new(1500)
|
|
9
|
+
_(ns.instance_variable_get(:@nanoseconds)).must_equal 1500
|
|
10
|
+
_(ns.instance_variable_get(:@nanoseconds)).must_be_kind_of Integer
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "conversions" do
|
|
15
|
+
subject do
|
|
16
|
+
Duration::Nanoseconds.new(2_000_000_000)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "converts to microseconds" do
|
|
20
|
+
us = subject.to_microseconds
|
|
21
|
+
_(us).must_be_instance_of Duration::Microseconds
|
|
22
|
+
_(us.to_f).must_equal 2_000_000.0
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "converts to milliseconds" do
|
|
26
|
+
ms = subject.to_milliseconds
|
|
27
|
+
_(ms).must_be_instance_of Duration::Milliseconds
|
|
28
|
+
_(ms.to_f).must_equal 2000.0
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "converts to seconds" do
|
|
32
|
+
secs = subject.to_seconds
|
|
33
|
+
_(secs).must_be_instance_of Duration::Seconds
|
|
34
|
+
_(secs.to_f).must_equal 2.0
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "converts to minutes" do
|
|
38
|
+
mins = subject.to_minutes
|
|
39
|
+
_(mins).must_be_instance_of Duration::Minutes
|
|
40
|
+
_(mins.to_f).must_be_close_to 0.0333, 0.0001
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "converts to microseconds without truncating sub-microsecond precision" do
|
|
44
|
+
us = Duration::Nanoseconds.new(1_500_500).to_microseconds
|
|
45
|
+
_(us.to_f).must_equal 1500.5
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "returns itself for to_nanoseconds" do
|
|
49
|
+
_((subject.to_nanoseconds).object_id).must_equal subject.object_id
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "time calculations" do
|
|
54
|
+
it "calculates ago from current time" do
|
|
55
|
+
ns = Duration::Nanoseconds.new(1_000_000_000)
|
|
56
|
+
time_ago = ns.ago
|
|
57
|
+
_(time_ago).must_be_instance_of Time
|
|
58
|
+
_(Time.now - time_ago).must_be_close_to 1.0, 1.0
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "calculates hence from current time" do
|
|
62
|
+
ns = Duration::Nanoseconds.new(1_000_000_000)
|
|
63
|
+
time_hence = ns.hence
|
|
64
|
+
_(time_hence).must_be_instance_of Time
|
|
65
|
+
_(time_hence - Time.now).must_be_close_to 1.0, 1.0
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -1,8 +1,37 @@
|
|
|
1
1
|
# test/duration/numeric_test.rb
|
|
2
2
|
|
|
3
3
|
require_relative '../test_helper'
|
|
4
|
+
require_relative '../../lib/Duration/Numeric'
|
|
4
5
|
|
|
5
6
|
describe Duration::Numeric do
|
|
7
|
+
describe "nanosecond extensions" do
|
|
8
|
+
it "creates Nanoseconds from integer" do
|
|
9
|
+
ns = 1000.nanoseconds
|
|
10
|
+
_(ns).must_be_instance_of Duration::Nanoseconds
|
|
11
|
+
_(ns.to_i).must_equal 1000
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "supports singular alias" do
|
|
15
|
+
ns = 1.nanosecond
|
|
16
|
+
_(ns).must_be_instance_of Duration::Nanoseconds
|
|
17
|
+
_(ns.to_i).must_equal 1
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe "microsecond extensions" do
|
|
22
|
+
it "creates Microseconds from integer" do
|
|
23
|
+
us = 1000.microseconds
|
|
24
|
+
_(us).must_be_instance_of Duration::Microseconds
|
|
25
|
+
_(us.to_i).must_equal 1000
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "supports singular alias" do
|
|
29
|
+
us = 1.microsecond
|
|
30
|
+
_(us).must_be_instance_of Duration::Microseconds
|
|
31
|
+
_(us.to_i).must_equal 1
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
6
35
|
describe "millisecond extensions" do
|
|
7
36
|
it "creates Milliseconds from integer" do
|
|
8
37
|
ms = 1000.milliseconds
|
|
@@ -9,6 +9,18 @@ describe Duration::Seconds do
|
|
|
9
9
|
_(secs.instance_variable_get(:@seconds)).must_equal 60.5
|
|
10
10
|
_(secs.instance_variable_get(:@seconds)).must_be_kind_of Float
|
|
11
11
|
end
|
|
12
|
+
|
|
13
|
+
it "holds an integer without coercing to a float" do
|
|
14
|
+
secs = Duration::Seconds.new(90)
|
|
15
|
+
_(secs.instance_variable_get(:@seconds)).must_equal 90
|
|
16
|
+
_(secs.instance_variable_get(:@seconds)).must_be_kind_of Integer
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "holds a rational without coercing" do
|
|
20
|
+
secs = Duration::Seconds.new(Rational(3, 2))
|
|
21
|
+
_(secs.instance_variable_get(:@seconds)).must_equal Rational(3, 2)
|
|
22
|
+
_(secs.instance_variable_get(:@seconds)).must_be_kind_of Rational
|
|
23
|
+
end
|
|
12
24
|
end
|
|
13
25
|
|
|
14
26
|
describe "conversions" do
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: duration.rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- thoran
|
|
@@ -62,22 +62,29 @@ files:
|
|
|
62
62
|
- README.md
|
|
63
63
|
- Rakefile
|
|
64
64
|
- duration.rb.gemspec
|
|
65
|
-
- lib/Duration.rb
|
|
66
65
|
- lib/Duration/Common.rb
|
|
67
66
|
- lib/Duration/Days.rb
|
|
68
67
|
- lib/Duration/Hours.rb
|
|
68
|
+
- lib/Duration/Microseconds.rb
|
|
69
69
|
- lib/Duration/Milliseconds.rb
|
|
70
70
|
- lib/Duration/Minutes.rb
|
|
71
71
|
- lib/Duration/Months.rb
|
|
72
|
+
- lib/Duration/Nanoseconds.rb
|
|
72
73
|
- lib/Duration/Numeric.rb
|
|
74
|
+
- lib/Duration/Relative.rb
|
|
73
75
|
- lib/Duration/Seconds.rb
|
|
74
76
|
- lib/Duration/VERSION.rb
|
|
75
77
|
- lib/Duration/Weeks.rb
|
|
78
|
+
- lib/duration-numeric.rb
|
|
79
|
+
- lib/duration.rb
|
|
80
|
+
- test/Duration/Common_test.rb
|
|
76
81
|
- test/Duration/Days_test.rb
|
|
77
82
|
- test/Duration/Hours_test.rb
|
|
83
|
+
- test/Duration/Microseconds_test.rb
|
|
78
84
|
- test/Duration/Milliseconds_test.rb
|
|
79
85
|
- test/Duration/Minutes_test.rb
|
|
80
86
|
- test/Duration/Months_test.rb
|
|
87
|
+
- test/Duration/Nanoseconds_test.rb
|
|
81
88
|
- test/Duration/Numeric_test.rb
|
|
82
89
|
- test/Duration/Seconds_test.rb
|
|
83
90
|
- test/Duration/Weeks_test.rb
|