monotime 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +4 -3
- data/.rubocop.yml +7 -1
- data/CHANGELOG.md +115 -51
- data/README.md +17 -11
- data/lib/monotime/duration.rb +59 -12
- data/lib/monotime/instant.rb +97 -4
- data/lib/monotime/version.rb +2 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 388a55af121b75e9a9ac06db8674e5a8a4b06ade0431a5cdd961f82426c87ade
|
4
|
+
data.tar.gz: 7d62a9b673252f01591769d8659c5a36b1026088724a2afc9694b41f633ca053
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14c7ede1fc2daa4fef854d3be58392f57849ff07c4f815c3e995f32073e14893fa7ad95f08e074199457517d262fc8c2942316b8039260b1e66e4045409bb6cf
|
7
|
+
data.tar.gz: b2c907ce1b4f3f92185ba4cb238c3809b465d40be7e34eb1c4a225779a4f6c156ae1d78742ddf24a467d59bfd3437c15be54d4f8bc91a9a9d06fa42ee5e5544a
|
data/.github/workflows/ci.yml
CHANGED
@@ -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
|
-
|
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@
|
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:
|
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,160 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## 0.
|
3
|
+
## [0.8.0] - 2023-09-17
|
4
|
+
|
4
5
|
### Added
|
5
|
-
|
6
|
-
|
6
|
+
|
7
|
+
- Default precision for `Duration#to_s` can be set using
|
8
|
+
`Duration.default_to_s_precision=`.
|
9
|
+
- Default sleep function can be set using `Duration.sleep_function=`
|
10
|
+
- `Duration::ZERO` and `Duration.zero` for an easy, memory-efficient
|
11
|
+
zero-duration singleton.
|
12
|
+
- `Instant.clock_id` and `Instant.clock_id=` to control the default clock
|
13
|
+
source.
|
14
|
+
- `Instant.clock_getres` to get the minimum supported `Duration` from the
|
15
|
+
selected clock source.
|
16
|
+
- `Instant.monotonic_function=` to completely replace the default monotonic
|
17
|
+
function.
|
7
18
|
|
8
19
|
### Changed
|
9
|
-
|
10
|
-
|
11
|
-
|
20
|
+
|
21
|
+
- The default clock source is now chosen from a selection of options instead of
|
22
|
+
defaulting to `CLOCK_MONOTONIC``. Where possible options are used which are
|
23
|
+
unaffected by NTP frequency skew and which do not count time in system suspend.
|
24
|
+
- CI matrix drops Ruby 2.5 and 2.6 and adds 3.1, 3.2, head branches of Ruby,
|
25
|
+
JRuby, and TruffleRuby, and also tests under macOS.
|
26
|
+
|
27
|
+
### Fixed
|
28
|
+
|
29
|
+
- CI on TruffleRuby has been fixed by disabling SimpleCov.
|
30
|
+
- Several fragile tests depending on relatively narrow sleep times have been fixed.
|
31
|
+
|
32
|
+
### Thanks
|
33
|
+
|
34
|
+
- [@petergoldstein] for fixing CI on TruffleRuby and adding 3.1 and 3.2.
|
35
|
+
- [@fig] for fixing a README error.
|
36
|
+
|
37
|
+
## [0.7.1] - 2021-10-22
|
38
|
+
|
39
|
+
### Added
|
40
|
+
|
41
|
+
- `simplecov` introduced to test suite.
|
42
|
+
- `monotime/include.rb` to auto-include types globally.
|
43
|
+
|
44
|
+
### Changed
|
45
|
+
|
46
|
+
- All `Instant` and `Duration` instances are now frozen.
|
47
|
+
- Migrate from Travis CI to Github Actions
|
48
|
+
- Update development dependency on `rake`.
|
12
49
|
|
13
50
|
## [0.7.0] - 2019-04-24
|
51
|
+
|
14
52
|
### Added
|
15
|
-
|
16
|
-
|
53
|
+
|
54
|
+
- `Duration.with_measure`, which yields and returns an array containing its
|
55
|
+
evaluated return value and its `Duration`.
|
17
56
|
|
18
57
|
### Changed
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
58
|
+
|
59
|
+
- Break `Duration` and `Instant` into their own files.
|
60
|
+
- Rename `Monotime::VERSION` to `Monotime::MONOTIME_VERSION` to reduce
|
61
|
+
potential for collision if the module is included.
|
62
|
+
- Update to bundler 2.0.
|
63
|
+
- Rework README.md. Includes fix for [issue #1] (added a "See Also" section).
|
24
64
|
|
25
65
|
## [0.6.1] - 2018-10-26
|
66
|
+
|
26
67
|
### Fixed
|
27
|
-
|
28
|
-
|
68
|
+
|
69
|
+
- Build gem from a clean git checkout, not my local development directory.
|
70
|
+
No functional changes.
|
29
71
|
|
30
72
|
## [0.6.0] - 2018-10-26
|
73
|
+
|
31
74
|
### Added
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
75
|
+
|
76
|
+
- This `CHANGELOG.md` by request of [@celsworth].
|
77
|
+
- Aliases for `Duration.from_*` and `Duration#to_*` without the prefix. e.g.
|
78
|
+
`Duration.from_secs(42).to_secs == 42` can now be written as
|
79
|
+
`Duration.secs(42).secs == 42`.
|
80
|
+
- `Duration#nonzero?`.
|
81
|
+
- `Instant#in_past?` and `Instant#in_future?`.
|
38
82
|
|
39
83
|
## [0.5.0] - 2018-10-13
|
84
|
+
|
40
85
|
### Added
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
86
|
+
|
87
|
+
- `Duration#abs` to make a `Duration` positive.
|
88
|
+
- `Duration#-@` to invert the sign of a `Duration`.
|
89
|
+
- `Duration#positive?`
|
90
|
+
- `Duration#negative?`
|
91
|
+
- `Duration#zero?`
|
46
92
|
|
47
93
|
### Changed
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
94
|
+
|
95
|
+
- `Instant#sleep` with no argument now sleeps until the `Instant`.
|
96
|
+
- `Duration.from_*` no longer coerce their argument to `Float`.
|
97
|
+
- `Duration#==` checks value via `#to_nanos`, not type.
|
98
|
+
- `Duration#eql?` checks value and type.
|
99
|
+
- `Duration#<=>` compares value via `#to_nanos`.
|
53
100
|
|
54
101
|
## [0.4.0] - 2018-10-09
|
102
|
+
|
55
103
|
### Added
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
104
|
+
|
105
|
+
- `Instant#sleep` - sleep to a given `Duration` past an `Instant`.
|
106
|
+
- `Instant#sleep_secs` and `Instant#sleep_millis` convenience methods.
|
107
|
+
- `Duration#sleep` - sleep for the `Duration`.
|
108
|
+
- `Duration#*` - multiply a `Duration` by a number.
|
109
|
+
- `Duration#/` - divide a `Duration` by a number.
|
61
110
|
|
62
111
|
### Changed
|
63
|
-
|
112
|
+
|
113
|
+
More `#to_nanos` `Duration` duck-typing.
|
64
114
|
|
65
115
|
## [0.3.0] - 2018-10-04
|
116
|
+
|
66
117
|
### Added
|
67
|
-
|
118
|
+
|
119
|
+
- `#to_nanos` is now used to duck-type `Duration` everywhere.
|
68
120
|
|
69
121
|
### Changed
|
70
|
-
|
122
|
+
|
123
|
+
- Make `<=>` return nil on invalid types, rather than raising a `TypeError`.
|
71
124
|
|
72
125
|
### Removed
|
73
|
-
|
126
|
+
|
127
|
+
- Dependency on `dry-equalizer`.
|
74
128
|
|
75
129
|
## [0.2.0] - 2018-10-03
|
130
|
+
|
76
131
|
### Added
|
77
|
-
|
78
|
-
|
132
|
+
|
133
|
+
- `Instant#to_s` as an alias for `#elapsed.to_s`
|
134
|
+
- `Duration#to_nanos`, with some limited duck-typing.
|
79
135
|
|
80
136
|
### Changed
|
81
|
-
|
82
|
-
|
83
|
-
|
137
|
+
|
138
|
+
- Switch to microseconds internally.
|
139
|
+
- `Duration#to_{secs,millis,micros}` now return a `Float`.
|
140
|
+
- `Instant#ns` is now `protected`.
|
84
141
|
|
85
142
|
### Fixed
|
86
|
-
|
87
|
-
|
88
|
-
|
143
|
+
|
144
|
+
- `Duration#to_s` zero-stripping with precision=0.
|
145
|
+
- `Instant#-` argument ordering with other `Instant`.
|
146
|
+
- `Duration#to_micros` returns microseconds, not picoseconds.
|
89
147
|
|
90
148
|
### Removed
|
91
|
-
|
92
|
-
|
149
|
+
|
150
|
+
- `Instant` and `Duration` maths methods no longer support passing an `Integer`
|
151
|
+
number of nanoseconds.
|
93
152
|
|
94
153
|
## [0.1.0] - 2018-10-02
|
154
|
+
|
95
155
|
### Added
|
96
|
-
- Initial release
|
97
156
|
|
157
|
+
- Initial release
|
98
158
|
|
99
159
|
[0.1.0]: https://github.com/Freaky/monotime/commits/v0.1.0
|
100
160
|
[0.2.0]: https://github.com/Freaky/monotime/commits/v0.2.0
|
@@ -104,5 +164,9 @@
|
|
104
164
|
[0.6.0]: https://github.com/Freaky/monotime/commits/v0.6.0
|
105
165
|
[0.6.1]: https://github.com/Freaky/monotime/commits/v0.6.1
|
106
166
|
[0.7.0]: https://github.com/Freaky/monotime/commits/v0.7.0
|
167
|
+
[0.7.1]: https://github.com/Freaky/monotime/commits/v0.7.0
|
168
|
+
[0.8.0]: https://github.com/Freaky/monotime/commits/v0.7.0
|
107
169
|
[issue #1]: https://github.com/Freaky/monotime/issues/1
|
108
170
|
[@celsworth]: https://github.com/celsworth
|
171
|
+
[@petergoldstein]: https://github.com/petergoldstein
|
172
|
+
[@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.
|
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
|
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
|
-
|
175
|
-
|
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
|
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`.
|
data/lib/monotime/duration.rb
CHANGED
@@ -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
|
11
|
+
# Users are strongly advised to use +Duration.from_nanos+ instead.
|
12
12
|
#
|
13
13
|
# @param nanos [Integer]
|
14
|
-
# @see
|
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
|
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
|
-
|
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
|
-
|
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
|
|
data/lib/monotime/instant.rb
CHANGED
@@ -11,13 +11,106 @@ module Monotime
|
|
11
11
|
|
12
12
|
include Comparable
|
13
13
|
|
14
|
+
class << self
|
15
|
+
attr_writer :clock_id
|
16
|
+
|
17
|
+
# The symbolic name of the automatically-selected +Process.clock_gettime+
|
18
|
+
# clock id, if available. This will *not* reflect a manually-set +clock_id+.
|
19
|
+
#
|
20
|
+
# @return [Symbol, nil]
|
21
|
+
attr_reader :clock_name
|
22
|
+
|
23
|
+
# The function used to create +Instant+ instances.
|
24
|
+
#
|
25
|
+
# This function must return a +Numeric+, monotonic count of nanoseconds
|
26
|
+
# since a fixed point in the past.
|
27
|
+
#
|
28
|
+
# Defaults to `lambda { Process.clock_gettime(clock_id, :nanosecond) }`.
|
29
|
+
#
|
30
|
+
# @overload monotonic_function=(function)
|
31
|
+
# @param function [#call]
|
32
|
+
attr_accessor :monotonic_function
|
33
|
+
|
34
|
+
# @overload clock_id
|
35
|
+
# The configured or detected +Process.clock_getime+ clock identifier.
|
36
|
+
#
|
37
|
+
# Raises +NotImplementedError+ if a suitable monotonic clock source cannot
|
38
|
+
# be found and one has not been specified manually.
|
39
|
+
#
|
40
|
+
# @return [Numeric]
|
41
|
+
#
|
42
|
+
# @overload clock_id=(id)
|
43
|
+
# The +Process.clock_gettime+ clock id used to create +Instant+ instances
|
44
|
+
# by the default monotonic function.
|
45
|
+
#
|
46
|
+
# Suggested options include but are not limited to:
|
47
|
+
#
|
48
|
+
# * +Process::CLOCK_MONOTONIC_RAW+
|
49
|
+
# * +Process::CLOCK_UPTIME_RAW+
|
50
|
+
# * +Process::CLOCK_UPTIME_PRECISE+
|
51
|
+
# * +Process::CLOCK_UPTIME_FAST+
|
52
|
+
# * +Process::CLOCK_UPTIME+
|
53
|
+
# * +Process::CLOCK_MONOTONIC_PRECISE+
|
54
|
+
# * +Process::CLOCK_MONOTONIC_FAST+
|
55
|
+
# * +Process::CLOCK_MONOTONIC+
|
56
|
+
#
|
57
|
+
# These are platform-dependant and may vary in resolution, performance,
|
58
|
+
# and behaviour from NTP frequency skew and system suspend/resume.
|
59
|
+
#
|
60
|
+
# It is possible to set non-monotonic clock sources here. You probably
|
61
|
+
# shouldn't.
|
62
|
+
#
|
63
|
+
# Defaults to auto-detect.
|
64
|
+
#
|
65
|
+
# @param id [Numeric]
|
66
|
+
def clock_id
|
67
|
+
@clock_id ||= detect_clock_id
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return the claimed resolution of the given clock id or the configured
|
71
|
+
# +clock_id+, as a +Duration+, or +nil+ if invalid.
|
72
|
+
#
|
73
|
+
# @param clock [Numeric] Optional clock id instead of default.
|
74
|
+
def clock_getres(clock = @clock_id)
|
75
|
+
Duration.from_nanos(Process.clock_getres(clock, :nanosecond))
|
76
|
+
rescue SystemCallError
|
77
|
+
# suppress errors
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def detect_clock_id
|
83
|
+
name, id, =
|
84
|
+
[
|
85
|
+
:CLOCK_MONOTONIC_RAW, # Linux, not affected by NTP frequency adjustments
|
86
|
+
:CLOCK_UPTIME_RAW, # macOS, not affected by NTP frequency adjustments
|
87
|
+
:CLOCK_UPTIME_PRECISE, # FreeBSD, increments while system is running
|
88
|
+
:CLOCK_UPTIME, # OpenBSD, increments while system is running
|
89
|
+
:CLOCK_MONOTONIC_PRECISE, # FreeBSD, precise monotonic clock
|
90
|
+
:CLOCK_MONOTONIC, # Standard cross-platform monotonic clock
|
91
|
+
]
|
92
|
+
.each_with_index # Used to force a stable sort in min_by
|
93
|
+
.filter { |name, _| Process.const_defined?(name) }
|
94
|
+
.map { |name, index| [name, Process.const_get(name), index] }
|
95
|
+
.filter_map { |clock| clock.insert(2, clock_getres(clock[1])) }
|
96
|
+
.min_by { |clock| clock[2..] } # find smallest resolution and index
|
97
|
+
.tap { |clock| raise NotImplementedError, 'No usable clock' unless clock }
|
98
|
+
|
99
|
+
@clock_name = name
|
100
|
+
id
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
self.monotonic_function = -> { Process.clock_gettime(clock_id, :nanosecond) }
|
105
|
+
clock_id # detect our clock_id early
|
106
|
+
|
14
107
|
# Create a new +Instant+ from an optional nanosecond measurement.
|
15
108
|
#
|
16
109
|
# Users should generally *not* pass anything to this function.
|
17
110
|
#
|
18
111
|
# @param nanos [Integer]
|
19
112
|
# @see #now
|
20
|
-
def initialize(nanos =
|
113
|
+
def initialize(nanos = self.class.monotonic_function.call)
|
21
114
|
@ns = Integer(nanos)
|
22
115
|
freeze
|
23
116
|
end
|
@@ -112,8 +205,8 @@ module Monotime
|
|
112
205
|
# Sugar for +#elapsed.to_s+.
|
113
206
|
#
|
114
207
|
# @see Duration#to_s
|
115
|
-
def to_s(
|
116
|
-
elapsed.to_s(
|
208
|
+
def to_s(...)
|
209
|
+
elapsed.to_s(...)
|
117
210
|
end
|
118
211
|
|
119
212
|
# Add a +Duration+ or +#to_nanos+-coercible object to this +Instant+, returning
|
@@ -173,7 +266,7 @@ module Monotime
|
|
173
266
|
#
|
174
267
|
# @return [Integer]
|
175
268
|
def hash
|
176
|
-
self.class
|
269
|
+
[self.class, @ns].hash
|
177
270
|
end
|
178
271
|
end
|
179
272
|
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.8.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:
|
11
|
+
date: 2023-09-17 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.
|
112
|
+
rubygems_version: 3.4.19
|
113
113
|
signing_key:
|
114
114
|
specification_version: 4
|
115
115
|
summary: A sensible interface to the monotonic clock
|