timers 4.3.2 → 4.3.3
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/lib/timers/events.rb +23 -51
- data/lib/timers/group.rb +21 -21
- data/lib/timers/priority_heap.rb +174 -0
- data/lib/timers/timer.rb +41 -39
- data/lib/timers/version.rb +1 -1
- data/lib/timers/wait.rb +8 -8
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9f471bfb9cac57f9462498ab12527eded7533318cec13604a10d32b159c6689
|
4
|
+
data.tar.gz: 69802b0774101037596274f2acf114c3f4234875ed8a82146e8ef1075407bf6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f15934803658ec4b1d0d7b4a8ea92c9a21e2267544ec11c9619604288264c7f0add19dd12b71a0680827d6d37b853192d98266f29b06ef27cb36e53408f8c67b
|
7
|
+
data.tar.gz: a50a935d7b73681b4b751341c6eda0143c64beb9d469641ea68b8481cd1c36bd16ad21f7ec274f06d1389b53c5849e06b20182d3faea6497f64773d8fba2dae6
|
data/lib/timers/events.rb
CHANGED
@@ -21,57 +21,52 @@
|
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
23
|
require_relative "timer"
|
24
|
+
require_relative "priority_heap"
|
24
25
|
|
25
26
|
module Timers
|
26
|
-
# Maintains
|
27
|
+
# Maintains a PriorityHeap of events ordered on time, which can be cancelled.
|
27
28
|
class Events
|
28
29
|
# Represents a cancellable handle for a specific timer event.
|
29
30
|
class Handle
|
31
|
+
include Comparable
|
32
|
+
|
30
33
|
def initialize(time, callback)
|
31
34
|
@time = time
|
32
35
|
@callback = callback
|
33
36
|
end
|
34
|
-
|
37
|
+
|
35
38
|
# The absolute time that the handle should be fired at.
|
36
39
|
attr_reader :time
|
37
|
-
|
40
|
+
|
38
41
|
# Cancel this timer, O(1).
|
39
42
|
def cancel!
|
40
43
|
# The simplest way to keep track of cancelled status is to nullify the
|
41
44
|
# callback. This should also be optimal for garbage collection.
|
42
45
|
@callback = nil
|
43
46
|
end
|
44
|
-
|
47
|
+
|
45
48
|
# Has this timer been cancelled? Cancelled timer's don't fire.
|
46
49
|
def cancelled?
|
47
50
|
@callback.nil?
|
48
51
|
end
|
49
|
-
|
50
|
-
def
|
51
|
-
@time
|
52
|
-
end
|
53
|
-
|
54
|
-
def >= other
|
55
|
-
@time >= other.to_f
|
56
|
-
end
|
57
|
-
|
58
|
-
def to_f
|
59
|
-
@time
|
52
|
+
|
53
|
+
def <=> other
|
54
|
+
@time <=> other.time
|
60
55
|
end
|
61
|
-
|
56
|
+
|
62
57
|
# Fire the callback if not cancelled with the given time parameter.
|
63
58
|
def fire(time)
|
64
59
|
@callback.call(time) if @callback
|
65
60
|
end
|
66
61
|
end
|
67
|
-
|
62
|
+
|
68
63
|
def initialize
|
69
64
|
# A sequence of handles, maintained in sorted order, future to present.
|
70
65
|
# @sequence.last is the next event to be fired.
|
71
|
-
@sequence =
|
66
|
+
@sequence = PriorityHeap.new
|
72
67
|
@queue = []
|
73
68
|
end
|
74
|
-
|
69
|
+
|
75
70
|
# Add an event at the given time.
|
76
71
|
def schedule(time, callback)
|
77
72
|
handle = Handle.new(time.to_f, callback)
|
@@ -80,64 +75,41 @@ module Timers
|
|
80
75
|
|
81
76
|
return handle
|
82
77
|
end
|
83
|
-
|
78
|
+
|
84
79
|
# Returns the first non-cancelled handle.
|
85
80
|
def first
|
86
81
|
merge!
|
87
82
|
|
88
|
-
while (handle = @sequence.
|
83
|
+
while (handle = @sequence.peek)
|
89
84
|
return handle unless handle.cancelled?
|
90
85
|
@sequence.pop
|
91
86
|
end
|
92
87
|
end
|
93
|
-
|
88
|
+
|
94
89
|
# Returns the number of pending (possibly cancelled) events.
|
95
90
|
def size
|
96
91
|
@sequence.size + @queue.size
|
97
92
|
end
|
98
|
-
|
93
|
+
|
99
94
|
# Fire all handles for which Handle#time is less than the given time.
|
100
95
|
def fire(time)
|
101
96
|
merge!
|
102
97
|
|
103
|
-
while handle = @sequence.
|
98
|
+
while handle = @sequence.peek and handle.time <= time
|
104
99
|
@sequence.pop
|
105
100
|
handle.fire(time)
|
106
101
|
end
|
107
102
|
end
|
108
|
-
|
103
|
+
|
109
104
|
private
|
110
|
-
|
105
|
+
|
106
|
+
# Move all non-cancelled timers from the pending queue to the priority heap
|
111
107
|
def merge!
|
112
108
|
while handle = @queue.pop
|
113
109
|
next if handle.cancelled?
|
114
110
|
|
115
|
-
|
116
|
-
|
117
|
-
if current_handle = @sequence[index] and current_handle.cancelled?
|
118
|
-
# puts "Replacing handle at index: #{index} due to cancellation in array containing #{@sequence.size} item(s)."
|
119
|
-
@sequence[index] = handle
|
120
|
-
else
|
121
|
-
# puts "Inserting handle at index: #{index} in array containing #{@sequence.size} item(s)."
|
122
|
-
@sequence.insert(index, handle)
|
123
|
-
end
|
111
|
+
@sequence.push(handle)
|
124
112
|
end
|
125
113
|
end
|
126
|
-
|
127
|
-
# Return the right-most index where to insert item e, in a list a, assuming
|
128
|
-
# a is sorted in descending order.
|
129
|
-
def bisect_right(a, e, l = 0, u = a.length)
|
130
|
-
while l < u
|
131
|
-
m = l + (u - l).div(2)
|
132
|
-
|
133
|
-
if a[m] >= e
|
134
|
-
l = m + 1
|
135
|
-
else
|
136
|
-
u = m
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
l
|
141
|
-
end
|
142
114
|
end
|
143
115
|
end
|
data/lib/timers/group.rb
CHANGED
@@ -31,62 +31,62 @@ module Timers
|
|
31
31
|
# A collection of timers which may fire at different times
|
32
32
|
class Group
|
33
33
|
include Enumerable
|
34
|
-
|
34
|
+
|
35
35
|
extend Forwardable
|
36
36
|
def_delegators :@timers, :each, :empty?
|
37
|
-
|
37
|
+
|
38
38
|
def initialize
|
39
39
|
@events = Events.new
|
40
|
-
|
40
|
+
|
41
41
|
@timers = Set.new
|
42
42
|
@paused_timers = Set.new
|
43
|
-
|
43
|
+
|
44
44
|
@interval = Interval.new
|
45
45
|
@interval.start
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
# Scheduled events:
|
49
49
|
attr_reader :events
|
50
|
-
|
50
|
+
|
51
51
|
# Active timers:
|
52
52
|
attr_reader :timers
|
53
|
-
|
53
|
+
|
54
54
|
# Paused timers:
|
55
55
|
attr_reader :paused_timers
|
56
|
-
|
56
|
+
|
57
57
|
# Call the given block after the given interval. The first argument will be
|
58
58
|
# the time at which the group was asked to fire timers for.
|
59
59
|
def after(interval, &block)
|
60
60
|
Timer.new(self, interval, false, &block)
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
# Call the given block immediately, and then after the given interval. The first
|
64
64
|
# argument will be the time at which the group was asked to fire timers for.
|
65
65
|
def now_and_after(interval, &block)
|
66
66
|
yield
|
67
67
|
after(interval, &block)
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
# Call the given block periodically at the given interval. The first
|
71
71
|
# argument will be the time at which the group was asked to fire timers for.
|
72
72
|
def every(interval, recur = true, &block)
|
73
73
|
Timer.new(self, interval, recur, &block)
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
# Call the given block immediately, and then periodically at the given interval. The first
|
77
77
|
# argument will be the time at which the group was asked to fire timers for.
|
78
78
|
def now_and_every(interval, recur = true, &block)
|
79
79
|
yield
|
80
80
|
every(interval, recur, &block)
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
# Wait for the next timer and fire it. Can take a block, which should behave
|
84
84
|
# like sleep(n), except that n may be nil (sleep forever) or a negative
|
85
85
|
# number (fire immediately after return).
|
86
86
|
def wait
|
87
87
|
if block_given?
|
88
88
|
yield wait_interval
|
89
|
-
|
89
|
+
|
90
90
|
while (interval = wait_interval) && interval > 0
|
91
91
|
yield interval
|
92
92
|
end
|
@@ -99,7 +99,7 @@ module Timers
|
|
99
99
|
|
100
100
|
fire
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
# Interval to wait until when the next timer will fire.
|
104
104
|
# - nil: no timers
|
105
105
|
# - -ve: timers expired already
|
@@ -109,36 +109,36 @@ module Timers
|
|
109
109
|
handle = @events.first
|
110
110
|
handle.time - Float(offset) if handle
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
# Fire all timers that are ready.
|
114
114
|
def fire(offset = current_offset)
|
115
115
|
@events.fire(offset)
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
118
|
# Pause all timers.
|
119
119
|
def pause
|
120
120
|
@timers.dup.each(&:pause)
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
# Resume all timers.
|
124
124
|
def resume
|
125
125
|
@paused_timers.dup.each(&:resume)
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
alias continue resume
|
129
|
-
|
129
|
+
|
130
130
|
# Delay all timers.
|
131
131
|
def delay(seconds)
|
132
132
|
@timers.each do |timer|
|
133
133
|
timer.delay(seconds)
|
134
134
|
end
|
135
135
|
end
|
136
|
-
|
136
|
+
|
137
137
|
# Cancel all timers.
|
138
138
|
def cancel
|
139
139
|
@timers.dup.each(&:cancel)
|
140
140
|
end
|
141
|
-
|
141
|
+
|
142
142
|
# The group's current time.
|
143
143
|
def current_offset
|
144
144
|
@interval.to_f
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright, 2021, by Wander Hillen.
|
4
|
+
# Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
11
|
+
# furnished to do so, subject to the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
14
|
+
# all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
# THE SOFTWARE.
|
23
|
+
|
24
|
+
module Timers
|
25
|
+
# A priority queue implementation using a standard binary minheap. It uses straight comparison
|
26
|
+
# of its contents to determine priority. This works because a Handle from Timers::Events implements
|
27
|
+
# the '<' operation by comparing the expiry time.
|
28
|
+
# See <https://en.wikipedia.org/wiki/Binary_heap> for explanations of the main methods.
|
29
|
+
class PriorityHeap
|
30
|
+
def initialize
|
31
|
+
# The heap is represented with an array containing a binary tree. See
|
32
|
+
# https://en.wikipedia.org/wiki/Binary_heap#Heap_implementation for how this array
|
33
|
+
# is built up.
|
34
|
+
@contents = []
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the earliest timer or nil if the heap is empty.
|
38
|
+
def peek
|
39
|
+
@contents[0]
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the number of elements in the heap
|
43
|
+
def size
|
44
|
+
@contents.size
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the earliest timer if the heap is non-empty and removes it from the heap.
|
48
|
+
# Returns nil if the heap is empty. (and doesn't change the heap in that case)
|
49
|
+
def pop
|
50
|
+
# If the heap is empty:
|
51
|
+
if @contents.empty?
|
52
|
+
return nil
|
53
|
+
end
|
54
|
+
|
55
|
+
# If we have only one item, no swapping is required:
|
56
|
+
if @contents.size == 1
|
57
|
+
return @contents.pop
|
58
|
+
end
|
59
|
+
|
60
|
+
# Take the root of the tree:
|
61
|
+
value = @contents[0]
|
62
|
+
|
63
|
+
# Remove the last item in the tree:
|
64
|
+
last = @contents.pop
|
65
|
+
|
66
|
+
# Overwrite the root of the tree with the item:
|
67
|
+
@contents[0] = last
|
68
|
+
|
69
|
+
# Bubble it down into place:
|
70
|
+
bubble_down(0)
|
71
|
+
|
72
|
+
# validate!
|
73
|
+
|
74
|
+
return value
|
75
|
+
end
|
76
|
+
|
77
|
+
# Inserts a new timer into the heap, then rearranges elements until the heap invariant is true again.
|
78
|
+
def push(element)
|
79
|
+
# Insert the item at the end of the heap:
|
80
|
+
@contents.push(element)
|
81
|
+
|
82
|
+
# Bubble it up into position:
|
83
|
+
bubble_up(@contents.size - 1)
|
84
|
+
|
85
|
+
# validate!
|
86
|
+
|
87
|
+
return self
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# Validate the heap invariant.
|
93
|
+
def validate!(index = 0)
|
94
|
+
if value = @contents[index]
|
95
|
+
left_index = index*2 + 1
|
96
|
+
if left_value = @contents[left_index]
|
97
|
+
unless value < left_value
|
98
|
+
raise "Invalid left index from #{index}!"
|
99
|
+
end
|
100
|
+
|
101
|
+
validate!(left_index)
|
102
|
+
end
|
103
|
+
|
104
|
+
right_index = left_index + 1
|
105
|
+
if right_value = @contents[right_index]
|
106
|
+
unless value < right_value
|
107
|
+
raise "Invalid right index from #{index}!"
|
108
|
+
end
|
109
|
+
|
110
|
+
validate!(right_index)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def swap(i, j)
|
116
|
+
@contents[i], @contents[j] = @contents[j], @contents[i]
|
117
|
+
end
|
118
|
+
|
119
|
+
def bubble_up(index)
|
120
|
+
parent_index = (index - 1) / 2 # watch out, integer division!
|
121
|
+
|
122
|
+
while index > 0 && @contents[index] < @contents[parent_index]
|
123
|
+
# if the node has a smaller value than its parent, swap these nodes
|
124
|
+
# to uphold the minheap invariant and update the index of the 'current'
|
125
|
+
# node. If the node is already at index 0, we can also stop because that
|
126
|
+
# is the root of the heap.
|
127
|
+
# swap(index, parent_index)
|
128
|
+
@contents[index], @contents[parent_index] = @contents[parent_index], @contents[index]
|
129
|
+
|
130
|
+
index = parent_index
|
131
|
+
parent_index = (index - 1) / 2 # watch out, integer division!
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def bubble_down(index)
|
136
|
+
swap_value = 0
|
137
|
+
swap_index = nil
|
138
|
+
|
139
|
+
while true
|
140
|
+
left_index = (2 * index) + 1
|
141
|
+
left_value = @contents[left_index]
|
142
|
+
|
143
|
+
if left_value.nil?
|
144
|
+
# This node has no children so it can't bubble down any further.
|
145
|
+
# We're done here!
|
146
|
+
return
|
147
|
+
end
|
148
|
+
|
149
|
+
# Determine which of the child nodes has the smallest value:
|
150
|
+
right_index = left_index + 1
|
151
|
+
right_value = @contents[right_index]
|
152
|
+
|
153
|
+
if right_value.nil? or right_value > left_value
|
154
|
+
swap_value = left_value
|
155
|
+
swap_index = left_index
|
156
|
+
else
|
157
|
+
swap_value = right_value
|
158
|
+
swap_index = right_index
|
159
|
+
end
|
160
|
+
|
161
|
+
if @contents[index] < swap_value
|
162
|
+
# No need to swap, the minheap invariant is already satisfied:
|
163
|
+
return
|
164
|
+
else
|
165
|
+
# At least one of the child node has a smaller value than the current node, swap current node with that child and update current node for if it might need to bubble down even further:
|
166
|
+
# swap(index, swap_index)
|
167
|
+
@contents[index], @contents[swap_index] = @contents[swap_index], @contents[index]
|
168
|
+
|
169
|
+
index = swap_index
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
data/lib/timers/timer.rb
CHANGED
@@ -29,66 +29,66 @@ module Timers
|
|
29
29
|
class Timer
|
30
30
|
include Comparable
|
31
31
|
attr_reader :interval, :offset, :recurring
|
32
|
-
|
32
|
+
|
33
33
|
def initialize(group, interval, recurring = false, offset = nil, &block)
|
34
34
|
@group = group
|
35
|
-
|
35
|
+
|
36
36
|
@interval = interval
|
37
37
|
@recurring = recurring
|
38
38
|
@block = block
|
39
39
|
@offset = offset
|
40
|
-
|
40
|
+
|
41
41
|
@handle = nil
|
42
|
-
|
42
|
+
|
43
43
|
# If a start offset was supplied, use that, otherwise use the current timers offset.
|
44
44
|
reset(@offset || @group.current_offset)
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
def paused?
|
48
48
|
@group.paused_timers.include? self
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
def pause
|
52
52
|
return if paused?
|
53
|
-
|
53
|
+
|
54
54
|
@group.timers.delete self
|
55
55
|
@group.paused_timers.add self
|
56
|
-
|
56
|
+
|
57
57
|
@handle.cancel! if @handle
|
58
58
|
@handle = nil
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
def resume
|
62
62
|
return unless paused?
|
63
|
-
|
63
|
+
|
64
64
|
@group.paused_timers.delete self
|
65
|
-
|
65
|
+
|
66
66
|
# This will add us back to the group:
|
67
67
|
reset
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
alias continue resume
|
71
|
-
|
71
|
+
|
72
72
|
# Extend this timer
|
73
73
|
def delay(seconds)
|
74
74
|
@handle.cancel! if @handle
|
75
|
-
|
75
|
+
|
76
76
|
@offset += seconds
|
77
|
-
|
77
|
+
|
78
78
|
@handle = @group.events.schedule(@offset, self)
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
# Cancel this timer. Do not call while paused.
|
82
82
|
def cancel
|
83
83
|
return unless @handle
|
84
|
-
|
84
|
+
|
85
85
|
@handle.cancel! if @handle
|
86
86
|
@handle = nil
|
87
|
-
|
87
|
+
|
88
88
|
# This timer is no longer valid:
|
89
89
|
@group.timers.delete self if @group
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
# Reset this timer. Do not call while paused.
|
93
93
|
# @param offset [Numeric] the duration to add to the timer.
|
94
94
|
def reset(offset = @group.current_offset)
|
@@ -99,12 +99,12 @@ module Timers
|
|
99
99
|
else
|
100
100
|
@group.timers << self
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
@offset = Float(offset) + @interval
|
104
|
-
|
104
|
+
|
105
105
|
@handle = @group.events.schedule(@offset, self)
|
106
106
|
end
|
107
|
-
|
107
|
+
|
108
108
|
# Fire the block.
|
109
109
|
def fire(offset = @group.current_offset)
|
110
110
|
if recurring == :strict
|
@@ -115,36 +115,38 @@ module Timers
|
|
115
115
|
else
|
116
116
|
@offset = offset
|
117
117
|
end
|
118
|
-
|
118
|
+
|
119
119
|
@block.call(offset, self)
|
120
|
-
|
120
|
+
|
121
121
|
cancel unless recurring
|
122
122
|
end
|
123
|
-
|
123
|
+
|
124
124
|
alias call fire
|
125
|
-
|
125
|
+
|
126
126
|
# Number of seconds until next fire / since last fire
|
127
127
|
def fires_in
|
128
128
|
@offset - @group.current_offset if @offset
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
# Inspect a timer
|
132
132
|
def inspect
|
133
|
-
|
134
|
-
|
133
|
+
buffer = "#{to_s[0..-2]} ".dup
|
134
|
+
|
135
135
|
if @offset
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
136
|
+
if fires_in >= 0
|
137
|
+
buffer << "fires in #{fires_in} seconds"
|
138
|
+
else
|
139
|
+
buffer << "fired #{fires_in.abs} seconds ago"
|
140
|
+
end
|
141
|
+
|
142
|
+
buffer << ", recurs every #{interval}" if recurring
|
143
143
|
else
|
144
|
-
|
144
|
+
buffer << "dead"
|
145
145
|
end
|
146
|
-
|
147
|
-
|
146
|
+
|
147
|
+
buffer << ">"
|
148
|
+
|
149
|
+
return buffer
|
148
150
|
end
|
149
151
|
end
|
150
152
|
end
|
data/lib/timers/version.rb
CHANGED
data/lib/timers/wait.rb
CHANGED
@@ -28,7 +28,7 @@ module Timers
|
|
28
28
|
def self.for(duration, &block)
|
29
29
|
if duration
|
30
30
|
timeout = new(duration)
|
31
|
-
|
31
|
+
|
32
32
|
timeout.while_time_remaining(&block)
|
33
33
|
else
|
34
34
|
loop do
|
@@ -36,31 +36,31 @@ module Timers
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
def initialize(duration)
|
41
41
|
@duration = duration
|
42
42
|
@remaining = true
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
attr_reader :duration
|
46
46
|
attr_reader :remaining
|
47
|
-
|
47
|
+
|
48
48
|
# Yields while time remains for work to be done:
|
49
49
|
def while_time_remaining
|
50
50
|
@interval = Interval.new
|
51
51
|
@interval.start
|
52
|
-
|
52
|
+
|
53
53
|
yield @remaining while time_remaining?
|
54
54
|
ensure
|
55
55
|
@interval.stop
|
56
56
|
@interval = nil
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
private
|
60
|
-
|
60
|
+
|
61
61
|
def time_remaining?
|
62
62
|
@remaining = (@duration - @interval.to_f)
|
63
|
-
|
63
|
+
|
64
64
|
@remaining > 0
|
65
65
|
end
|
66
66
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.3.
|
4
|
+
version: 4.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-02-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -63,6 +63,7 @@ files:
|
|
63
63
|
- lib/timers/events.rb
|
64
64
|
- lib/timers/group.rb
|
65
65
|
- lib/timers/interval.rb
|
66
|
+
- lib/timers/priority_heap.rb
|
66
67
|
- lib/timers/timer.rb
|
67
68
|
- lib/timers/version.rb
|
68
69
|
- lib/timers/wait.rb
|