monotime 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|