monotime 0.7.1 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a9395967e506d690912041251bc7b6afd1a373aa49d0b4425ec08ca611e5238
4
- data.tar.gz: '09ec6a1e96c9ce434d4847d275d85f7514c4a9bb3d9c71d205b04ab0f06e6d5b'
3
+ metadata.gz: 207159be0c76004c8676ac860106cd133344a29ca0021decbc14bc7448a17fab
4
+ data.tar.gz: 89c97583a40bfe82dd7c822cfd9a165be19c796cdf32396ee49ef861bbf7fb32
5
5
  SHA512:
6
- metadata.gz: a68a338484a8534a8953abf5bec0a98a6b7a2dc6a506cd1f5fb1e3b29e1b534fa0d41e4175aa81598273ee5d706d16caeb60ce1b89a92b5e8192f87a960265f3
7
- data.tar.gz: f9f329d74339eccc1b4c50007d2cb93cc87132ce6a5841faa327d4db48dfb347df8faee3f9777551cb686e90001def65d72c8a77c6b6df4dfed1d847598ac685
6
+ metadata.gz: c3aa917f832adedaa98acca61c58858d9e4ce57922d3ba457921b2e2c8adc023875a328c308258555f38dbb482168da73f7488c6306bd9751089b3ef21f5e7b0
7
+ data.tar.gz: b340008fa59637177c6c3caad1d4f5816ba8626a533993d3cc8de615b4c12899b3939e4338f6dae04d66fa09c90e6d7de06667cd02af915c2717bef7fca9aa25
@@ -2,13 +2,14 @@ name: CI
2
2
  on: [push, pull_request]
3
3
  jobs:
4
4
  test:
5
- runs-on: ubuntu-latest
6
5
  strategy:
7
6
  fail-fast: false
8
7
  matrix:
9
- ruby: ['2.5', '2.6', '2.7', '3.0', jruby, truffleruby]
8
+ os: [ubuntu-latest, macos-latest]
9
+ ruby: ['2.7', '3.0', '3.1', '3.2', head, jruby, jruby-head, truffleruby, truffleruby-head]
10
+ runs-on: ${{ matrix.os }}
10
11
  steps:
11
- - uses: actions/checkout@v2
12
+ - uses: actions/checkout@v4
12
13
  - uses: ruby/setup-ruby@v1
13
14
  with:
14
15
  ruby-version: ${{ matrix.ruby }}
data/.rubocop.yml CHANGED
@@ -11,7 +11,10 @@ Layout/LineLength:
11
11
  Max: 96
12
12
 
13
13
  Metrics/ClassLength:
14
- Max: 120
14
+ Max: 140
15
+
16
+ Metrics/MethodLength:
17
+ Max: 20
15
18
 
16
19
  Style/AsciiComments:
17
20
  Enabled: false
@@ -36,3 +39,6 @@ Style/ExplicitBlockArgument:
36
39
 
37
40
  Style/MixinUsage:
38
41
  Enabled: false
42
+
43
+ Style/TrailingCommaInArrayLiteral:
44
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,100 +1,172 @@
1
1
  # Changelog
2
2
 
3
- ## 0.7.1 - 2021-10-22
3
+ ## [0.8.1] - 2023-09-18
4
+
5
+ ### Changed
6
+
7
+ - After further consideration, return to defaulting to `CLOCK_MONOTONIC` instead
8
+ of the overly-elaborate auto-selection introduced in 0.8.0.
9
+
10
+ ### Removed
11
+
12
+ - `Instant.clock_name`. No I'm not incrementing to 0.9. It's been a few hours,
13
+ you're not using it, shut up.
14
+
15
+ ## [0.8.0] - 2023-09-17
16
+
4
17
  ### Added
5
- - `simplecov` introduced to test suite.
6
- - `monotime/include.rb` to auto-include types globally.
18
+
19
+ - Default precision for `Duration#to_s` can be set using
20
+ `Duration.default_to_s_precision=`.
21
+ - Default sleep function can be set using `Duration.sleep_function=`
22
+ - `Duration::ZERO` and `Duration.zero` for an easy, memory-efficient
23
+ zero-duration singleton.
24
+ - `Instant.clock_id` and `Instant.clock_id=` to control the default clock
25
+ source.
26
+ - `Instant.clock_getres` to get the minimum supported `Duration` from the
27
+ selected clock source.
28
+ - `Instant.monotonic_function=` to completely replace the default monotonic
29
+ function.
7
30
 
8
31
  ### Changed
9
- - All `Instant` and `Duration` instances are now frozen.
10
- - Migrate from Travis CI to Github Actions
11
- - Update development dependency on `rake`.
32
+
33
+ - The default clock source is now chosen from a selection of options instead of
34
+ defaulting to `CLOCK_MONOTONIC``. Where possible options are used which are
35
+ unaffected by NTP frequency skew and which do not count time in system suspend.
36
+ - CI matrix drops Ruby 2.5 and 2.6 and adds 3.1, 3.2, head branches of Ruby,
37
+ JRuby, and TruffleRuby, and also tests under macOS.
38
+
39
+ ### Fixed
40
+
41
+ - CI on TruffleRuby has been fixed by disabling SimpleCov.
42
+ - Several fragile tests depending on relatively narrow sleep times have been fixed.
43
+
44
+ ### Thanks
45
+
46
+ - [@petergoldstein] for fixing CI on TruffleRuby and adding 3.1 and 3.2.
47
+ - [@fig] for fixing a README error.
48
+
49
+ ## [0.7.1] - 2021-10-22
50
+
51
+ ### Added
52
+
53
+ - `simplecov` introduced to test suite.
54
+ - `monotime/include.rb` to auto-include types globally.
55
+
56
+ ### Changed
57
+
58
+ - All `Instant` and `Duration` instances are now frozen.
59
+ - Migrate from Travis CI to Github Actions
60
+ - Update development dependency on `rake`.
12
61
 
13
62
  ## [0.7.0] - 2019-04-24
63
+
14
64
  ### Added
15
- - `Duration.with_measure`, which yields and returns an array containing its
16
- evaluated return value and its `Duration`.
65
+
66
+ - `Duration.with_measure`, which yields and returns an array containing its
67
+ evaluated return value and its `Duration`.
17
68
 
18
69
  ### Changed
19
- - Break `Duration` and `Instant` into their own files.
20
- - Rename `Monotime::VERSION` to `Monotime::MONOTIME_VERSION` to reduce
21
- potential for collision if the module is included.
22
- - Update to bundler 2.0.
23
- - Rework README.md. Includes fix for [issue #1] (added a "See Also" section).
70
+
71
+ - Break `Duration` and `Instant` into their own files.
72
+ - Rename `Monotime::VERSION` to `Monotime::MONOTIME_VERSION` to reduce
73
+ potential for collision if the module is included.
74
+ - Update to bundler 2.0.
75
+ - Rework README.md. Includes fix for [issue #1] (added a "See Also" section).
24
76
 
25
77
  ## [0.6.1] - 2018-10-26
78
+
26
79
  ### Fixed
27
- - Build gem from a clean git checkout, not my local development directory.
28
- No functional changes.
80
+
81
+ - Build gem from a clean git checkout, not my local development directory.
82
+ No functional changes.
29
83
 
30
84
  ## [0.6.0] - 2018-10-26
85
+
31
86
  ### Added
32
- - This `CHANGELOG.md` by request of [@celsworth].
33
- - Aliases for `Duration.from_*` and `Duration#to_*` without the prefix. e.g.
34
- `Duration.from_secs(42).to_secs == 42` can now be written as
35
- `Duration.secs(42).secs == 42`.
36
- - `Duration#nonzero?`.
37
- - `Instant#in_past?` and `Instant#in_future?`.
87
+
88
+ - This `CHANGELOG.md` by request of [@celsworth].
89
+ - Aliases for `Duration.from_*` and `Duration#to_*` without the prefix. e.g.
90
+ `Duration.from_secs(42).to_secs == 42` can now be written as
91
+ `Duration.secs(42).secs == 42`.
92
+ - `Duration#nonzero?`.
93
+ - `Instant#in_past?` and `Instant#in_future?`.
38
94
 
39
95
  ## [0.5.0] - 2018-10-13
96
+
40
97
  ### Added
41
- - `Duration#abs` to make a `Duration` positive.
42
- - `Duration#-@` to invert the sign of a `Duration`.
43
- - `Duration#positive?`
44
- - `Duration#negative?`
45
- - `Duration#zero?`
98
+
99
+ - `Duration#abs` to make a `Duration` positive.
100
+ - `Duration#-@` to invert the sign of a `Duration`.
101
+ - `Duration#positive?`
102
+ - `Duration#negative?`
103
+ - `Duration#zero?`
46
104
 
47
105
  ### Changed
48
- - `Instant#sleep` with no argument now sleeps until the `Instant`.
49
- - `Duration.from_*` no longer coerce their argument to `Float`.
50
- - `Duration#==` checks value via `#to_nanos`, not type.
51
- - `Duration#eql?` checks value and type.
52
- - `Duration#<=>` compares value via `#to_nanos`.
106
+
107
+ - `Instant#sleep` with no argument now sleeps until the `Instant`.
108
+ - `Duration.from_*` no longer coerce their argument to `Float`.
109
+ - `Duration#==` checks value via `#to_nanos`, not type.
110
+ - `Duration#eql?` checks value and type.
111
+ - `Duration#<=>` compares value via `#to_nanos`.
53
112
 
54
113
  ## [0.4.0] - 2018-10-09
114
+
55
115
  ### Added
56
- - `Instant#sleep` - sleep to a given `Duration` past an `Instant`.
57
- - `Instant#sleep_secs` and `Instant#sleep_millis` convenience methods.
58
- - `Duration#sleep` - sleep for the `Duration`.
59
- - `Duration#*` - multiply a `Duration` by a number.
60
- - `Duration#/` - divide a `Duration` by a number.
116
+
117
+ - `Instant#sleep` - sleep to a given `Duration` past an `Instant`.
118
+ - `Instant#sleep_secs` and `Instant#sleep_millis` convenience methods.
119
+ - `Duration#sleep` - sleep for the `Duration`.
120
+ - `Duration#*` - multiply a `Duration` by a number.
121
+ - `Duration#/` - divide a `Duration` by a number.
61
122
 
62
123
  ### Changed
63
- - More `#to_nanos` `Duration` duck-typing.
124
+
125
+ More `#to_nanos` `Duration` duck-typing.
64
126
 
65
127
  ## [0.3.0] - 2018-10-04
128
+
66
129
  ### Added
67
- - `#to_nanos` is now used to duck-type `Duration` everywhere.
130
+
131
+ - `#to_nanos` is now used to duck-type `Duration` everywhere.
68
132
 
69
133
  ### Changed
70
- - Make `<=>` return nil on invalid types, rather than raising a `TypeError`.
134
+
135
+ - Make `<=>` return nil on invalid types, rather than raising a `TypeError`.
71
136
 
72
137
  ### Removed
73
- - Dependency on `dry-equalizer`.
138
+
139
+ - Dependency on `dry-equalizer`.
74
140
 
75
141
  ## [0.2.0] - 2018-10-03
142
+
76
143
  ### Added
77
- - `Instant#to_s` as an alias for `#elapsed.to_s`
78
- - `Duration#to_nanos`, with some limited duck-typing.
144
+
145
+ - `Instant#to_s` as an alias for `#elapsed.to_s`
146
+ - `Duration#to_nanos`, with some limited duck-typing.
79
147
 
80
148
  ### Changed
81
- - Switch to microseconds internally.
82
- - `Duration#to_{secs,millis,micros}` now return a `Float`.
83
- - `Instant#ns` is now `protected`.
149
+
150
+ - Switch to microseconds internally.
151
+ - `Duration#to_{secs,millis,micros}` now return a `Float`.
152
+ - `Instant#ns` is now `protected`.
84
153
 
85
154
  ### Fixed
86
- - `Duration#to_s` zero-stripping with precision=0.
87
- - `Instant#-` argument ordering with other `Instant`.
88
- - `Duration#to_micros` returns microseconds, not picoseconds.
155
+
156
+ - `Duration#to_s` zero-stripping with precision=0.
157
+ - `Instant#-` argument ordering with other `Instant`.
158
+ - `Duration#to_micros` returns microseconds, not picoseconds.
89
159
 
90
160
  ### Removed
91
- - `Instant` and `Duration` maths methods no longer support passing an `Integer`
92
- number of nanoseconds.
161
+
162
+ - `Instant` and `Duration` maths methods no longer support passing an `Integer`
163
+ number of nanoseconds.
93
164
 
94
165
  ## [0.1.0] - 2018-10-02
166
+
95
167
  ### Added
96
- - Initial release
97
168
 
169
+ - Initial release
98
170
 
99
171
  [0.1.0]: https://github.com/Freaky/monotime/commits/v0.1.0
100
172
  [0.2.0]: https://github.com/Freaky/monotime/commits/v0.2.0
@@ -104,5 +176,11 @@
104
176
  [0.6.0]: https://github.com/Freaky/monotime/commits/v0.6.0
105
177
  [0.6.1]: https://github.com/Freaky/monotime/commits/v0.6.1
106
178
  [0.7.0]: https://github.com/Freaky/monotime/commits/v0.7.0
179
+ [0.7.1]: https://github.com/Freaky/monotime/commits/v0.7.0
180
+ [0.8.0]: https://github.com/Freaky/monotime/commits/v0.8.0
181
+ [0.8.1]: https://github.com/Freaky/monotime/commits/v0.8.1
107
182
  [issue #1]: https://github.com/Freaky/monotime/issues/1
183
+ [Ruby #16740]: https://bugs.ruby-lang.org/issues/16740
108
184
  [@celsworth]: https://github.com/celsworth
185
+ [@petergoldstein]: https://github.com/petergoldstein
186
+ [@fig]: https://github.com/fig
data/README.md CHANGED
@@ -1,12 +1,13 @@
1
- [![Gem Version](https://badge.fury.io/rb/monotime.svg)](https://badge.fury.io/rb/monotime)
2
- ![Build Status](https://github.com/Freaky/monotime/actions/workflows/ci.yml/badge.svg)
3
- [![Inline docs](http://inch-ci.org/github/Freaky/monotime.svg?branch=master)](http://inch-ci.org/github/Freaky/monotime)
4
- [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/gems/monotime)
5
1
 
6
2
  # Monotime
7
3
 
8
4
  A sensible interface to Ruby's monotonic clock, inspired by Rust.
9
5
 
6
+ [![Gem Version](https://badge.fury.io/rb/monotime.svg)](https://badge.fury.io/rb/monotime)
7
+ [![Build Status](https://github.com/Freaky/monotime/actions/workflows/ci.yml/badge.svg)](https://github.com/Freaky/monotime/actions)
8
+ [![Inline docs](http://inch-ci.org/github/Freaky/monotime.svg?branch=master)](http://inch-ci.org/github/Freaky/monotime)
9
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/gems/monotime)
10
+
10
11
  ## Installation
11
12
 
12
13
  Add this line to your application's Gemfile:
@@ -23,7 +24,7 @@ Or install it yourself as:
23
24
 
24
25
  $ gem install monotime
25
26
 
26
- `Monotime` is tested on Ruby 2.5&mdash;3.0 and recent JRuby 9.x releases.
27
+ `Monotime` is tested on Ruby 2.7+, TruffleRuby, and JRuby.
27
28
 
28
29
  ## Usage
29
30
 
@@ -106,7 +107,7 @@ Duration.secs(1).sleep # => 1
106
107
 
107
108
  So can `Instant`, taking a `Duration` and sleeping until the given `Duration`
108
109
  past the time the `Instant` was created, if any. This can be useful for
109
- maintaining a precise candence between tasks:
110
+ maintaining a precise cadence between tasks:
110
111
 
111
112
  ```ruby
112
113
  interval = Duration.secs(60)
@@ -159,7 +160,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
159
160
 
160
161
  ## Contributing
161
162
 
162
- Bug reports and pull requests are welcome on GitHub at https://github.com/Freaky/monotime.
163
+ Bug reports and pull requests are welcome on GitHub at <https://github.com/Freaky/monotime>.
163
164
 
164
165
  ## License
165
166
 
@@ -169,14 +170,19 @@ The gem is available as open source under the terms of the [MIT License](https:/
169
170
 
170
171
  ### Core Ruby
171
172
 
172
- For a zero-dependency alternative, see
173
+ For a zero-dependency alternative upon which `monotime` is based, see
173
174
  [`Process.clock_gettime`](https://ruby-doc.org/core-2.6.3/Process.html#method-c-clock_gettime).
174
- `monotime` currently only uses `Process::CLOCK_MONOTONIC`, but others may offer higher precision
175
- depending on platform.
175
+
176
+ `Process::CLOCK_MONOTONIC` is a safe default, but other options may offer better
177
+ behaviour in face of NTP frequency skew or suspend/resume and should be evaluated
178
+ carefully.
176
179
 
177
180
  ### Other Gems
178
181
 
179
182
  [hitimes](https://rubygems.org/gems/hitimes) is a popular and mature alternative
180
183
  which also includes a variety of features for gathering statistics about
181
- measurements, and may offer higher precision on some platforms.
184
+ measurements.
182
185
 
186
+ [concurrent-ruby](https://rubygems.org/gems/concurrent-ruby) includes
187
+ `Concurrent.monotonic_time`, which is at the time of writing a trivial proxy to
188
+ the aforementioned `Process::clock_gettime` with `Process::CLOCK_MONOTONIC`.
@@ -8,16 +8,57 @@ module Monotime
8
8
  # Create a new +Duration+ of a specified number of nanoseconds, zero by
9
9
  # default.
10
10
  #
11
- # Users are strongly advised to use +#from_nanos+ instead.
11
+ # Users are strongly advised to use +Duration.from_nanos+ instead.
12
12
  #
13
13
  # @param nanos [Integer]
14
- # @see #from_nanos
14
+ # @see from_nanos
15
15
  def initialize(nanos = 0)
16
16
  @ns = Integer(nanos)
17
17
  freeze
18
18
  end
19
19
 
20
+ # A static instance for zero durations
21
+ ZERO = allocate.tap { |d| d.__send__(:initialize, 0) }
22
+
23
+ class << self
24
+ # The sleep function used by all +Monotime+ sleep functions.
25
+ #
26
+ # This function must accept a positive +Float+ number of seconds and return
27
+ # the +Float+ time slept.
28
+ #
29
+ # Defaults to +Kernel.method(:sleep)+
30
+ #
31
+ # @overload sleep_function=(function)
32
+ # @param function [#call]
33
+ attr_accessor :sleep_function
34
+
35
+ # Precision for +Duration#to_s+ if not otherwise specified
36
+ #
37
+ # Defaults to 9.
38
+ #
39
+ # @overload default_to_s_precision=(precision)
40
+ # @param precision [Numeric]
41
+ attr_accessor :default_to_s_precision
42
+ end
43
+
44
+ self.sleep_function = Kernel.method(:sleep)
45
+ self.default_to_s_precision = 9
46
+
20
47
  class << self
48
+ # @!visibility private
49
+ def new(nanos = 0)
50
+ return ZERO if nanos.zero?
51
+
52
+ super
53
+ end
54
+
55
+ # Return a zero +Duration+.
56
+ #
57
+ # @return [Duration]
58
+ def zero
59
+ ZERO
60
+ end
61
+
21
62
  # Generate a new +Duration+ measuring the given number of seconds.
22
63
  #
23
64
  # @param secs [Numeric]
@@ -87,7 +128,7 @@ module Monotime
87
128
  # @example
88
129
  # (Duration.from_secs(10) + Duration.from_secs(5)).to_s # => "15s"
89
130
  #
90
- # @param [Duration, #to_nanos]
131
+ # @param other [Duration, #to_nanos]
91
132
  # @return [Duration]
92
133
  def +(other)
93
134
  raise TypeError, 'Not one of: [Duration, #to_nanos]' unless other.respond_to?(:to_nanos)
@@ -101,7 +142,7 @@ module Monotime
101
142
  # @example
102
143
  # (Duration.from_secs(10) - Duration.from_secs(5)).to_s # => "5s"
103
144
  #
104
- # @param [Duration, #to_nanos]
145
+ # @param other [Duration, #to_nanos]
105
146
  # @return [Duration]
106
147
  def -(other)
107
148
  raise TypeError, 'Not one of: [Duration, #to_nanos]' unless other.respond_to?(:to_nanos)
@@ -114,7 +155,7 @@ module Monotime
114
155
  # @example
115
156
  # (Duration.from_secs(10) / 2).to_s # => "5s"
116
157
  #
117
- # @param [Numeric]
158
+ # @param other [Numeric]
118
159
  # @return [Duration]
119
160
  def /(other)
120
161
  Duration.new(to_nanos / other)
@@ -125,7 +166,7 @@ module Monotime
125
166
  # @example
126
167
  # (Duration.from_secs(10) * 2).to_s # => "20s"
127
168
  #
128
- # @param [Numeric]
169
+ # @param other [Numeric]
129
170
  # @return [Duration]
130
171
  def *(other)
131
172
  Duration.new(to_nanos * other)
@@ -158,7 +199,7 @@ module Monotime
158
199
  # Compare the *value* of this +Duration+ with another, or any +#to_nanos+-coercible
159
200
  # object, or nil if not comparable.
160
201
  #
161
- # @param [Duration, #to_nanos, Object]
202
+ # @param other [Duration, #to_nanos, Object]
162
203
  # @return [-1, 0, 1, nil]
163
204
  def <=>(other)
164
205
  to_nanos <=> other.to_nanos if other.respond_to?(:to_nanos)
@@ -167,7 +208,7 @@ module Monotime
167
208
  # Compare the equality of the *value* of this +Duration+ with another, or
168
209
  # any +#to_nanos+-coercible object, or nil if not comparable.
169
210
  #
170
- # @param [Duration, #to_nanos, Object]
211
+ # @param other [Duration, #to_nanos, Object]
171
212
  # @return [Boolean]
172
213
  def ==(other)
173
214
  other.respond_to?(:to_nanos) && to_nanos == other.to_nanos
@@ -175,7 +216,7 @@ module Monotime
175
216
 
176
217
  # Check equality of the value and type of this +Duration+ with another.
177
218
  #
178
- # @param [Duration, Object]
219
+ # @param other [Duration, Object]
179
220
  # @return [Boolean]
180
221
  def eql?(other)
181
222
  other.is_a?(Duration) && to_nanos == other.to_nanos
@@ -185,7 +226,7 @@ module Monotime
185
226
  #
186
227
  # @return [Integer]
187
228
  def hash
188
- self.class.hash ^ to_nanos.hash
229
+ [self.class, to_nanos].hash
189
230
  end
190
231
 
191
232
  # Return this +Duration+ in seconds.
@@ -255,6 +296,8 @@ module Monotime
255
296
  # Sleep for the duration of this +Duration+. Equivalent to
256
297
  # +Kernel.sleep(duration.to_secs)+.
257
298
  #
299
+ # The sleep function may be overridden globally using +Duration.sleep_function=+
300
+ #
258
301
  # @example
259
302
  # Duration.from_secs(1).sleep # => 1
260
303
  # Duration.from_secs(-1).sleep # => raises NotImplementedError
@@ -262,10 +305,11 @@ module Monotime
262
305
  # @raise [NotImplementedError] negative +Duration+ sleeps are not yet supported.
263
306
  # @return [Integer]
264
307
  # @see Instant#sleep
308
+ # @see sleep_function=
265
309
  def sleep
266
310
  raise NotImplementedError, 'time travel module missing' if negative?
267
311
 
268
- Kernel.sleep(to_secs)
312
+ self.class.sleep_function.call(to_secs)
269
313
  end
270
314
 
271
315
  DIVISORS = [
@@ -280,6 +324,8 @@ module Monotime
280
324
  # Format this +Duration+ into a human-readable string, with a given number
281
325
  # of decimal places.
282
326
  #
327
+ # The default precision may be set globally using +Duration.default_to_s_precision=+
328
+ #
283
329
  # The exact format is subject to change, users with specific requirements
284
330
  # are encouraged to use their own formatting methods.
285
331
  #
@@ -293,7 +339,8 @@ module Monotime
293
339
  #
294
340
  # @param precision [Integer] the maximum number of decimal places
295
341
  # @return [String]
296
- def to_s(precision = 9)
342
+ # @see default_to_s_precision=
343
+ def to_s(precision = self.class.default_to_s_precision)
297
344
  precision = Integer(precision).abs
298
345
  div, unit = DIVISORS.find { |d, _| to_nanos.abs >= d }
299
346
 
@@ -11,13 +11,74 @@ module Monotime
11
11
 
12
12
  include Comparable
13
13
 
14
+ class << self
15
+ # @overload clock_id
16
+ # The +Process.clock_gettime+ clock id used to create +Instant+ instances
17
+ # by the default monotonic function.
18
+ #
19
+ # @return [Numeric]
20
+ #
21
+ # @overload clock_id=(id)
22
+ #
23
+ # Override the default +Process.clock_gettime+ clock id. Some potential
24
+ # choices include but are not limited to:
25
+ #
26
+ # * +Process::CLOCK_MONOTONIC_RAW+
27
+ # * +Process::CLOCK_UPTIME_RAW+
28
+ # * +Process::CLOCK_UPTIME_PRECISE+
29
+ # * +Process::CLOCK_UPTIME_FAST+
30
+ # * +Process::CLOCK_UPTIME+
31
+ # * +Process::CLOCK_MONOTONIC_PRECISE+
32
+ # * +Process::CLOCK_MONOTONIC_FAST+
33
+ # * +Process::CLOCK_MONOTONIC+
34
+ #
35
+ # These are platform-dependant and may vary in resolution, performance,
36
+ # and behaviour from NTP frequency skew and system suspend/resume, and
37
+ # should be selected with care.
38
+ #
39
+ # It is possible to set non-monotonic clock sources here. You probably
40
+ # shouldn't.
41
+ #
42
+ # Defaults to +Process::CLOCK_MONOTONIC+.
43
+ #
44
+ # @param id [Numeric]
45
+ attr_accessor :clock_id
46
+
47
+ # The function used to create +Instant+ instances.
48
+ #
49
+ # This function must return a +Numeric+, monotonic count of nanoseconds
50
+ # since a fixed point in the past.
51
+ #
52
+ # Defaults to +-> { Process.clock_gettime(clock_id, :nanosecond) }+.
53
+ #
54
+ # @overload monotonic_function=(function)
55
+ # @param function [#call]
56
+ attr_accessor :monotonic_function
57
+
58
+ # Return the claimed resolution of the given clock id or the configured
59
+ # +clock_id+, as a +Duration+, or +nil+ if invalid.
60
+ #
61
+ # Note per Ruby issue #16740, the practical usability of this method is
62
+ # dubious and non-portable.
63
+ #
64
+ # @param clock [Numeric] Optional clock id instead of default.
65
+ def clock_getres(clock = clock_id)
66
+ Duration.from_nanos(Process.clock_getres(clock, :nanosecond))
67
+ rescue SystemCallError
68
+ # suppress errors
69
+ end
70
+ end
71
+
72
+ self.monotonic_function = -> { Process.clock_gettime(clock_id, :nanosecond) }
73
+ self.clock_id = Process::CLOCK_MONOTONIC
74
+
14
75
  # Create a new +Instant+ from an optional nanosecond measurement.
15
76
  #
16
77
  # Users should generally *not* pass anything to this function.
17
78
  #
18
79
  # @param nanos [Integer]
19
80
  # @see #now
20
- def initialize(nanos = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond))
81
+ def initialize(nanos = self.class.monotonic_function.call)
21
82
  @ns = Integer(nanos)
22
83
  freeze
23
84
  end
@@ -112,8 +173,8 @@ module Monotime
112
173
  # Sugar for +#elapsed.to_s+.
113
174
  #
114
175
  # @see Duration#to_s
115
- def to_s(*args)
116
- elapsed.to_s(*args)
176
+ def to_s(...)
177
+ elapsed.to_s(...)
117
178
  end
118
179
 
119
180
  # Add a +Duration+ or +#to_nanos+-coercible object to this +Instant+, returning
@@ -173,7 +234,7 @@ module Monotime
173
234
  #
174
235
  # @return [Integer]
175
236
  def hash
176
- self.class.hash ^ @ns.hash
237
+ [self.class, @ns].hash
177
238
  end
178
239
  end
179
240
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Monotime
4
- # Try to avoid blatting existing VERSION constants when we're included.
5
- MONOTIME_VERSION = '0.7.1'
4
+ # Version of the `monotime` gem
5
+ MONOTIME_VERSION = '0.8.1'
6
6
  end
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.7.1
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Hurst
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-22 00:00:00.000000000 Z
11
+ date: 2023-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -109,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  requirements: []
112
- rubygems_version: 3.2.22
112
+ rubygems_version: 3.4.18
113
113
  signing_key:
114
114
  specification_version: 4
115
115
  summary: A sensible interface to the monotonic clock