monotime 0.1.0 → 0.2.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 +2 -0
- data/README.md +1 -1
- data/bin/console +4 -4
- data/lib/monotime/version.rb +1 -1
- data/lib/monotime.rb +74 -54
- metadata +2 -2
- data/Gemfile.lock +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a97344679471a970a324027b84b560faf9dfc9597c0937094de1486cc0da602
|
4
|
+
data.tar.gz: 35d55277a3181f0033939263122296b3a5328c5cc1605722644dd21aa9305ac1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29d7c0fb1aa092127f1a1a3036552466d9f6ea83d337fa3c9ffda0e88d3b5fb4ca996f81c828701a2a1bee4bf44d8c6392395298ac9f257034b3b71b8d0437b3
|
7
|
+
data.tar.gz: bd3bef852b6d5b25810091e0ee7452e60e03a5cd25cc5577e25760452804d3d201cfc05efd2dcf19d91680ff6bdacbd93b9428473def942ac3c024aea4675c9d
|
data/.rubocop.yml
ADDED
data/README.md
CHANGED
@@ -71,7 +71,7 @@ And how to do basic maths on itself:
|
|
71
71
|
(Instant.now - Duration.from_secs(1)).elapsed.to_s # => "1.000014627s"
|
72
72
|
|
73
73
|
# Instant - Instant => Duration
|
74
|
-
(Instant.now - Instant.now).to_s # => "
|
74
|
+
(Instant.now - Instant.now).to_s # => "-5.585μs"
|
75
75
|
```
|
76
76
|
|
77
77
|
`Duration` and `Instant` are also `Comparable` with other instances of their
|
data/bin/console
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'monotime'
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
8
8
|
|
9
9
|
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require
|
10
|
+
# require 'pry'
|
11
11
|
# Pry.start
|
12
12
|
|
13
|
-
require
|
13
|
+
require 'irb'
|
14
14
|
IRB.start(__FILE__)
|
data/lib/monotime/version.rb
CHANGED
data/lib/monotime.rb
CHANGED
@@ -5,147 +5,167 @@ require 'monotime/version'
|
|
5
5
|
require 'dry-equalizer'
|
6
6
|
|
7
7
|
module Monotime
|
8
|
+
# A measurement from the operating system's monotonic clock, with up to
|
9
|
+
# nanosecond precision.
|
8
10
|
class Instant
|
9
|
-
|
11
|
+
# A measurement, in nanoseconds. Should be considered opaque and
|
12
|
+
# non-portable outside the process that created it.
|
13
|
+
protected def ns() @ns end
|
10
14
|
|
11
15
|
include Dry::Equalizer(:ns)
|
12
16
|
include Comparable
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
# Create a new +Instant+ from a given nanosecond measurement, defaulting to
|
19
|
+
# that given by +Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond))+.
|
20
|
+
#
|
21
|
+
# Users should generally *not* pass anything to this function.
|
22
|
+
def initialize(nanos = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond))
|
23
|
+
@ns = Integer(nanos)
|
18
24
|
end
|
19
25
|
|
26
|
+
# An alias to +new+, and generally preferred over it.
|
20
27
|
def self.now
|
21
28
|
new
|
22
29
|
end
|
23
30
|
|
31
|
+
# Return a +Duration+ between this +Instant+ and another.
|
24
32
|
def duration_since(earlier)
|
25
33
|
case earlier
|
26
|
-
when Instant then
|
34
|
+
when Instant then earlier - self
|
27
35
|
else raise TypeError, 'Not an Instant'
|
28
36
|
end
|
29
37
|
end
|
30
38
|
|
39
|
+
# Return a +Duration+ since this +Instant+ and now.
|
31
40
|
def elapsed
|
32
41
|
duration_since(self.class.now)
|
33
42
|
end
|
34
43
|
|
44
|
+
# Sugar for +elapsed.to_s+.
|
45
|
+
def to_s(*args)
|
46
|
+
elapsed.to_s(*args)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Add a +Duration+ to this +Instant+, returning a new +Instant+.
|
35
50
|
def +(other)
|
36
51
|
case other
|
37
|
-
when Duration then Instant.new(
|
38
|
-
|
39
|
-
else raise TypeError, 'Not a Duration or Integer'
|
52
|
+
when Duration then Instant.new(@ns + other.to_nanos)
|
53
|
+
else raise TypeError, 'Not a Duration'
|
40
54
|
end
|
41
55
|
end
|
42
56
|
|
57
|
+
# Subtract another +Instant+ to generate a +Duration+ between the two,
|
58
|
+
# or a +Duration+, to generate an +Instant+ offset by it.
|
43
59
|
def -(other)
|
44
60
|
case other
|
45
|
-
when Instant then Duration.new(
|
46
|
-
when Duration then Instant.new(
|
47
|
-
|
48
|
-
else raise TypeError, 'Not an Instant, Duration or Integer'
|
61
|
+
when Instant then Duration.new(@ns - other.ns)
|
62
|
+
when Duration then Instant.new(@ns - other.to_nanos)
|
63
|
+
else raise TypeError, 'Not an Instant or Duration'
|
49
64
|
end
|
50
65
|
end
|
51
66
|
|
67
|
+
# Compare this +Instant+ with another.
|
52
68
|
def <=>(other)
|
53
69
|
case other
|
54
|
-
when
|
55
|
-
else raise TypeError, 'Not
|
70
|
+
when Instant then @ns <=> other.ns
|
71
|
+
else raise TypeError, 'Not an Instant'
|
56
72
|
end
|
57
73
|
end
|
58
74
|
end
|
59
75
|
|
76
|
+
# A type representing a span of time in nanoseconds.
|
60
77
|
class Duration
|
61
|
-
|
62
|
-
|
63
|
-
include Dry::Equalizer(:ns)
|
78
|
+
include Dry::Equalizer(:to_nanos)
|
64
79
|
include Comparable
|
65
80
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
@ns =
|
81
|
+
# Create a new +Duration+ of a specified number of nanoseconds, zero by
|
82
|
+
# default.
|
83
|
+
def initialize(nanos = 0)
|
84
|
+
@ns = Integer(nanos)
|
70
85
|
end
|
71
86
|
|
72
87
|
class << self
|
88
|
+
# Generate a new +Duration+ measuring the given number of seconds.
|
73
89
|
def from_secs(secs)
|
74
90
|
new(Integer(Float(secs) * 1_000_000_000))
|
75
91
|
end
|
76
92
|
|
93
|
+
# Generate a new +Duration+ measuring the given number of milliseconds.
|
77
94
|
def from_millis(millis)
|
78
95
|
new(Integer(Float(millis) * 1_000_000))
|
79
96
|
end
|
80
97
|
|
98
|
+
# Generate a new +Duration+ measuring the given number of microseconds.
|
81
99
|
def from_micros(micros)
|
82
100
|
new(Integer(Float(micros) * 1_000))
|
83
101
|
end
|
84
102
|
|
103
|
+
# Generate a new +Duration+ measuring the given number of nanoseconds.
|
85
104
|
def from_nanos(nanos)
|
86
105
|
new(Integer(nanos))
|
87
106
|
end
|
88
107
|
|
108
|
+
# Return a +Duration+ measuring the elapsed time of the yielded block.
|
89
109
|
def measure
|
90
110
|
Instant.now.tap { yield }.elapsed
|
91
111
|
end
|
92
112
|
end
|
93
113
|
|
114
|
+
# Add another +Duration+ to this one, returning a new +Duration+.
|
94
115
|
def +(other)
|
95
|
-
|
96
|
-
when Duration then Duration.new(self.ns + other.ns)
|
97
|
-
when Numeric then Duration.new(self.ns + other)
|
98
|
-
else raise TypeError, 'Not a Duration or Numeric'
|
99
|
-
end
|
116
|
+
Duration.new(to_nanos + other.to_nanos)
|
100
117
|
end
|
101
118
|
|
119
|
+
# Subtract another +Duration+ from this one, returning a new +Duration+.
|
102
120
|
def -(other)
|
103
|
-
|
104
|
-
when Duration then Duration.new(self.ns - other.ns)
|
105
|
-
when Numeric then Duration.new(self.ns - other)
|
106
|
-
else raise TypeError, 'Not a Duration or Numeric'
|
107
|
-
end
|
121
|
+
Duration.new(to_nanos - other.to_nanos)
|
108
122
|
end
|
109
123
|
|
124
|
+
# Compare this +Duration+ with another.
|
110
125
|
def <=>(other)
|
111
|
-
|
112
|
-
when self.class then self.ns <=> other.ns
|
113
|
-
else raise TypeError, "Not a #{self.class}"
|
114
|
-
end
|
126
|
+
to_nanos <=> other.to_nanos
|
115
127
|
end
|
116
128
|
|
129
|
+
# Return this +Duration+ in seconds.
|
117
130
|
def to_secs
|
118
|
-
|
131
|
+
to_nanos / 1_000_000_000.0
|
119
132
|
end
|
120
133
|
|
134
|
+
# Return this +Duration+ in milliseconds.
|
121
135
|
def to_millis
|
122
|
-
|
136
|
+
to_nanos / 1_000_000.0
|
123
137
|
end
|
124
138
|
|
139
|
+
# Return this +Duration+ in microseconds.
|
125
140
|
def to_micros
|
126
|
-
|
141
|
+
to_nanos / 1_000.0
|
127
142
|
end
|
128
143
|
|
144
|
+
# Return this +Duration+ in nanoseconds.
|
129
145
|
def to_nanos
|
130
146
|
@ns
|
131
147
|
end
|
132
148
|
|
149
|
+
DIVISORS = [
|
150
|
+
[1_000_000_000.0, 's'],
|
151
|
+
[1_000_000.0, 'ms'],
|
152
|
+
[1_000.0, 'μs'],
|
153
|
+
[0, 'ns']
|
154
|
+
].map(&:freeze).freeze
|
155
|
+
|
156
|
+
# Format this +Duration+ into a human-readable string, with a given number
|
157
|
+
# of decimal places.
|
158
|
+
#
|
159
|
+
# The exact format is subject to change, users with specific requirements
|
160
|
+
# are encouraged to use their own formatting methods.
|
133
161
|
def to_s(precision = 9)
|
134
|
-
|
135
|
-
ns =
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
elsif ns >= 1_000
|
142
|
-
postfix = 'μs'
|
143
|
-
ns / 1_000.0
|
144
|
-
else
|
145
|
-
postfix = 'ns'
|
146
|
-
ns
|
147
|
-
end
|
148
|
-
num.sub(/\.?0*$/, '') << postfix
|
162
|
+
precision = Integer(precision).abs
|
163
|
+
ns = to_nanos.abs
|
164
|
+
div, unit = DIVISORS.find { |d, _| ns >= d }
|
165
|
+
ns /= div if div.nonzero?
|
166
|
+
num = format("#{'-' if to_nanos.negative?}%.#{precision}f", ns)
|
167
|
+
num.sub!(/\.?0*$/, '') if precision.nonzero?
|
168
|
+
num << unit
|
149
169
|
end
|
150
170
|
end
|
151
171
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: monotime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Hurst
|
@@ -74,9 +74,9 @@ extensions: []
|
|
74
74
|
extra_rdoc_files: []
|
75
75
|
files:
|
76
76
|
- ".gitignore"
|
77
|
+
- ".rubocop.yml"
|
77
78
|
- ".travis.yml"
|
78
79
|
- Gemfile
|
79
|
-
- Gemfile.lock
|
80
80
|
- LICENSE.txt
|
81
81
|
- README.md
|
82
82
|
- Rakefile
|
data/Gemfile.lock
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
monotime (0.1.0)
|
5
|
-
dry-equalizer
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
dry-equalizer (0.2.1)
|
11
|
-
minitest (5.11.3)
|
12
|
-
rake (10.5.0)
|
13
|
-
|
14
|
-
PLATFORMS
|
15
|
-
ruby
|
16
|
-
|
17
|
-
DEPENDENCIES
|
18
|
-
bundler (~> 1.16)
|
19
|
-
minitest (~> 5.0)
|
20
|
-
monotime!
|
21
|
-
rake (~> 10.0)
|
22
|
-
|
23
|
-
BUNDLED WITH
|
24
|
-
1.16.3
|