timers 4.1.2 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # This file is part of the "timers" project and released under the MIT license.
4
+ #
5
+ # Copyright, 2018, by Samuel Williams. All rights reserved.
6
+ #
7
+
8
+ module Timers
9
+ # A collection of timers which may fire at different times
10
+ class Interval
11
+ # Get the current elapsed monotonic time.
12
+ def initialize
13
+ @total = 0.0
14
+ @current = nil
15
+ end
16
+
17
+ def start
18
+ return if @current
19
+
20
+ @current = now
21
+ end
22
+
23
+ def stop
24
+ return unless @current
25
+
26
+ @total += duration
27
+
28
+ @current = nil
29
+ end
30
+
31
+ def to_f
32
+ @total + duration
33
+ end
34
+
35
+ protected def duration
36
+ now - @current
37
+ end
38
+
39
+ protected def now
40
+ ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
41
+ end
42
+ end
43
+ end
@@ -1,129 +1,134 @@
1
1
  # frozen_string_literal: true
2
+ #
3
+ # This file is part of the "timers" project and released under the MIT license.
4
+ #
5
+ # Copyright, 2018, by Samuel Williams. All rights reserved.
6
+ #
2
7
 
3
8
  module Timers
4
- # An individual timer set to fire a given proc at a given time. A timer is
5
- # always connected to a Timer::Group but it would ONLY be in @group.timers
6
- # if it also has a @handle specified. Otherwise it is either PAUSED or has
7
- # been FIRED and is not recurring. You can manually enter this state by
8
- # calling #cancel and resume normal operation by calling #reset.
9
- class Timer
10
- include Comparable
11
- attr_reader :interval, :offset, :recurring
9
+ # An individual timer set to fire a given proc at a given time. A timer is
10
+ # always connected to a Timer::Group but it would ONLY be in @group.timers
11
+ # if it also has a @handle specified. Otherwise it is either PAUSED or has
12
+ # been FIRED and is not recurring. You can manually enter this state by
13
+ # calling #cancel and resume normal operation by calling #reset.
14
+ class Timer
15
+ include Comparable
16
+ attr_reader :interval, :offset, :recurring
12
17
 
13
- def initialize(group, interval, recurring = false, offset = nil, &block)
14
- @group = group
18
+ def initialize(group, interval, recurring = false, offset = nil, &block)
19
+ @group = group
15
20
 
16
- @interval = interval
17
- @recurring = recurring
18
- @block = block
19
- @offset = offset
21
+ @interval = interval
22
+ @recurring = recurring
23
+ @block = block
24
+ @offset = offset
20
25
 
21
- @handle = nil
26
+ @handle = nil
22
27
 
23
- # If a start offset was supplied, use that, otherwise use the current timers offset.
24
- reset(@offset || @group.current_offset)
25
- end
28
+ # If a start offset was supplied, use that, otherwise use the current timers offset.
29
+ reset(@offset || @group.current_offset)
30
+ end
26
31
 
27
- def paused?
28
- @group.paused_timers.include? self
29
- end
30
-
31
- def pause
32
- return if paused?
33
-
34
- @group.timers.delete self
35
- @group.paused_timers.add self
36
-
37
- @handle.cancel! if @handle
38
- @handle = nil
39
- end
40
-
41
- def resume
42
- return unless paused?
43
-
44
- @group.paused_timers.delete self
45
-
46
- # This will add us back to the group:
47
- reset
48
- end
49
-
50
- alias continue resume
51
-
52
- # Extend this timer
53
- def delay(seconds)
54
- @handle.cancel! if @handle
55
-
56
- @offset += seconds
57
-
58
- @handle = @group.events.schedule(@offset, self)
59
- end
60
-
61
- # Cancel this timer. Do not call while paused.
62
- def cancel
63
- return unless @handle
64
-
65
- @handle.cancel! if @handle
66
- @handle = nil
67
-
68
- # This timer is no longer valid:
69
- @group.timers.delete self if @group
70
- end
71
-
72
- # Reset this timer. Do not call while paused.
73
- def reset(offset = @group.current_offset)
74
- # This logic allows us to minimise the interaction with @group.timers.
75
- # A timer with a handle is always registered with the group.
76
- if @handle
77
- @handle.cancel!
78
- else
79
- @group.timers << self
80
- end
81
-
82
- @offset = Float(offset) + @interval
83
-
84
- @handle = @group.events.schedule(@offset, self)
85
- end
86
-
87
- # Fire the block.
88
- def fire(offset = @group.current_offset)
89
- if recurring == :strict
90
- # ... make the next interval strictly the last offset + the interval:
91
- reset(@offset)
92
- elsif recurring
93
- reset(offset)
94
- else
95
- @offset = offset
96
- end
97
-
98
- @block.call(offset)
99
-
100
- cancel unless recurring
101
- end
102
-
103
- alias call fire
104
-
105
- # Number of seconds until next fire / since last fire
106
- def fires_in
107
- @offset - @group.current_offset if @offset
108
- end
32
+ def paused?
33
+ @group.paused_timers.include? self
34
+ end
35
+
36
+ def pause
37
+ return if paused?
38
+
39
+ @group.timers.delete self
40
+ @group.paused_timers.add self
41
+
42
+ @handle.cancel! if @handle
43
+ @handle = nil
44
+ end
45
+
46
+ def resume
47
+ return unless paused?
48
+
49
+ @group.paused_timers.delete self
50
+
51
+ # This will add us back to the group:
52
+ reset
53
+ end
54
+
55
+ alias continue resume
56
+
57
+ # Extend this timer
58
+ def delay(seconds)
59
+ @handle.cancel! if @handle
60
+
61
+ @offset += seconds
62
+
63
+ @handle = @group.events.schedule(@offset, self)
64
+ end
65
+
66
+ # Cancel this timer. Do not call while paused.
67
+ def cancel
68
+ return unless @handle
69
+
70
+ @handle.cancel! if @handle
71
+ @handle = nil
72
+
73
+ # This timer is no longer valid:
74
+ @group.timers.delete self if @group
75
+ end
76
+
77
+ # Reset this timer. Do not call while paused.
78
+ def reset(offset = @group.current_offset)
79
+ # This logic allows us to minimise the interaction with @group.timers.
80
+ # A timer with a handle is always registered with the group.
81
+ if @handle
82
+ @handle.cancel!
83
+ else
84
+ @group.timers << self
85
+ end
86
+
87
+ @offset = Float(offset) + @interval
88
+
89
+ @handle = @group.events.schedule(@offset, self)
90
+ end
91
+
92
+ # Fire the block.
93
+ def fire(offset = @group.current_offset)
94
+ if recurring == :strict
95
+ # ... make the next interval strictly the last offset + the interval:
96
+ reset(@offset)
97
+ elsif recurring
98
+ reset(offset)
99
+ else
100
+ @offset = offset
101
+ end
102
+
103
+ @block.call(offset)
104
+
105
+ cancel unless recurring
106
+ end
107
+
108
+ alias call fire
109
+
110
+ # Number of seconds until next fire / since last fire
111
+ def fires_in
112
+ @offset - @group.current_offset if @offset
113
+ end
109
114
 
110
- # Inspect a timer
111
- def inspect
112
- str = "#<Timers::Timer:#{object_id.to_s(16)} ".dup
115
+ # Inspect a timer
116
+ def inspect
117
+ str = "#{to_s[0..-2]} ".dup
113
118
 
114
- if @offset
115
- str << if fires_in >= 0
116
- "fires in #{fires_in} seconds"
117
- else
118
- "fired #{fires_in.abs} seconds ago"
119
- end
119
+ if @offset
120
+ str << if fires_in >= 0
121
+ "fires in #{fires_in} seconds"
122
+ else
123
+ "fired #{fires_in.abs} seconds ago"
124
+ end
120
125
 
121
- str << ", recurs every #{interval}" if recurring
122
- else
123
- str << "dead"
124
- end
126
+ str << ", recurs every #{interval}" if recurring
127
+ else
128
+ str << "dead"
129
+ end
125
130
 
126
- str << ">"
127
- end
128
- end
131
+ str << ">"
132
+ end
133
+ end
129
134
  end
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
+ #
3
+ # This file is part of the "timers" project and released under the MIT license.
4
+ #
5
+ # Copyright, 2018, by Samuel Williams. All rights reserved.
6
+ #
2
7
 
3
8
  module Timers
4
- VERSION = "4.1.2"
9
+ VERSION = "4.2.0"
5
10
  end
@@ -1,47 +1,52 @@
1
1
  # frozen_string_literal: true
2
+ #
3
+ # This file is part of the "timers" project and released under the MIT license.
4
+ #
5
+ # Copyright, 2018, by Samuel Williams. All rights reserved.
6
+ #
2
7
 
3
- require "hitimes"
8
+ require_relative "interval"
4
9
 
5
10
  module Timers
6
- # An exclusive, monotonic timeout class.
7
- class Wait
8
- def self.for(duration, &block)
9
- if duration
10
- timeout = new(duration)
11
-
12
- timeout.while_time_remaining(&block)
13
- else
14
- loop do
15
- yield(nil)
16
- end
17
- end
18
- end
19
-
20
- def initialize(duration)
21
- @duration = duration
22
- @remaining = true
23
- end
24
-
25
- attr_reader :duration
26
- attr_reader :remaining
27
-
28
- # Yields while time remains for work to be done:
29
- def while_time_remaining
30
- @interval = Hitimes::Interval.new
31
- @interval.start
32
-
33
- yield @remaining while time_remaining?
34
- ensure
35
- @interval.stop
36
- @interval = nil
37
- end
38
-
39
- private
40
-
41
- def time_remaining?
42
- @remaining = (@duration - @interval.duration)
43
-
44
- @remaining > 0
45
- end
46
- end
11
+ # An exclusive, monotonic timeout class.
12
+ class Wait
13
+ def self.for(duration, &block)
14
+ if duration
15
+ timeout = new(duration)
16
+
17
+ timeout.while_time_remaining(&block)
18
+ else
19
+ loop do
20
+ yield(nil)
21
+ end
22
+ end
23
+ end
24
+
25
+ def initialize(duration)
26
+ @duration = duration
27
+ @remaining = true
28
+ end
29
+
30
+ attr_reader :duration
31
+ attr_reader :remaining
32
+
33
+ # Yields while time remains for work to be done:
34
+ def while_time_remaining
35
+ @interval = Interval.new
36
+ @interval.start
37
+
38
+ yield @remaining while time_remaining?
39
+ ensure
40
+ @interval.stop
41
+ @interval = nil
42
+ end
43
+
44
+ private
45
+
46
+ def time_remaining?
47
+ @remaining = (@duration - @interval.to_f)
48
+
49
+ @remaining > 0
50
+ end
51
+ end
47
52
  end
@@ -1,21 +1,38 @@
1
1
  # frozen_string_literal: true
2
+ #
3
+ # This file is part of the "timers" project and released under the MIT license.
4
+ #
5
+ # Copyright, 2018, by Samuel Williams. All rights reserved.
6
+ #
2
7
 
3
- require "coveralls"
4
- Coveralls.wear!
8
+ # Level of accuracy enforced by tests (50ms)
9
+ TIMER_QUANTUM = 0.05
10
+
11
+ if ENV['COVERAGE'] || ENV['TRAVIS']
12
+ begin
13
+ require 'simplecov'
14
+
15
+ SimpleCov.start do
16
+ add_filter "/spec/"
17
+ end
18
+
19
+ if ENV['TRAVIS']
20
+ require 'coveralls'
21
+ Coveralls.wear!
22
+ end
23
+ rescue LoadError
24
+ warn "Could not load simplecov: #{$!}"
25
+ end
26
+ end
5
27
 
6
28
  require "bundler/setup"
7
29
  require "timers"
8
30
 
9
- # Level of accuracy enforced by tests (50ms)
10
- TIMER_QUANTUM = 0.05
11
-
12
31
  RSpec.configure do |config|
13
- # Setting this config option `false` removes rspec-core's monkey patching of the
14
- # top level methods like `describe`, `shared_examples_for` and `shared_context`
15
- # on `main` and `Module`. The methods are always available through the `RSpec`
16
- # module like `RSpec.describe` regardless of this setting.
17
- # For backwards compatibility this defaults to `true`.
18
- #
19
- # https://relishapp.com/rspec/rspec-core/v/3-0/docs/configuration/global-namespace-dsl
20
- config.expose_dsl_globally = false
32
+ # Enable flags like --only-failures and --next-failure
33
+ config.example_status_persistence_file_path = ".rspec_status"
34
+
35
+ config.expect_with :rspec do |c|
36
+ c.syntax = :expect
37
+ end
21
38
  end