timers 2.0.0 → 3.0.0.pre

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
  SHA1:
3
- metadata.gz: 1bb812d219dd39a2f06dbead6028d0a472d43358
4
- data.tar.gz: 069ca7cb58645d3a4bc419166d67842eb482a375
3
+ metadata.gz: 3e9bfe42a47fd75ccdb65871da796a7f8fc34c06
4
+ data.tar.gz: 1b399be03f9c02b444b1564f63694bb41b81ecde
5
5
  SHA512:
6
- metadata.gz: 49534f3d20dab0cff520e02592ed0f4850230454f6fae5165990df3ad71b408b54ffe1c3e362954dc4f0fa9271f5a436f31c6bdb50b40b83d44d3aaac180c1b1
7
- data.tar.gz: b26cf3a87ac426cc12b336ef16f3081b302da9ebd8d5e631a7ddfc5c7aed64544c4d8e1aec13dd36f1e36771506a5e077b1b0a6dca91763d2a8eb40288047dc5
6
+ metadata.gz: 61ac36cb1df7d08dc523bd198d3cc510a7d59db6e21a25e7641b9bd3f8d3106518a99ec8691933c2ef64fd5d1abc43e3b2a7f5543baa4ebd7fb09fd5df7f07b0
7
+ data.tar.gz: c1679de4914d8d11ebccc3e8cc9ab833e9f14ca24ce5cd5bc601b40f5a6dac5cd42268375f15e04e157e8695f0d9ffd26f79c98aec25ac98a6682e7a725555c5
data/.rspec CHANGED
@@ -1,4 +1,5 @@
1
1
  --color
2
2
  --format documentation
3
3
  --backtrace
4
- --default_path spec
4
+ --order random
5
+ --warnings
@@ -1,16 +1,17 @@
1
1
  rvm:
2
2
  - 1.9.3
3
3
  - 2.0.0
4
+ - 2.1.2
4
5
  - ruby-head
5
6
  - jruby
6
7
  - jruby-head
7
- - rbx
8
+ - rbx-2
8
9
 
9
10
  matrix:
10
11
  allow_failures:
11
12
  - rvm: ruby-head
12
13
  - rvm: jruby-head
13
- - rvm: rbx
14
+ - rvm: rbx-2
14
15
 
15
16
  notifications:
16
17
  irc: "irc.freenode.org#celluloid"
@@ -0,0 +1,15 @@
1
+ # The Celluloid timers gem is beamed directly to you from the minds of...
2
+
3
+ - Tony Arcieri <bascule@gmail.com>
4
+ - Jeremy Hinegardner
5
+ - Sean Gregory
6
+ - Chuck Remes
7
+ - Utenmiki
8
+ - Ron Evans
9
+ - Larry Lv
10
+ - Bruno Enten
11
+ - Jesse Cooke
12
+ - Nicholas Evans
13
+ - Dimitrij Denissenko
14
+ - Ryan LeCompte
15
+ - Samuel G. D. Williams
data/CHANGES.md CHANGED
@@ -1,3 +1,9 @@
1
+ 3.0.0.pre
2
+ ---------
3
+ * Refactor `Timers` class into `Timers::Group`
4
+ * Add `Timers::Timeout` class for implementing timeouts
5
+ * Fix timer fudging
6
+
1
7
  2.0.0 (2013-12-30)
2
8
  ------------------
3
9
  * Switch to Hitimes for high precision monotonic counters
data/LICENSE CHANGED
@@ -1,4 +1,5 @@
1
- Copyright (c) 2012 Tony Arcieri
1
+ Copyright (c) 2012-14 The Celluloid Timers Developers: given in the file
2
+ AUTHORS.md at https://github.com/celluloid/timers/blob/master/AUTHORS.md
2
3
 
3
4
  MIT License
4
5
 
@@ -19,4 +20,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
20
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
21
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
22
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -90,5 +90,7 @@ timers.continue
90
90
  License
91
91
  -------
92
92
 
93
- Copyright (c) 2012 Tony Arcieri. Distributed under the MIT License. See
94
- LICENSE for further details.
93
+ Copyright (c) 2014 Celluloid timers project developers (given in the file
94
+ AUTHORS.md).
95
+
96
+ Distributed under the MIT License. See LICENSE file for further details.
@@ -1,176 +1,9 @@
1
- require 'set'
2
- require 'forwardable'
3
- require 'timers/version'
4
- require 'hitimes'
5
1
 
6
2
  # Workaround for thread safety issues in SortedSet initialization
7
3
  # See: https://github.com/celluloid/timers/issues/20
8
4
  SortedSet.new
9
5
 
10
- class Timers
11
- include Enumerable
12
- extend Forwardable
13
- def_delegators :@timers, :delete, :each, :empty?
14
-
15
- def initialize
16
- @timers = SortedSet.new
17
- @paused_timers = SortedSet.new
18
- @interval = Hitimes::Interval.new
19
- @interval.start
20
- end
21
-
22
- # Call the given block after the given interval
23
- def after(interval, &block)
24
- Timer.new(self, interval, false, &block)
25
- end
26
-
27
- # Call the given block after the given interval has expired. +interval+
28
- # is measured in milliseconds.
29
- #
30
- # Timer.new.after_milliseconds(25) { puts "fired!" }
31
- #
32
- def after_milliseconds(interval, &block)
33
- after(interval / 1000.0, &block)
34
- end
35
- alias_method :after_ms, :after_milliseconds
36
-
37
- # Call the given block periodically at the given interval
38
- def every(interval, &block)
39
- Timer.new(self, interval, true, &block)
40
- end
41
-
42
- # Wait for the next timer and fire it
43
- def wait
44
- i = wait_interval
45
- sleep i if i
46
- fire
47
- end
48
-
49
- # Interval to wait until when the next timer will fire
50
- def wait_interval(offset = self.current_offset)
51
- timer = @timers.first
52
- return unless timer
53
- interval = timer.offset - Float(offset)
54
- interval > 0 ? interval : 0
55
- end
56
-
57
- # Fire all timers that are ready
58
- def fire(offset = self.current_offset)
59
- time = Float(offset) + 0.001 # Fudge 1ms in case of clock imprecision
60
- while (timer = @timers.first) && (time >= timer.offset)
61
- @timers.delete timer
62
- timer.fire(offset)
63
- end
64
- end
65
-
66
- def add(timer)
67
- raise TypeError, "not a Timers::Timer" unless timer.is_a? Timers::Timer
68
- @timers.add(timer)
69
- end
70
-
71
- def pause(timer = nil)
72
- return pause_all if timer.nil?
73
- raise TypeError, "not a Timers::Timer" unless timer.is_a? Timers::Timer
74
- @timers.delete timer
75
- @paused_timers.add timer
76
- end
77
-
78
- def pause_all
79
- @timers.each {|timer| timer.pause}
80
- end
81
-
82
- def continue(timer = nil)
83
- return continue_all if timer.nil?
84
- raise TypeError, "not a Timers::Timer" unless timer.is_a? Timers::Timer
85
- @paused_timers.delete timer
86
- @timers.add timer
87
- end
88
-
89
- def continue_all
90
- @paused_timers.each {|timer| timer.continue}
91
- end
92
-
93
- def delay(seconds)
94
- @timers.each {|timer| timer.delay(seconds)}
95
- end
96
-
97
- alias_method :cancel, :delete
98
-
99
- def current_offset
100
- @interval.to_f
101
- end
102
-
103
- # An individual timer set to fire a given proc at a given time
104
- class Timer
105
- include Comparable
106
- attr_reader :interval, :offset, :recurring
107
-
108
- def initialize(timers, interval, recurring = false, &block)
109
- @timers, @interval, @recurring = timers, interval, recurring
110
- @block = block
111
- @offset = nil
112
-
113
- reset
114
- end
115
-
116
- def <=>(other)
117
- @offset <=> other.offset
118
- end
119
-
120
- # Cancel this timer
121
- def cancel
122
- @timers.cancel self
123
- end
124
-
125
- # Extend this timer
126
- def delay(seconds)
127
- @timers.delete self
128
- @offset += seconds
129
- @timers.add self
130
- end
131
-
132
- # Reset this timer
133
- def reset(offset = @timers.current_offset)
134
- @timers.cancel self if @time
135
- @offset = Float(offset) + @interval
136
- @timers.add self
137
- end
138
-
139
- # Fire the block
140
- def fire(offset = @timers.current_offset)
141
- reset(offset) if recurring
142
- @block.call
143
- end
144
- alias_method :call, :fire
145
-
146
- # Pause this timer
147
- def pause
148
- @timers.pause self
149
- end
150
-
151
- # Continue this timer
152
- def continue
153
- @timers.continue self
154
- end
155
-
156
- # Inspect a timer
157
- def inspect
158
- str = "#<Timers::Timer:#{object_id.to_s(16)} "
159
- offset = @timers.current_offset
160
-
161
- if @offset
162
- if @offset >= offset
163
- str << "fires in #{@offset - offset} seconds"
164
- else
165
- str << "fired #{offset - @offset} seconds ago"
166
- end
167
-
168
- str << ", recurs every #{interval}" if recurring
169
- else
170
- str << "dead"
171
- end
6
+ require 'timers/version'
172
7
 
173
- str << ">"
174
- end
175
- end
176
- end
8
+ require 'timers/group'
9
+ require 'timers/timeout'
@@ -0,0 +1,106 @@
1
+
2
+ require 'set'
3
+ require 'forwardable'
4
+ require 'hitimes'
5
+
6
+ require 'timers/timer'
7
+
8
+ module Timers
9
+ class Group
10
+ include Enumerable
11
+ extend Forwardable
12
+ def_delegators :@timers, :delete, :each, :empty?
13
+
14
+ def initialize
15
+ @timers = SortedSet.new
16
+ @paused_timers = SortedSet.new
17
+ @interval = Hitimes::Interval.new
18
+ @interval.start
19
+ end
20
+
21
+ # Call the given block after the given interval
22
+ def after(interval, &block)
23
+ Timer.new(self, interval, false, &block)
24
+ end
25
+
26
+ # Call the given block after the given interval has expired. +interval+
27
+ # is measured in milliseconds.
28
+ #
29
+ # Timer.new.after_milliseconds(25) { puts "fired!" }
30
+ #
31
+ def after_milliseconds(interval, &block)
32
+ after(interval / 1000.0, &block)
33
+ end
34
+ alias_method :after_ms, :after_milliseconds
35
+
36
+ # Call the given block periodically at the given interval
37
+ def every(interval, &block)
38
+ Timer.new(self, interval, true, &block)
39
+ end
40
+
41
+ # Wait for the next timer and fire it
42
+ def wait
43
+ # Repeatedly call sleep until there is no longer any wait_interval:
44
+ while i = wait_interval
45
+ # We cannot assume that sleep will wait for the specified time, it might be +/- a bit.
46
+ sleep i
47
+ end
48
+
49
+ fire
50
+ end
51
+
52
+ # Interval to wait until when the next timer will fire
53
+ def wait_interval(offset = self.current_offset)
54
+ timer = @timers.first
55
+ return unless timer
56
+ interval = timer.offset - Float(offset)
57
+ interval > 0 ? interval : nil
58
+ end
59
+
60
+ # Fire all timers that are ready
61
+ def fire(offset = self.current_offset)
62
+ time = Float(offset)
63
+ while (timer = @timers.first) && (time >= timer.offset)
64
+ @timers.delete timer
65
+ timer.fire(offset)
66
+ end
67
+ end
68
+
69
+ def add(timer)
70
+ raise TypeError, "not a Timers::Timer" unless timer.is_a? Timers::Timer
71
+ @timers.add(timer)
72
+ end
73
+
74
+ def pause(timer = nil)
75
+ return pause_all if timer.nil?
76
+ raise TypeError, "not a Timers::Timer" unless timer.is_a? Timers::Timer
77
+ @timers.delete timer
78
+ @paused_timers.add timer
79
+ end
80
+
81
+ def pause_all
82
+ @timers.each {|timer| timer.pause}
83
+ end
84
+
85
+ def continue(timer = nil)
86
+ return continue_all if timer.nil?
87
+ raise TypeError, "not a Timers::Timer" unless timer.is_a? Timers::Timer
88
+ @paused_timers.delete timer
89
+ @timers.add timer
90
+ end
91
+
92
+ def continue_all
93
+ @paused_timers.each {|timer| timer.continue}
94
+ end
95
+
96
+ def delay(seconds)
97
+ @timers.each {|timer| timer.delay(seconds)}
98
+ end
99
+
100
+ alias_method :cancel, :delete
101
+
102
+ def current_offset
103
+ @interval.to_f
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,36 @@
1
+
2
+ require 'hitimes'
3
+
4
+ module Timers
5
+ # An exclusive, monotonic timeout class.
6
+ class Timeout
7
+ def initialize(duration)
8
+ @duration = duration
9
+ @remaining = true
10
+ end
11
+
12
+ attr :duration
13
+ attr :remaining
14
+
15
+ # Yields while time remains for work to be done:
16
+ def while_time_remaining(&block)
17
+ @interval = Hitimes::Interval.new
18
+ @interval.start
19
+
20
+ while time_remaining?
21
+ yield @remaining
22
+ end
23
+ ensure
24
+ @interval.stop
25
+ @interval = nil
26
+ end
27
+
28
+ private
29
+
30
+ def time_remaining?
31
+ @remaining = (@duration - @interval.duration)
32
+
33
+ return @remaining > 0
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,86 @@
1
+
2
+ module Timers
3
+ # An individual timer set to fire a given proc at a given time
4
+ class Timer
5
+ include Comparable
6
+ attr_reader :interval, :offset, :recurring
7
+
8
+ def initialize(timers, interval, recurring = false, &block)
9
+ @timers, @interval, @recurring = timers, interval, recurring
10
+ @block = block
11
+ @offset = nil
12
+
13
+ reset
14
+ end
15
+
16
+ def <=>(other)
17
+ @offset <=> other.offset
18
+ end
19
+
20
+ # Cancel this timer
21
+ def cancel
22
+ @timers.cancel self
23
+ end
24
+
25
+ # Extend this timer
26
+ def delay(seconds)
27
+ @timers.delete self
28
+ @offset += seconds
29
+ @timers.add self
30
+ end
31
+
32
+ # Reset this timer
33
+ def reset(offset = @timers.current_offset)
34
+ @timers.cancel self if @offset
35
+ @offset = Float(offset) + @interval
36
+ @timers.add self
37
+ end
38
+
39
+ # Fire the block
40
+ def fire(offset = @timers.current_offset)
41
+ if recurring
42
+ reset(offset)
43
+ else
44
+ @offset = offset
45
+ end
46
+
47
+ @block.call
48
+ end
49
+ alias_method :call, :fire
50
+
51
+ # Pause this timer
52
+ def pause
53
+ @timers.pause self
54
+ end
55
+
56
+ # Continue this timer
57
+ def continue
58
+ @timers.continue self
59
+ end
60
+
61
+ # Number of seconds until next fire / since last fire
62
+ def fires_in
63
+ @offset - @timers.current_offset if @offset
64
+ end
65
+
66
+ # Inspect a timer
67
+ def inspect
68
+ str = "#<Timers::Timer:#{object_id.to_s(16)} "
69
+ offset = @timers.current_offset
70
+
71
+ if @offset
72
+ if fires_in >= 0
73
+ str << "fires in #{fires_in} seconds"
74
+ else
75
+ str << "fired #{fires_in.abs} seconds ago"
76
+ end
77
+
78
+ str << ", recurs every #{interval}" if recurring
79
+ else
80
+ str << "dead"
81
+ end
82
+
83
+ str << ">"
84
+ end
85
+ end
86
+ end
@@ -1,3 +1,3 @@
1
- class Timers
2
- VERSION = "2.0.0"
1
+ module Timers
2
+ VERSION = "3.0.0.pre"
3
3
  end
@@ -1,48 +1,46 @@
1
- require 'spec_helper'
2
1
 
3
- describe Timers do
4
- # Level of accuracy enforced by tests (50ms)
5
- Q = 0.05
2
+ require 'spec_helper'
6
3
 
4
+ describe Timers::Group do
7
5
  it "sleeps until the next timer" do
8
- interval = Q * 2
6
+ interval = TIMER_QUANTUM * 2
9
7
  started_at = Time.now
10
8
 
11
9
  fired = false
12
10
  subject.after(interval) { fired = true }
13
11
  subject.wait
14
12
 
15
- expect(fired).to be_true
16
- expect(Time.now - started_at).to be_within(Q).of interval
13
+ expect(fired).to be true
14
+ expect(Time.now - started_at).to be_within(TIMER_QUANTUM).of interval
17
15
  end
18
16
 
19
17
  it "fires instantly when next timer is in the past" do
20
18
  fired = false
21
- subject.after(Q) { fired = true }
22
- sleep(Q * 2)
19
+ subject.after(TIMER_QUANTUM) { fired = true }
20
+ sleep(TIMER_QUANTUM * 2)
23
21
  subject.wait
24
22
 
25
- expect(fired).to be_true
23
+ expect(fired).to be true
26
24
  end
27
25
 
28
26
  it "calculates the interval until the next timer should fire" do
29
27
  interval = 0.1
30
28
 
31
29
  subject.after(interval)
32
- expect(subject.wait_interval).to be_within(Q).of interval
30
+ expect(subject.wait_interval).to be_within(TIMER_QUANTUM).of interval
33
31
 
34
32
  sleep(interval)
35
- expect(subject.wait_interval).to be(0)
33
+ expect(subject.wait_interval).to be(nil)
36
34
  end
37
35
 
38
36
  it "fires timers in the correct order" do
39
37
  result = []
40
38
 
41
- subject.after(Q * 2) { result << :two }
42
- subject.after(Q * 3) { result << :three }
43
- subject.after(Q * 1) { result << :one }
39
+ subject.after(TIMER_QUANTUM * 2) { result << :two }
40
+ subject.after(TIMER_QUANTUM * 3) { result << :three }
41
+ subject.after(TIMER_QUANTUM * 1) { result << :one }
44
42
 
45
- sleep Q * 4
43
+ sleep TIMER_QUANTUM * 4
46
44
  subject.fire
47
45
 
48
46
  expect(result).to eq [:one, :two, :three]
@@ -58,13 +56,13 @@ describe Timers do
58
56
  it "continues to fire the timers at each interval" do
59
57
  result = []
60
58
 
61
- subject.every(Q * 2) { result << :foo }
59
+ subject.every(TIMER_QUANTUM * 2) { result << :foo }
62
60
 
63
- sleep Q * 3
61
+ sleep TIMER_QUANTUM * 3
64
62
  subject.fire
65
63
  expect(result).to eq [:foo]
66
64
 
67
- sleep Q * 5
65
+ sleep TIMER_QUANTUM * 5
68
66
  subject.fire
69
67
  expect(result).to eq [:foo, :foo]
70
68
  end
@@ -77,13 +75,13 @@ describe Timers do
77
75
  subject.after_milliseconds(interval_ms)
78
76
  expected_elapse = subject.wait_interval
79
77
 
80
- expect(subject.wait_interval).to be_within(Q).of(interval_ms / 1000.0)
78
+ expect(subject.wait_interval).to be_within(TIMER_QUANTUM).of(interval_ms / 1000.0)
81
79
  end
82
80
  end
83
81
 
84
82
  describe "pause and continue timers" do
85
83
  before(:each) do
86
- @interval = Q * 2
84
+ @interval = TIMER_QUANTUM * 2
87
85
  started_at = Time.now
88
86
 
89
87
  @fired = false
@@ -95,7 +93,7 @@ describe Timers do
95
93
  it "does not fire when paused" do
96
94
  @timer.pause
97
95
  subject.wait
98
- expect(@fired).to be_false
96
+ expect(@fired).to be false
99
97
  end
100
98
 
101
99
  it "fires when continued after pause" do
@@ -103,14 +101,14 @@ describe Timers do
103
101
  subject.wait
104
102
  @timer.continue
105
103
  subject.wait
106
- expect(@fired).to be_true
104
+ expect(@fired).to be true
107
105
  end
108
106
 
109
107
  it "can pause all timers at once" do
110
108
  subject.pause
111
109
  subject.wait
112
- expect(@fired).to be_false
113
- expect(@fired2).to be_false
110
+ expect(@fired).to be false
111
+ expect(@fired2).to be false
114
112
  end
115
113
 
116
114
  it "can continue all timers at once" do
@@ -118,20 +116,20 @@ describe Timers do
118
116
  subject.wait
119
117
  subject.continue
120
118
  subject.wait
121
- expect(@fired).to be_true
122
- expect(@fired2).to be_true
119
+ expect(@fired).to be true
120
+ expect(@fired2).to be true
123
121
  end
124
122
 
125
123
  it "can fire the timer directly" do
126
124
  fired = false
127
- timer = subject.after( Q * 1 ) { fired = true }
125
+ timer = subject.after( TIMER_QUANTUM * 1 ) { fired = true }
128
126
  timer.pause
129
127
  subject.wait
130
- expect(fired).not_to be_true
128
+ expect(fired).not_to be true
131
129
  timer.continue
132
- expect(fired).not_to be_true
130
+ expect(fired).not_to be true
133
131
  timer.fire
134
- expect(fired).to be_true
132
+ expect(fired).to be true
135
133
  end
136
134
 
137
135
  end
@@ -140,7 +138,7 @@ describe Timers do
140
138
  it "adds appropriate amount of time to timer" do
141
139
  timer = subject.after(10)
142
140
  timer.delay(5)
143
- expect(timer.offset - subject.current_offset).to be_within(Q).of(15)
141
+ expect(timer.offset - subject.current_offset).to be_within(TIMER_QUANTUM).of(15)
144
142
  end
145
143
  end
146
144
 
@@ -149,8 +147,8 @@ describe Timers do
149
147
  timer = subject.after(10)
150
148
  timer2 = subject.after(20)
151
149
  subject.delay(5)
152
- expect(timer.offset - subject.current_offset).to be_within(Q).of(15)
153
- expect(timer2.offset - subject.current_offset).to be_within(Q).of(25)
150
+ expect(timer.offset - subject.current_offset).to be_within(TIMER_QUANTUM).of(15)
151
+ expect(timer2.offset - subject.current_offset).to be_within(TIMER_QUANTUM).of(25)
154
152
  end
155
153
  end
156
154
 
@@ -158,12 +156,12 @@ describe Timers do
158
156
  it "fires timers in the correct order" do
159
157
  result = []
160
158
 
161
- second = subject.after(Q * 2) { result << :two }
162
- third = subject.after(Q * 3) { result << :three }
163
- first = subject.after(Q * 1) { result << :one }
164
- first.delay(Q * 3)
159
+ second = subject.after(TIMER_QUANTUM * 2) { result << :two }
160
+ third = subject.after(TIMER_QUANTUM * 3) { result << :three }
161
+ first = subject.after(TIMER_QUANTUM * 1) { result << :one }
162
+ first.delay(TIMER_QUANTUM * 3)
165
163
 
166
- sleep Q * 5
164
+ sleep TIMER_QUANTUM * 5
167
165
  subject.fire
168
166
 
169
167
  expect(result).to eq [:two, :three, :one]
@@ -173,29 +171,52 @@ describe Timers do
173
171
  describe "Timer inspection" do
174
172
  it "before firing" do
175
173
  fired = false
176
- timer = subject.after(Q * 5) { fired = true }
174
+ timer = subject.after(TIMER_QUANTUM * 5) { fired = true }
177
175
  timer.pause
178
- expect(fired).not_to be_true
176
+ expect(fired).not_to be true
179
177
  expect(timer.inspect).to match(/\A#<Timers::Timer:[\da-f]+ fires in [-\.\de]+ seconds>\Z/)
180
178
  end
181
179
 
182
180
  it "after firing" do
183
181
  fired = false
184
- timer = subject.after(Q) { fired = true }
182
+ timer = subject.after(TIMER_QUANTUM) { fired = true }
185
183
 
186
184
  subject.wait
187
185
 
188
- expect(fired).to be_true
186
+ expect(fired).to be true
189
187
  expect(timer.inspect).to match(/\A#<Timers::Timer:[\da-f]+ fired [-\.\de]+ seconds ago>\Z/)
190
188
  end
191
189
 
192
190
  it "recurring firing" do
193
191
  result = []
194
- timer = subject.every(Q) { result << :foo }
192
+ timer = subject.every(TIMER_QUANTUM) { result << :foo }
195
193
 
196
194
  subject.wait
197
195
  expect(result).not_to be_empty
198
- expect(timer.inspect).to match(/\A#<Timers::Timer:[\da-f]+ fires in [-\.\de]+ seconds, recurs every #{sprintf("%0.2f", Q)}>\Z/)
196
+ expect(timer.inspect).to match(/\A#<Timers::Timer:[\da-f]+ fires in [-\.\de]+ seconds, recurs every #{sprintf("%0.2f", TIMER_QUANTUM)}>\Z/)
197
+ end
198
+ end
199
+
200
+ describe "fires_in" do
201
+ let(:interval) { TIMER_QUANTUM * 2 }
202
+
203
+ it "calculates the interval until the next fire if it's recurring" do
204
+ timer = subject.every(interval) { true }
205
+ expect(timer.fires_in).to be_within(TIMER_QUANTUM).of(interval)
206
+ end
207
+
208
+ context "when timer is not recurring" do
209
+ let!(:timer) { subject.after(interval) { true } }
210
+
211
+ it "calculates the interval until the next fire if it hasn't already fired" do
212
+ expect(timer.fires_in).to be_within(TIMER_QUANTUM).of(interval)
213
+ end
214
+
215
+ it "calculates the interval since last fire if already fired" do
216
+ subject.wait
217
+ sleep(interval)
218
+ expect(timer.fires_in).to be_within(TIMER_QUANTUM).of(0 - interval)
219
+ end
199
220
  end
200
221
  end
201
222
  end
@@ -1,4 +1,8 @@
1
- require 'bundler/setup'
2
- require 'timers'
3
1
  require 'coveralls'
4
2
  Coveralls.wear!
3
+
4
+ require 'bundler/setup'
5
+ require 'timers'
6
+
7
+ # Level of accuracy enforced by tests (50ms)
8
+ TIMER_QUANTUM = 0.05
@@ -0,0 +1,29 @@
1
+
2
+ require 'spec_helper'
3
+ require 'timers/timeout'
4
+
5
+ describe Timers::Timeout do
6
+ it "repeats until timeout expired" do
7
+ timeout = Timers::Timeout.new(5)
8
+ count = 0
9
+
10
+ timeout.while_time_remaining do |remaining|
11
+ expect(remaining).to be_within(TIMER_QUANTUM).of (timeout.duration - count)
12
+
13
+ count += 1
14
+ sleep 1
15
+ end
16
+
17
+ expect(count).to eq(5)
18
+ end
19
+
20
+ it "yields results as soon as possible" do
21
+ timeout = Timers::Timeout.new(5)
22
+
23
+ result = timeout.while_time_remaining do |remaining|
24
+ break :done
25
+ end
26
+
27
+ expect(result).to eq(:done)
28
+ end
29
+ end
@@ -19,5 +19,5 @@ Gem::Specification.new do |gem|
19
19
  gem.add_runtime_dependency 'hitimes'
20
20
 
21
21
  gem.add_development_dependency 'rake'
22
- gem.add_development_dependency 'rspec'
22
+ gem.add_development_dependency 'rspec', '~> 3.0.0'
23
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timers
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 3.0.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Arcieri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-30 00:00:00.000000000 Z
11
+ date: 2014-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hitimes
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 3.0.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 3.0.0
55
55
  description: Pure Ruby one-shot and periodic timers
56
56
  email:
57
57
  - tony.arcieri@gmail.com
@@ -63,15 +63,20 @@ files:
63
63
  - ".gitignore"
64
64
  - ".rspec"
65
65
  - ".travis.yml"
66
+ - AUTHORS.md
66
67
  - CHANGES.md
67
68
  - Gemfile
68
69
  - LICENSE
69
70
  - README.md
70
71
  - Rakefile
71
72
  - lib/timers.rb
73
+ - lib/timers/group.rb
74
+ - lib/timers/timeout.rb
75
+ - lib/timers/timer.rb
72
76
  - lib/timers/version.rb
77
+ - spec/group_spec.rb
73
78
  - spec/spec_helper.rb
74
- - spec/timers_spec.rb
79
+ - spec/timeout_spec.rb
75
80
  - timers.gemspec
76
81
  homepage: https://github.com/celluloid/timers
77
82
  licenses:
@@ -88,16 +93,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
88
93
  version: '0'
89
94
  required_rubygems_version: !ruby/object:Gem::Requirement
90
95
  requirements:
91
- - - ">="
96
+ - - ">"
92
97
  - !ruby/object:Gem::Version
93
- version: '0'
98
+ version: 1.3.1
94
99
  requirements: []
95
100
  rubyforge_project:
96
- rubygems_version: 2.2.0
101
+ rubygems_version: 2.2.2
97
102
  signing_key:
98
103
  specification_version: 4
99
104
  summary: Schedule procs to run after a certain time, or at periodic intervals, using
100
105
  any API that accepts a timeout
101
106
  test_files:
107
+ - spec/group_spec.rb
102
108
  - spec/spec_helper.rb
103
- - spec/timers_spec.rb
109
+ - spec/timeout_spec.rb