monotime 0.4.0 → 0.5.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/.rubocop.yml +9 -0
- data/README.md +8 -0
- data/lib/monotime.rb +128 -19
- data/lib/monotime/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bbb84fdd4db4d629ca5d4cc847c47d9003f4553f010b575364f7ad562c16bb4d
|
4
|
+
data.tar.gz: 40729463ba3970e77110c2ae92620f4d6ca08b6d9997776272a3d0a05a03b595
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2916513d7d5dada28d18855d7644055cf82ddd6d2ad66ebd27c7a73d9ae2c88cde94887e7769d007372768c7acbcac32d8210308f9bc2ba2256b150126f29d9b
|
7
|
+
data.tar.gz: cff3a4bd7be443460f7dfc65432da3f3d30fef62433e5caa73c932497d490fdc5641b34659f18d8790bb0797449d93b9019f46678c0489b3aa9756c871222bd1
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -108,6 +108,14 @@ loop do
|
|
108
108
|
end
|
109
109
|
```
|
110
110
|
|
111
|
+
Or you can declare a future `Instant` and ask to sleep until it passes:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
next_minute = Instant.now + Duration.from_secs(60)
|
115
|
+
do_stuff
|
116
|
+
next_minute.sleep # => sleeps any remaining seconds
|
117
|
+
```
|
118
|
+
|
111
119
|
`Instant#sleep` returns a `Duration` which was slept, or a negative `Duration` if
|
112
120
|
the desired sleep period has passed.
|
113
121
|
|
data/lib/monotime.rb
CHANGED
@@ -8,7 +8,8 @@ module Monotime
|
|
8
8
|
class Instant
|
9
9
|
# A measurement, in nanoseconds. Should be considered opaque and
|
10
10
|
# non-portable outside the process that created it.
|
11
|
-
|
11
|
+
attr_reader :ns
|
12
|
+
protected :ns
|
12
13
|
|
13
14
|
include Comparable
|
14
15
|
|
@@ -17,6 +18,7 @@ module Monotime
|
|
17
18
|
# Users should generally *not* pass anything to this function.
|
18
19
|
#
|
19
20
|
# @param nanos [Integer]
|
21
|
+
# @see #now
|
20
22
|
def initialize(nanos = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond))
|
21
23
|
@ns = Integer(nanos)
|
22
24
|
end
|
@@ -45,7 +47,9 @@ module Monotime
|
|
45
47
|
duration_since(self.class.now)
|
46
48
|
end
|
47
49
|
|
48
|
-
# Sleep
|
50
|
+
# Sleep until this +Instant+, plus an optional +Duration+, returning a +Duration+
|
51
|
+
# that's either positive if any time was slept, or negative if sleeping would
|
52
|
+
# require time travel.
|
49
53
|
#
|
50
54
|
# @example Sleeps for a second
|
51
55
|
# start = Instant.now
|
@@ -53,13 +57,17 @@ module Monotime
|
|
53
57
|
# start.sleep(Duration.from_secs(1)).to_s # => "490.088706ms" (slept)
|
54
58
|
# start.sleep(Duration.from_secs(1)).to_s # => "-12.963502ms" (did not sleep)
|
55
59
|
#
|
56
|
-
# @
|
60
|
+
# @example Also sleeps for a second.
|
61
|
+
# one_second_in_the_future = Instant.now + Duration.from_secs(1)
|
62
|
+
# one_second_in_the_future.sleep.to_s # => "985.592712ms" (slept)
|
63
|
+
# one_second_in_the_future.sleep.to_s # => "-4.71217ms" (did not sleep)
|
64
|
+
#
|
65
|
+
# @param duration [nil, Duration, #to_nanos]
|
57
66
|
# @return [Duration] the slept duration, if +#positive?+, else the overshot time
|
58
|
-
def sleep(duration)
|
59
|
-
remaining = duration - elapsed
|
67
|
+
def sleep(duration = nil)
|
68
|
+
remaining = duration ? duration - elapsed : -elapsed
|
60
69
|
|
61
|
-
|
62
|
-
remaining.tap(&:sleep)
|
70
|
+
remaining.tap { |rem| rem.sleep if rem.positive? }
|
63
71
|
end
|
64
72
|
|
65
73
|
# Sleep for the given number of seconds past this +Instant+, if any.
|
@@ -80,8 +88,8 @@ module Monotime
|
|
80
88
|
# @param millis [Numeric] number of milliseconds to sleep past this +Instant+
|
81
89
|
# @return [Duration] the slept duration, if +#positive?+, else the overshot time
|
82
90
|
# @see #sleep
|
83
|
-
def sleep_millis(
|
84
|
-
sleep(Duration.from_millis(
|
91
|
+
def sleep_millis(millis)
|
92
|
+
sleep(Duration.from_millis(millis))
|
85
93
|
end
|
86
94
|
|
87
95
|
# Sugar for +#elapsed.to_s+.
|
@@ -94,6 +102,9 @@ module Monotime
|
|
94
102
|
# Add a +Duration+ or +#to_nanos+-coercible object to this +Instant+, returning
|
95
103
|
# a new +Instant+.
|
96
104
|
#
|
105
|
+
# @example
|
106
|
+
# (Instant.now + Duration.from_secs(1)).to_s # => "-999.983976ms"
|
107
|
+
#
|
97
108
|
# @param other [Duration, #to_nanos]
|
98
109
|
# @return [Instant]
|
99
110
|
def +(other)
|
@@ -106,6 +117,10 @@ module Monotime
|
|
106
117
|
# or a +Duration+ or +#to_nanos+-coercible object, to generate an +Instant+
|
107
118
|
# offset by it.
|
108
119
|
#
|
120
|
+
# @example
|
121
|
+
# (Instant.now - Duration.from_secs(1)).to_s # => "1.000016597s"
|
122
|
+
# (Instant.now - Instant.now).to_s # => "-3.87μs"
|
123
|
+
#
|
109
124
|
# @param other [Instant, Duration, #to_nanos]
|
110
125
|
# @return [Duration, Instant]
|
111
126
|
def -(other)
|
@@ -152,7 +167,10 @@ module Monotime
|
|
152
167
|
# Create a new +Duration+ of a specified number of nanoseconds, zero by
|
153
168
|
# default.
|
154
169
|
#
|
170
|
+
# Users are strongly advised to use +#from_nanos+ instead.
|
171
|
+
#
|
155
172
|
# @param nanos [Integer]
|
173
|
+
# @see #from_nanos
|
156
174
|
def initialize(nanos = 0)
|
157
175
|
@ns = Integer(nanos)
|
158
176
|
end
|
@@ -163,7 +181,7 @@ module Monotime
|
|
163
181
|
# @param secs [Numeric]
|
164
182
|
# @return [Duration]
|
165
183
|
def from_secs(secs)
|
166
|
-
new(Integer(
|
184
|
+
new(Integer(secs * 1_000_000_000))
|
167
185
|
end
|
168
186
|
|
169
187
|
# Generate a new +Duration+ measuring the given number of milliseconds.
|
@@ -171,7 +189,7 @@ module Monotime
|
|
171
189
|
# @param millis [Numeric]
|
172
190
|
# @return [Duration]
|
173
191
|
def from_millis(millis)
|
174
|
-
new(Integer(
|
192
|
+
new(Integer(millis * 1_000_000))
|
175
193
|
end
|
176
194
|
|
177
195
|
# Generate a new +Duration+ measuring the given number of microseconds.
|
@@ -179,7 +197,7 @@ module Monotime
|
|
179
197
|
# @param micros [Numeric]
|
180
198
|
# @return [Duration]
|
181
199
|
def from_micros(micros)
|
182
|
-
new(Integer(
|
200
|
+
new(Integer(micros * 1_000))
|
183
201
|
end
|
184
202
|
|
185
203
|
# Generate a new +Duration+ measuring the given number of nanoseconds.
|
@@ -192,6 +210,9 @@ module Monotime
|
|
192
210
|
|
193
211
|
# Return a +Duration+ measuring the elapsed time of the yielded block.
|
194
212
|
#
|
213
|
+
# @example
|
214
|
+
# Duration.measure { sleep(0.5) }.to_s # => "512.226109ms"
|
215
|
+
#
|
195
216
|
# @return [Duration]
|
196
217
|
def measure
|
197
218
|
Instant.now.tap { yield }.elapsed
|
@@ -201,8 +222,10 @@ module Monotime
|
|
201
222
|
# Add another +Duration+ or +#to_nanos+-coercible object to this one,
|
202
223
|
# returning a new +Duration+.
|
203
224
|
#
|
204
|
-
# @
|
225
|
+
# @example
|
226
|
+
# (Duration.from_secs(10) + Duration.from_secs(5)).to_s # => "15s"
|
205
227
|
#
|
228
|
+
# @param [Duration, #to_nanos]
|
206
229
|
# @return [Duration]
|
207
230
|
def +(other)
|
208
231
|
raise TypeError, 'Not one of: [Duration, #to_nanos]' unless other.respond_to?(:to_nanos)
|
@@ -213,6 +236,9 @@ module Monotime
|
|
213
236
|
# Subtract another +Duration+ or +#to_nanos+-coercible object from this one,
|
214
237
|
# returning a new +Duration+.
|
215
238
|
#
|
239
|
+
# @example
|
240
|
+
# (Duration.from_secs(10) - Duration.from_secs(5)).to_s # => "5s"
|
241
|
+
#
|
216
242
|
# @param [Duration, #to_nanos]
|
217
243
|
# @return [Duration]
|
218
244
|
def -(other)
|
@@ -223,6 +249,9 @@ module Monotime
|
|
223
249
|
|
224
250
|
# Divide this duration by a +Numeric+.
|
225
251
|
#
|
252
|
+
# @example
|
253
|
+
# (Duration.from_secs(10) / 2).to_s # => "5s"
|
254
|
+
#
|
226
255
|
# @param [Numeric]
|
227
256
|
# @return [Duration]
|
228
257
|
def /(other)
|
@@ -231,12 +260,38 @@ module Monotime
|
|
231
260
|
|
232
261
|
# Multiply this duration by a +Numeric+.
|
233
262
|
#
|
263
|
+
# @example
|
264
|
+
# (Duration.from_secs(10) * 2).to_s # => "20s"
|
265
|
+
#
|
234
266
|
# @param [Numeric]
|
235
267
|
# @return [Duration]
|
236
268
|
def *(other)
|
237
269
|
Duration.new(to_nanos * other)
|
238
270
|
end
|
239
271
|
|
272
|
+
# Unary minus: make a positive +Duration+ negative, and vice versa.
|
273
|
+
#
|
274
|
+
# @example
|
275
|
+
# -Duration.from_secs(-1).to_s # => "1s"
|
276
|
+
# -Duration.from_secs(1).to_s # => "-1s"
|
277
|
+
#
|
278
|
+
# @return [Duration]
|
279
|
+
def -@
|
280
|
+
Duration.new(-to_nanos)
|
281
|
+
end
|
282
|
+
|
283
|
+
# Return a +Duration+ that's absolute (positive).
|
284
|
+
#
|
285
|
+
# @example
|
286
|
+
# Duration.from_secs(-1).abs.to_s # => "1s"
|
287
|
+
# Duration.from_secs(1).abs.to_s # => "1s"
|
288
|
+
#
|
289
|
+
# @return [Duration]
|
290
|
+
def abs
|
291
|
+
return self if positive? || zero?
|
292
|
+
Duration.new(to_nanos.abs)
|
293
|
+
end
|
294
|
+
|
240
295
|
# Compare the *value* of this +Duration+ with another, or any +#to_nanos+-coercible
|
241
296
|
# object, or nil if not comparable.
|
242
297
|
#
|
@@ -322,6 +377,10 @@ module Monotime
|
|
322
377
|
# Sleep for the duration of this +Duration+. Equivalent to
|
323
378
|
# +Kernel.sleep(duration.to_secs)+.
|
324
379
|
#
|
380
|
+
# @example
|
381
|
+
# Duration.from_secs(1).sleep # => 1
|
382
|
+
# Duration.from_secs(-1).sleep # => raises NotImplementedError
|
383
|
+
#
|
325
384
|
# @raise [NotImplementedError] negative +Duration+ sleeps are not yet supported.
|
326
385
|
# @return [Integer]
|
327
386
|
# @see Instant#sleep
|
@@ -345,16 +404,66 @@ module Monotime
|
|
345
404
|
# The exact format is subject to change, users with specific requirements
|
346
405
|
# are encouraged to use their own formatting methods.
|
347
406
|
#
|
407
|
+
# @example
|
408
|
+
# Duration.from_nanos(100).to_s # => "100ns"
|
409
|
+
# Duration.from_micros(100).to_s # => "100μs"
|
410
|
+
# Duration.from_millis(100).to_s # => "100ms"
|
411
|
+
# Duration.from_secs(100).to_s # => "100s"
|
412
|
+
# Duration.from_nanos(1234567).to_s # => "1.234567ms"
|
413
|
+
# Duration.from_nanos(1234567).to_s(2) # => "1.23ms"
|
414
|
+
#
|
348
415
|
# @param precision [Integer] the maximum number of decimal places
|
349
416
|
# @return [String]
|
350
417
|
def to_s(precision = 9)
|
351
418
|
precision = Integer(precision).abs
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
419
|
+
div, unit = DIVISORS.find { |d, _| to_nanos.abs >= d }
|
420
|
+
|
421
|
+
if div.zero?
|
422
|
+
format('%d%s', to_nanos, unit)
|
423
|
+
else
|
424
|
+
format("%#.#{precision}f", to_nanos / div).sub(/\.?0*\z/, '') << unit
|
425
|
+
end
|
358
426
|
end
|
427
|
+
|
428
|
+
# def to_s_bigdecimal(precision = 9)
|
429
|
+
# require 'bigdecimal'
|
430
|
+
# precision = Integer(precision).abs
|
431
|
+
# div, unit = DIVISORS.find { |d, _| to_nanos.abs >= d }
|
432
|
+
|
433
|
+
# if div.zero?
|
434
|
+
# format('%d%s', to_nanos, unit)
|
435
|
+
# else
|
436
|
+
# num = (BigDecimal(to_nanos) / div.to_i)
|
437
|
+
# .round(precision, :banker).to_s('F').sub(/\.?0*$/, '')
|
438
|
+
# format('%s%s', num, unit)
|
439
|
+
# end
|
440
|
+
# end
|
441
|
+
|
442
|
+
# def to_s_divmod(precision = 9)
|
443
|
+
# precision = Integer(precision).abs
|
444
|
+
|
445
|
+
# ns = to_nanos.abs
|
446
|
+
# div, unit = DIVISORS.find { |d, _| ns >= d }
|
447
|
+
|
448
|
+
# return format('%dns', to_nanos) if div.zero?
|
449
|
+
|
450
|
+
# whole, frac = to_nanos.divmod(div.to_i)
|
451
|
+
|
452
|
+
# if precision.zero? || frac.zero?
|
453
|
+
# whole += 1 if frac > div / 2
|
454
|
+
# return format('%d%s', whole, unit)
|
455
|
+
# end
|
456
|
+
|
457
|
+
# # XXX: still need to round: Duration.from_nanos(99999999999).to_s_divmod 7 # => 99.1s
|
458
|
+
# p frac
|
459
|
+
# frac = ((frac / div.to_f) * (10 ** precision)).round
|
460
|
+
# if frac.to_s =~ /\A10*\z/ # erm...
|
461
|
+
# whole += 1
|
462
|
+
# frac = 0
|
463
|
+
# end
|
464
|
+
# num = format('%d.%d', whole, frac)
|
465
|
+
# num.sub!(/\.?0*\z/, '') if precision.nonzero?
|
466
|
+
# num << unit
|
467
|
+
# end
|
359
468
|
end
|
360
469
|
end
|
data/lib/monotime/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: monotime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Hurst
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-10-
|
11
|
+
date: 2018-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|