monotonic.rb 0.8.0 → 0.9.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 +20 -0
- data/README.md +25 -9
- data/lib/Monotonic/Measurement.rb +118 -0
- data/lib/Monotonic/Timer.rb +40 -1
- data/lib/Monotonic/VERSION.rb +1 -1
- data/monotonic.rb.gemspec +1 -0
- data/test/Monotonic/Measurement_test.rb +118 -0
- data/test/Monotonic/Timer_test.rb +4 -4
- data/test/gemspec_test.rb +1 -1
- metadata +17 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 02f12d8ccd007cc410e5ebeb524fd6761088aebe771409a81323fd331e479e61
|
|
4
|
+
data.tar.gz: 9bfd7ff12760b554b0921e535803c4e3e07c0c0cdb166b8133f1ab710a6a1d10
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fb3b665160980c7d6319db88518e9bd6f74a5e7eade1035a61e62c6aaa88e06110b382f02900f4e61fc7509cb7d9167084d5650c95858912c4a5b5bb2ffdcd43
|
|
7
|
+
data.tar.gz: 9c7c70bb79a05df1608516272583870cd7aab4229e13dce3d626b38fd3426a58c3529bfe2e8ddd2607f3995508c3c1cdcda287212002349db0fabea114a373b5
|
data/CHANGELOG
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 20260816
|
|
4
|
+
|
|
5
|
+
0.9.0: Use measurand gem, + Monotonic::Measurement and Monotonic::Timer.floor.
|
|
6
|
+
|
|
7
|
+
1. + measurand as a dependency, constrained to >= 0.1.0 where Measurand#place became public. How well a figure is known is its business, and it was being hand-rolled here: combining an absolute floor with a relative drift by addition gave 109.49ns where the correct combination in quadrature gives 87.78ns, a quarter out.
|
|
8
|
+
2. + Monotonic::Timer.floor: what it costs to measure at all, in nanoseconds, measured by timing measurements of nothing and remembered. The clock's tick is not the limit, an interval wanting two readings and the taking of them taking time. A high percentile rather than a median, so that the ordinary case is covered and not merely the best one. It is a floor and not an error bar: the tail is unbounded and one-sided, the scheduler being free to take the processor away between the two readings, and no single measurement can detect that it did.
|
|
9
|
+
3. + Monotonic::Measurement: an elapsed interval together with what it is worth. #to_s shows only as many digits as the uncertainty reaches, the least significant place being settled by Measurand#place upon the Particle Data Group convention, so 1265625ns against a floor of 84ns prints as 1.26562ms and the same count measured coarsely prints as 1.27ms. The unit ladder is powers of a thousand and stops at seconds, the scheme being a decimal-places one and minutes being sexagesimal. Nothing is capped, a day resolved to a hundred nanoseconds printing every figure it has: the absurdity is the mismatch between instrument and question, and is better seen than rounded away.
|
|
10
|
+
4. + Monotonic::Measurement#uncertainty, #measurand, #unit_name, #decimals, #nanoseconds, #floor, #drift: every figure the rendering rests upon, so that a string can be walked back to the clock which produced it.
|
|
11
|
+
5. + Monotonic::Measurement#floor takes a number or anything answering to #call, and Monotonic::Timer hands over its .floor method rather than its value. Measuring the floor is a thousand null measurements, and a caller which only wants a number should not set them going: a timed block costs 0.008ms where it would cost 0.307ms, the floor being measured when doubt is first asked about.
|
|
12
|
+
6. + Monotonic::Measurement drift, optional and nil by default: the relative term, being the rate at which the clock's own oscillator wanders. It cannot be measured from within, weighing a clock wanting a better clock and this being the best one here, so it is supplied by a caller or not at all.
|
|
13
|
+
7. + Monotonic::Measurement#to_i and #to_f, both in nanoseconds, its own unit, as Duration::Minutes answers 5 rather than 300; #to_duration for every other unit; and #<=> with Comparable, against another measurement only, a bare number having no unit to compare against.
|
|
14
|
+
8. ~ BREAKING: Monotonic::Timer#time and .time return a Monotonic::Measurement rather than a Float of seconds. What comes back now says how much of itself is real, which a bare Float could not: 0.001295791 shows nine figures upon an instrument which resolves five. #total_time and #total_nanoseconds are unchanged for a number.
|
|
15
|
+
9. + Monotonic::Timer#measurement and #to_s.
|
|
16
|
+
10. + test/Monotonic/Measurement_test.rb: the unit chosen, the digits allowed, the uncertainty and that it combines in quadrature, the comparison, the conversions, the lazy floor, and that every figure the rendering rests upon is reachable.
|
|
17
|
+
11. + test/Monotonic/Timer_test.rb: the floor, and that a timed block returns a measurement which carries the interval and the floor.
|
|
18
|
+
12. ~ test/gemspec_test.rb: the runtime dependency list.
|
|
19
|
+
13. ~ README.md: + the floor and the measurement, and what a timed block now hands back.
|
|
20
|
+
14. ~ Monotonic::VERSION: /0.8.0/0.9.0/
|
|
21
|
+
|
|
22
|
+
|
|
3
23
|
## 20260816
|
|
4
24
|
|
|
5
25
|
0.8.0: Use duration.rb gem.
|
data/README.md
CHANGED
|
@@ -35,6 +35,22 @@ timer.total_nanoseconds
|
|
|
35
35
|
# => 2508000, upon a clock which ticks in whole microseconds
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
A timed block hands back a `Monotonic::Measurement` rather than a bare number, so that what comes back says how much of itself is real. `Monotonic::Timer.floor` is what it costs to measure at all, taken by timing measurements of nothing, and the measurement shows only as many digits as that floor reaches — the doubt itself being [measurand](https://github.com/thoran/measurand)'s business, which combines an absolute floor with a relative drift in quadrature rather than by addition.
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
Monotonic::Timer.floor
|
|
42
|
+
# => 84
|
|
43
|
+
measurement = Monotonic::Timer.time{sleep 0.001}
|
|
44
|
+
measurement.to_s
|
|
45
|
+
# => "1.26562 ms"
|
|
46
|
+
measurement.uncertainty
|
|
47
|
+
# => 84.0
|
|
48
|
+
measurement.to_duration.to_microseconds.to_f
|
|
49
|
+
# => 1265.625
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Nothing is capped: a day resolved to a hundred nanoseconds prints every figure it has, the absurdity being the mismatch between what the instrument resolves and what was asked of it, which is better seen than rounded away. The floor is a floor and not an error bar — the tail is unbounded and one-sided, the scheduler being free to take the processor away between the two readings — so repeat and take a robust statistic where that matters.
|
|
53
|
+
|
|
38
54
|
|
|
39
55
|
## Installation
|
|
40
56
|
|
|
@@ -115,26 +131,26 @@ timer.total_time
|
|
|
115
131
|
```ruby
|
|
116
132
|
require 'monotonic.rb'
|
|
117
133
|
|
|
118
|
-
|
|
134
|
+
measurement = Monotonic::Timer.time do
|
|
119
135
|
i = 0
|
|
120
136
|
1_000_000.times{puts i += 1}
|
|
121
137
|
end
|
|
122
|
-
|
|
123
|
-
# => 6.
|
|
138
|
+
measurement.to_s
|
|
139
|
+
# => "6.97582 s"
|
|
124
140
|
```
|
|
125
141
|
|
|
126
142
|
### Monotonic::Timer with a block and block variable
|
|
127
143
|
|
|
128
144
|
```ruby
|
|
129
145
|
require 'monotonic.rb'
|
|
130
|
-
|
|
146
|
+
measurement = Monotonic::Timer.time do |timer|
|
|
131
147
|
i = 0
|
|
132
148
|
500_000.times{puts i += 1}
|
|
133
149
|
p timer.total_time
|
|
134
150
|
500_000.times{puts i += 1}
|
|
135
151
|
end
|
|
136
|
-
|
|
137
|
-
# => 6.
|
|
152
|
+
measurement.to_s
|
|
153
|
+
# => "6.97582 s"
|
|
138
154
|
```
|
|
139
155
|
|
|
140
156
|
### Monotonic::Timer with a block on a timer instance
|
|
@@ -142,12 +158,12 @@ time
|
|
|
142
158
|
```ruby
|
|
143
159
|
require 'monotonic.rb'
|
|
144
160
|
timer = Monotonic::Timer.new
|
|
145
|
-
|
|
161
|
+
measurement = timer.time do
|
|
146
162
|
i = 0
|
|
147
163
|
1_000_000.times{puts i += 1}
|
|
148
164
|
end
|
|
149
|
-
|
|
150
|
-
# => 7.
|
|
165
|
+
measurement.to_s
|
|
166
|
+
# => "7.03313 s"
|
|
151
167
|
```
|
|
152
168
|
|
|
153
169
|
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Monotonic/Measurement.rb
|
|
2
|
+
# Monotonic::Measurement
|
|
3
|
+
|
|
4
|
+
require 'duration.rb'
|
|
5
|
+
require 'measurand'
|
|
6
|
+
|
|
7
|
+
module Monotonic
|
|
8
|
+
# An elapsed interval together with what it is worth. The count alone says
|
|
9
|
+
# nothing of how much of itself is real, so #to_s shows only as many digits as
|
|
10
|
+
# the uncertainty supports. Nothing is capped: a day resolved to a hundred
|
|
11
|
+
# nanoseconds prints every figure it has, which looks absurd and is — the
|
|
12
|
+
# absurdity being the mismatch between what the instrument resolves and what
|
|
13
|
+
# was asked of it, and better seen than rounded away.
|
|
14
|
+
#
|
|
15
|
+
# The doubt is a Measurand's business and the unit is a Duration's; what is
|
|
16
|
+
# left here is the ladder between them and the string at the end of it.
|
|
17
|
+
class Measurement
|
|
18
|
+
include Comparable
|
|
19
|
+
|
|
20
|
+
# Powers of a thousand, and no further. The scheme is a decimal-places one,
|
|
21
|
+
# so minutes and hours have no place in it: 90s is plainer than 1.5min, and
|
|
22
|
+
# a run of a day reads as 86400s rather than reaching for a unit which does
|
|
23
|
+
# not divide by ten.
|
|
24
|
+
UNITS = [[1, 'ns'], [1_000, 'us'], [1_000_000, 'ms'], [1_000_000_000, 's']]
|
|
25
|
+
|
|
26
|
+
attr_reader :nanoseconds
|
|
27
|
+
attr_reader :drift
|
|
28
|
+
|
|
29
|
+
# The floor may be given as a number or as anything which answers to #call,
|
|
30
|
+
# so that measuring it can wait until somebody asks about doubt.
|
|
31
|
+
# Monotonic::Timer hands over its .floor method rather than its value, and a
|
|
32
|
+
# caller which only wants a number never sets the thousand null measurements
|
|
33
|
+
# going.
|
|
34
|
+
def floor
|
|
35
|
+
@floor = @floor.respond_to?(:call) ? @floor.call : @floor
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# The floor is absolute and tells upon short intervals; drift is relative
|
|
39
|
+
# and tells upon long ones, being the rate at which the clock's own
|
|
40
|
+
# oscillator wanders. Combining them is not addition — they are independent,
|
|
41
|
+
# so they go in quadrature — which is why the arithmetic is Measurand's and
|
|
42
|
+
# not done here.
|
|
43
|
+
def measurand
|
|
44
|
+
@measurand ||= (
|
|
45
|
+
absolute = Measurand.new(@nanoseconds, floor)
|
|
46
|
+
@drift ? absolute * Measurand.relative(1, @drift) : absolute
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def uncertainty
|
|
51
|
+
measurand.uncertainty
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def unit
|
|
55
|
+
@unit ||= UNITS.reverse.find{|scale, _| @nanoseconds.abs >= scale} || UNITS.first
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def scale
|
|
59
|
+
unit.first
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def unit_name
|
|
63
|
+
unit.last
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# The least significant digit worth showing is the one the uncertainty
|
|
67
|
+
# reaches, which Measurand settles by the Particle Data Group convention and
|
|
68
|
+
# reports as #place, a power of ten. Rendering in a coarser unit moves it
|
|
69
|
+
# along by however many tens that unit is worth. A measurand with no
|
|
70
|
+
# uncertainty has no last real digit, and answers nil.
|
|
71
|
+
def decimals
|
|
72
|
+
@decimals ||= (
|
|
73
|
+
place = measurand.place
|
|
74
|
+
place ? [Math.log10(scale) - place, 0].max.to_i : Math.log10(scale).to_i
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def to_duration
|
|
79
|
+
Duration::Nanoseconds.new(@nanoseconds)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Both answer in nanoseconds, this measurement's own unit, as
|
|
83
|
+
# Duration::Minutes answers 5 rather than 300. Every other unit comes from
|
|
84
|
+
# #to_duration, which names the one it is asked for. A number handed out
|
|
85
|
+
# without its unit stated must at least always mean the same thing.
|
|
86
|
+
def to_i
|
|
87
|
+
@nanoseconds
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def to_f
|
|
91
|
+
@nanoseconds.to_f
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def to_s
|
|
95
|
+
format("%.#{decimals}f #{unit_name}", @nanoseconds.to_f / scale)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Against another measurement only. A bare number has no unit, and comparing
|
|
99
|
+
# against one would have to assume which was meant, so nil is returned and ==
|
|
100
|
+
# is false, as Duration::Common does.
|
|
101
|
+
def <=>(other)
|
|
102
|
+
return nil unless other.is_a?(Monotonic::Measurement)
|
|
103
|
+
@nanoseconds <=> other.nanoseconds
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def inspect
|
|
107
|
+
"#<#{self.class} #{self} (#{measurand} ns)>"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
def initialize(nanoseconds, floor:, drift: nil)
|
|
113
|
+
@nanoseconds = nanoseconds
|
|
114
|
+
@floor = floor
|
|
115
|
+
@drift = drift
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
data/lib/Monotonic/Timer.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# Monotonic::Timer
|
|
3
3
|
|
|
4
4
|
require 'duration.rb'
|
|
5
|
+
require_relative './Measurement'
|
|
5
6
|
|
|
6
7
|
module Monotonic
|
|
7
8
|
class Timer
|
|
@@ -20,6 +21,10 @@ module Monotonic
|
|
|
20
21
|
# rigidity: a method call would be a measurable part of what it measures.
|
|
21
22
|
CLOCK = Process.const_get(CLOCK_NAMES.find{|name| Process.const_defined?(name)})
|
|
22
23
|
|
|
24
|
+
# How many measurements of nothing .floor takes, and which of them it keeps.
|
|
25
|
+
SAMPLES = 1_000
|
|
26
|
+
PERCENTILE = 0.95
|
|
27
|
+
|
|
23
28
|
class << self
|
|
24
29
|
def clock_name
|
|
25
30
|
@clock_name ||= CLOCK_NAMES.find{|name| Process.const_defined?(name)}
|
|
@@ -36,6 +41,24 @@ module Monotonic
|
|
|
36
41
|
def resolution
|
|
37
42
|
Process.clock_getres(CLOCK, :nanosecond)
|
|
38
43
|
end
|
|
44
|
+
|
|
45
|
+
# What it costs to measure at all, in nanoseconds, measured by timing
|
|
46
|
+
# measurements of nothing. The clock's tick is not the limit: two readings
|
|
47
|
+
# must be taken, and taking them takes time, so an interval near this
|
|
48
|
+
# figure is mostly the measuring.
|
|
49
|
+
#
|
|
50
|
+
# It is a floor and not an error bar. The typical cost is a tick or two;
|
|
51
|
+
# the tail is unbounded and one-sided, since the scheduler may take the
|
|
52
|
+
# processor away between the two readings and no single measurement can
|
|
53
|
+
# detect that it did. A high percentile is taken rather than a median, so
|
|
54
|
+
# that the ordinary case is covered rather than merely the best one.
|
|
55
|
+
# Repeat and take a robust statistic if the tail matters.
|
|
56
|
+
def floor
|
|
57
|
+
@floor ||= (
|
|
58
|
+
samples = SAMPLES.times.map{timer = new; timer.start; timer.stop; timer.total_nanoseconds}.sort
|
|
59
|
+
samples[(samples.length * PERCENTILE).to_i]
|
|
60
|
+
)
|
|
61
|
+
end
|
|
39
62
|
end # class << self
|
|
40
63
|
|
|
41
64
|
# Where the instants come from. Nothing supplied means the clock is read
|
|
@@ -87,6 +110,22 @@ module Monotonic
|
|
|
87
110
|
to_duration.to_seconds.to_f
|
|
88
111
|
end
|
|
89
112
|
|
|
113
|
+
# The elapsed interval together with what it is worth. Not memoized: a timer
|
|
114
|
+
# which has not been stopped is still running, and so is its measurement.
|
|
115
|
+
# The floor is handed over as a method rather than a figure, so that a caller
|
|
116
|
+
# which only ever wants a number never sets the thousand null measurements
|
|
117
|
+
# going.
|
|
118
|
+
def measurement(drift: nil)
|
|
119
|
+
Monotonic::Measurement.new(total_nanoseconds, floor: self.class.method(:floor), drift: drift)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def to_s
|
|
123
|
+
measurement.to_s
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# A Monotonic::Measurement rather than a bare Float, so that what comes back
|
|
127
|
+
# says how much of itself is real. #total_time and #total_nanoseconds are
|
|
128
|
+
# still there for a number.
|
|
90
129
|
def time
|
|
91
130
|
start
|
|
92
131
|
begin
|
|
@@ -94,7 +133,7 @@ module Monotonic
|
|
|
94
133
|
ensure
|
|
95
134
|
stop
|
|
96
135
|
end
|
|
97
|
-
|
|
136
|
+
measurement
|
|
98
137
|
end
|
|
99
138
|
|
|
100
139
|
private
|
data/lib/Monotonic/VERSION.rb
CHANGED
data/monotonic.rb.gemspec
CHANGED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
require_relative '../../lib/monotonic.rb'
|
|
2
|
+
|
|
3
|
+
require 'minitest/autorun'
|
|
4
|
+
require 'minitest-spec-context'
|
|
5
|
+
|
|
6
|
+
describe Monotonic::Measurement do
|
|
7
|
+
def measurement(nanoseconds, floor: 84, drift: nil)
|
|
8
|
+
Monotonic::Measurement.new(nanoseconds, floor: floor, drift: drift)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe "the unit" do
|
|
12
|
+
it "is the largest which leaves a mantissa of at least one" do
|
|
13
|
+
_(measurement(999).unit_name).must_equal('ns')
|
|
14
|
+
_(measurement(1_000).unit_name).must_equal('us')
|
|
15
|
+
_(measurement(1_265_625).unit_name).must_equal('ms')
|
|
16
|
+
_(measurement(1_000_000_000).unit_name).must_equal('s')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "stops at seconds, the ladder being powers of a thousand" do
|
|
20
|
+
_(measurement(86_400_000_000_000).unit_name).must_equal('s')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "is nanoseconds for nothing at all" do
|
|
24
|
+
_(measurement(0).to_s).must_equal('0 ns')
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "the digits" do
|
|
29
|
+
it "reach as far as the uncertainty does and no further" do
|
|
30
|
+
_(measurement(1_265_625).to_s).must_equal('1.26562 ms')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "are fewer upon a coarser instrument" do
|
|
34
|
+
_(measurement(1_265_625, floor: 100_000).to_s).must_equal('1.27 ms')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "are none where the interval is near the floor" do
|
|
38
|
+
_(measurement(999).to_s).must_equal('999 ns')
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "are not capped, a day resolved to a hundred nanoseconds saying so" do
|
|
42
|
+
_(measurement(86_400_000_000_000).to_s).must_equal('86400.00000000 s')
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe "the uncertainty" do
|
|
47
|
+
it "is the floor alone when no drift is supplied" do
|
|
48
|
+
_(measurement(1_000_000).uncertainty).must_equal(84)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "combines a drift in quadrature rather than by addition" do
|
|
52
|
+
combined = measurement(1_000_000_000, drift: 1e-6).uncertainty
|
|
53
|
+
_(combined).must_be_close_to(Math.sqrt(84**2 + 1_000**2), 0.01)
|
|
54
|
+
_(combined).wont_be_close_to(84 + 1_000, 1)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "takes digits away as it grows" do
|
|
58
|
+
_(measurement(7_166_559_999, drift: 20e-6).decimals) \
|
|
59
|
+
.must_be(:<, measurement(7_166_559_999).decimals)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "comes from a Measurand, which owns the arithmetic" do
|
|
63
|
+
_(measurement(1_000_000).measurand).must_be_instance_of(Measurand)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe "the floor" do
|
|
68
|
+
it "may be a number" do
|
|
69
|
+
_(measurement(1_000_000, floor: 84).floor).must_equal(84)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "may be something callable, and is not called until doubt is asked about" do
|
|
73
|
+
called = false
|
|
74
|
+
subject = Monotonic::Measurement.new(1_000_000, floor: ->{called = true; 84})
|
|
75
|
+
subject.to_i
|
|
76
|
+
subject.to_duration
|
|
77
|
+
_(called).must_equal(false)
|
|
78
|
+
subject.uncertainty
|
|
79
|
+
_(called).must_equal(true)
|
|
80
|
+
_(subject.floor).must_equal(84)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe "comparison" do
|
|
85
|
+
it "orders one measurement against another" do
|
|
86
|
+
_(measurement(999)).must_be(:<, measurement(1_000))
|
|
87
|
+
_([measurement(1_000), measurement(999)].sort.map(&:nanoseconds)).must_equal([999, 1_000])
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "is nil against a bare number, which has no unit" do
|
|
91
|
+
_(measurement(999) <=> 999).must_be_nil
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "is therefore not equal to a bare number" do
|
|
95
|
+
_(measurement(999) == 999).must_equal(false)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
describe "#to_duration" do
|
|
100
|
+
it "hands the interval to duration.rb, whose business the units are" do
|
|
101
|
+
_(measurement(1_500_000_000).to_duration).must_be_instance_of(Duration::Nanoseconds)
|
|
102
|
+
_(measurement(1_500_000_000).to_duration.to_seconds.to_f).must_equal(1.5)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe "#to_i and #to_f" do
|
|
107
|
+
it "both answer in nanoseconds, the measurement's own unit" do
|
|
108
|
+
_(measurement(1_274_625).to_i).must_equal(1_274_625)
|
|
109
|
+
_(measurement(1_274_625).to_f).must_equal(1_274_625.0)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "agree with one another, and with #nanoseconds" do
|
|
113
|
+
subject = measurement(1_274_625)
|
|
114
|
+
_(subject.to_f).must_equal(subject.to_i.to_f)
|
|
115
|
+
_(subject.to_i).must_equal(subject.nanoseconds)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -9,7 +9,7 @@ describe Monotonic::Timer do
|
|
|
9
9
|
block_time = Monotonic::Timer.time do |timer|
|
|
10
10
|
sleep 3
|
|
11
11
|
end
|
|
12
|
-
expect(block_time.round).must_equal(3)
|
|
12
|
+
expect(block_time.to_duration.to_seconds.to_f.round).must_equal(3)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
# Test introduced in 0.6.5 to demonstrate that the bug had been fixed.
|
|
@@ -18,7 +18,7 @@ describe Monotonic::Timer do
|
|
|
18
18
|
sleep 3
|
|
19
19
|
4
|
|
20
20
|
end
|
|
21
|
-
expect(block_time.round).must_equal(3)
|
|
21
|
+
expect(block_time.to_duration.to_seconds.to_f.round).must_equal(3)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
# Test introduced in 0.6.7 to demonstrate that the bug had been fixed.
|
|
@@ -51,7 +51,7 @@ describe Monotonic::Timer do
|
|
|
51
51
|
timer.start
|
|
52
52
|
sleep 1
|
|
53
53
|
end
|
|
54
|
-
expect(block_time.round).must_equal(1)
|
|
54
|
+
expect(block_time.to_duration.to_seconds.to_f.round).must_equal(1)
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
|
|
@@ -88,7 +88,7 @@ describe Monotonic::Timer do
|
|
|
88
88
|
expect(timer.total_time.round).must_equal(0)
|
|
89
89
|
sleep 1
|
|
90
90
|
end
|
|
91
|
-
expect(time.round).must_equal(1)
|
|
91
|
+
expect(time.to_duration.to_seconds.to_f.round).must_equal(1)
|
|
92
92
|
expect(timer.total_time.round).must_equal(1)
|
|
93
93
|
end
|
|
94
94
|
|
data/test/gemspec_test.rb
CHANGED
|
@@ -19,7 +19,7 @@ describe 'monotonic.rb.gemspec' do
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
it "declares its runtime dependencies" do
|
|
22
|
-
_(spec.runtime_dependencies.map(&:name).sort).must_equal(%w{duration.rb sys-uptime})
|
|
22
|
+
_(spec.runtime_dependencies.map(&:name).sort).must_equal(%w{duration.rb measurand sys-uptime})
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
it "declares its development dependencies" do
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: monotonic.rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- thoran
|
|
@@ -23,6 +23,20 @@ dependencies:
|
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: 0.4.0
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: measurand
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 0.1.0
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 0.1.0
|
|
26
40
|
- !ruby/object:Gem::Dependency
|
|
27
41
|
name: sys-uptime
|
|
28
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -89,11 +103,13 @@ files:
|
|
|
89
103
|
- Gemfile
|
|
90
104
|
- README.md
|
|
91
105
|
- Rakefile
|
|
106
|
+
- lib/Monotonic/Measurement.rb
|
|
92
107
|
- lib/Monotonic/Time.rb
|
|
93
108
|
- lib/Monotonic/Timer.rb
|
|
94
109
|
- lib/Monotonic/VERSION.rb
|
|
95
110
|
- lib/monotonic.rb
|
|
96
111
|
- monotonic.rb.gemspec
|
|
112
|
+
- test/Monotonic/Measurement_test.rb
|
|
97
113
|
- test/Monotonic/Time_test.rb
|
|
98
114
|
- test/Monotonic/Timer_test.rb
|
|
99
115
|
- test/Monotonic/VERSION_test.rb
|