timers 4.1.1 → 4.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ module Timers
24
+ # A collection of timers which may fire at different times
25
+ class Interval
26
+ # Get the current elapsed monotonic time.
27
+ def initialize
28
+ @total = 0.0
29
+ @current = nil
30
+ end
31
+
32
+ def start
33
+ return if @current
34
+
35
+ @current = now
36
+ end
37
+
38
+ def stop
39
+ return unless @current
40
+
41
+ @total += duration
42
+
43
+ @current = nil
44
+ end
45
+
46
+ def to_f
47
+ @total + duration
48
+ end
49
+
50
+ protected def duration
51
+ now - @current
52
+ end
53
+
54
+ protected def now
55
+ ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
56
+ end
57
+ end
58
+ end
@@ -1,128 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
1
22
 
2
23
  module Timers
3
- # An individual timer set to fire a given proc at a given time. A timer is
4
- # always connected to a Timer::Group but it would ONLY be in @group.timers
5
- # if it also has a @handle specified. Otherwise it is either PAUSED or has
6
- # been FIRED and is not recurring. You can manually enter this state by
7
- # calling #cancel and resume normal operation by calling #reset.
8
- class Timer
9
- include Comparable
10
- attr_reader :interval, :offset, :recurring
11
-
12
- def initialize(group, interval, recurring = false, offset = nil, &block)
13
- @group = group
14
-
15
- @interval = interval
16
- @recurring = recurring
17
- @block = block
18
- @offset = offset
19
-
20
- @handle = nil
21
-
22
- # If a start offset was supplied, use that, otherwise use the current timers offset.
23
- reset(@offset || @group.current_offset)
24
- end
25
-
26
- def paused?
27
- @group.paused_timers.include? self
28
- end
29
-
30
- def pause
31
- return if paused?
32
-
33
- @group.timers.delete self
34
- @group.paused_timers.add self
35
-
36
- @handle.cancel! if @handle
37
- @handle = nil
38
- end
39
-
40
- def resume
41
- return unless paused?
42
-
43
- @group.paused_timers.delete self
44
-
45
- # This will add us back to the group:
46
- reset
47
- end
48
-
49
- alias_method :continue, :resume
50
-
51
- # Extend this timer
52
- def delay(seconds)
53
- @handle.cancel! if @handle
54
-
55
- @offset += seconds
56
-
57
- @handle = @group.events.schedule(@offset, self)
58
- end
59
-
60
- # Cancel this timer. Do not call while paused.
61
- def cancel
62
- return unless @handle
63
-
64
- @handle.cancel! if @handle
65
- @handle = nil
66
-
67
- # This timer is no longer valid:
68
- @group.timers.delete self if @group
69
- end
70
-
71
- # Reset this timer. Do not call while paused.
72
- def reset(offset = @group.current_offset)
73
- # This logic allows us to minimise the interaction with @group.timers.
74
- # A timer with a handle is always registered with the group.
75
- if @handle
76
- @handle.cancel!
77
- else
78
- @group.timers << self
79
- end
80
-
81
- @offset = Float(offset) + @interval
82
-
83
- @handle = @group.events.schedule(@offset, self)
84
- end
85
-
86
- # Fire the block.
87
- def fire(offset = @group.current_offset)
88
- if recurring == :strict
89
- # ... make the next interval strictly the last offset + the interval:
90
- reset(@offset)
91
- elsif recurring
92
- reset(offset)
93
- else
94
- @offset = offset
95
- end
96
-
97
- @block.call(offset)
98
-
99
- cancel unless recurring
100
- end
101
-
102
- alias_method :call, :fire
103
-
104
- # Number of seconds until next fire / since last fire
105
- def fires_in
106
- @offset - @group.current_offset if @offset
107
- end
108
-
109
- # Inspect a timer
110
- def inspect
111
- str = "#<Timers::Timer:#{object_id.to_s(16)} "
112
-
113
- if @offset
114
- if fires_in >= 0
115
- str << "fires in #{fires_in} seconds"
116
- else
117
- str << "fired #{fires_in.abs} seconds ago"
118
- end
119
-
120
- str << ", recurs every #{interval}" if recurring
121
- else
122
- str << "dead"
123
- end
124
-
125
- str << ">"
126
- end
127
- end
24
+ # An individual timer set to fire a given proc at a given time. A timer is
25
+ # always connected to a Timer::Group but it would ONLY be in @group.timers
26
+ # if it also has a @handle specified. Otherwise it is either PAUSED or has
27
+ # been FIRED and is not recurring. You can manually enter this state by
28
+ # calling #cancel and resume normal operation by calling #reset.
29
+ class Timer
30
+ include Comparable
31
+ attr_reader :interval, :offset, :recurring
32
+
33
+ def initialize(group, interval, recurring = false, offset = nil, &block)
34
+ @group = group
35
+
36
+ @interval = interval
37
+ @recurring = recurring
38
+ @block = block
39
+ @offset = offset
40
+
41
+ @handle = nil
42
+
43
+ # If a start offset was supplied, use that, otherwise use the current timers offset.
44
+ reset(@offset || @group.current_offset)
45
+ end
46
+
47
+ def paused?
48
+ @group.paused_timers.include? self
49
+ end
50
+
51
+ def pause
52
+ return if paused?
53
+
54
+ @group.timers.delete self
55
+ @group.paused_timers.add self
56
+
57
+ @handle.cancel! if @handle
58
+ @handle = nil
59
+ end
60
+
61
+ def resume
62
+ return unless paused?
63
+
64
+ @group.paused_timers.delete self
65
+
66
+ # This will add us back to the group:
67
+ reset
68
+ end
69
+
70
+ alias continue resume
71
+
72
+ # Extend this timer
73
+ def delay(seconds)
74
+ @handle.cancel! if @handle
75
+
76
+ @offset += seconds
77
+
78
+ @handle = @group.events.schedule(@offset, self)
79
+ end
80
+
81
+ # Cancel this timer. Do not call while paused.
82
+ def cancel
83
+ return unless @handle
84
+
85
+ @handle.cancel! if @handle
86
+ @handle = nil
87
+
88
+ # This timer is no longer valid:
89
+ @group.timers.delete self if @group
90
+ end
91
+
92
+ # Reset this timer. Do not call while paused.
93
+ # @param offset [Numeric] the duration to add to the timer.
94
+ def reset(offset = @group.current_offset)
95
+ # This logic allows us to minimise the interaction with @group.timers.
96
+ # A timer with a handle is always registered with the group.
97
+ if @handle
98
+ @handle.cancel!
99
+ else
100
+ @group.timers << self
101
+ end
102
+
103
+ @offset = Float(offset) + @interval
104
+
105
+ @handle = @group.events.schedule(@offset, self)
106
+ end
107
+
108
+ # Fire the block.
109
+ def fire(offset = @group.current_offset)
110
+ if recurring == :strict
111
+ # ... make the next interval strictly the last offset + the interval:
112
+ reset(@offset)
113
+ elsif recurring
114
+ reset(offset)
115
+ else
116
+ @offset = offset
117
+ end
118
+
119
+ @block.call(offset, self)
120
+
121
+ cancel unless recurring
122
+ end
123
+
124
+ alias call fire
125
+
126
+ # Number of seconds until next fire / since last fire
127
+ def fires_in
128
+ @offset - @group.current_offset if @offset
129
+ end
130
+
131
+ # Inspect a timer
132
+ def inspect
133
+ str = "#{to_s[0..-2]} ".dup
134
+
135
+ if @offset
136
+ str << if fires_in >= 0
137
+ "fires in #{fires_in} seconds"
138
+ else
139
+ "fired #{fires_in.abs} seconds ago"
140
+ end
141
+
142
+ str << ", recurs every #{interval}" if recurring
143
+ else
144
+ str << "dead"
145
+ end
146
+
147
+ str << ">"
148
+ end
149
+ end
128
150
  end
@@ -1,3 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
1
23
  module Timers
2
- VERSION = "4.1.1"
24
+ VERSION = "4.3.1"
3
25
  end
@@ -1,48 +1,67 @@
1
+ # frozen_string_literal: true
1
2
 
2
- require 'hitimes'
3
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require_relative "interval"
3
24
 
4
25
  module Timers
5
- # An exclusive, monotonic timeout class.
6
- class Wait
7
- def self.for(duration, &block)
8
- if duration
9
- timeout = self.new(duration)
10
-
11
- timeout.while_time_remaining(&block)
12
- else
13
- while true
14
- yield(nil)
15
- end
16
- end
17
- end
18
-
19
- def initialize(duration)
20
- @duration = duration
21
- @remaining = true
22
- end
23
-
24
- attr :duration
25
- attr :remaining
26
-
27
- # Yields while time remains for work to be done:
28
- def while_time_remaining(&block)
29
- @interval = Hitimes::Interval.new
30
- @interval.start
31
-
32
- while time_remaining?
33
- yield @remaining
34
- end
35
- ensure
36
- @interval.stop
37
- @interval = nil
38
- end
39
-
40
- private
41
-
42
- def time_remaining?
43
- @remaining = (@duration - @interval.duration)
44
-
45
- return @remaining > 0
46
- end
47
- end
26
+ # An exclusive, monotonic timeout class.
27
+ class Wait
28
+ def self.for(duration, &block)
29
+ if duration
30
+ timeout = new(duration)
31
+
32
+ timeout.while_time_remaining(&block)
33
+ else
34
+ loop do
35
+ yield(nil)
36
+ end
37
+ end
38
+ end
39
+
40
+ def initialize(duration)
41
+ @duration = duration
42
+ @remaining = true
43
+ end
44
+
45
+ attr_reader :duration
46
+ attr_reader :remaining
47
+
48
+ # Yields while time remains for work to be done:
49
+ def while_time_remaining
50
+ @interval = Interval.new
51
+ @interval.start
52
+
53
+ yield @remaining while time_remaining?
54
+ ensure
55
+ @interval.stop
56
+ @interval = nil
57
+ end
58
+
59
+ private
60
+
61
+ def time_remaining?
62
+ @remaining = (@duration - @interval.to_f)
63
+
64
+ @remaining > 0
65
+ end
66
+ end
48
67
  end