servolux 0.5.0 → 0.6.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.
data/History.txt CHANGED
@@ -1,6 +1,12 @@
1
+ == 0.6.0 / 2009-07-07
2
+
3
+ * 2 Minor Enhancements
4
+ * Threaded objects can be set to run only a given number of times
5
+ * Threaded objects can now continue on error
6
+
1
7
  == 0.5.0 / 2009-06-30
2
8
 
3
- * 2 Minor Enchancements
9
+ * 2 Minor Enhancements
4
10
  * Added tests for the Child class
5
11
  * Updating documentation in preperation for a release
6
12
 
@@ -57,17 +57,28 @@ module Servolux::Threaded
57
57
 
58
58
  before_starting if self.respond_to?(:before_starting)
59
59
  @activity_thread_running = true
60
+ @activity_thread_iterations = 0
60
61
  @activity_thread = Thread.new {
61
62
  begin
62
63
  loop {
63
- sleep interval if running?
64
- break unless running?
65
- run
64
+ begin
65
+ sleep interval if running?
66
+ break unless running?
67
+ run
68
+ @activity_thread_iterations += 1
69
+ break if finished_iterations?
70
+ rescue SystemExit; raise
71
+ rescue Exception => err
72
+ if continue_on_error?
73
+ logger.error err
74
+ else
75
+ logger.fatal err
76
+ raise err
77
+ end
78
+ end
66
79
  }
67
- rescue Exception => err
80
+ ensure
68
81
  @activity_thread_running = false
69
- logger.fatal err unless err.is_a?(SystemExit)
70
- raise err
71
82
  end
72
83
  }
73
84
  after_starting if self.respond_to?(:after_starting)
@@ -96,6 +107,20 @@ module Servolux::Threaded
96
107
  self
97
108
  end
98
109
 
110
+ # Wait on the activity thread. If the thread is already stopped, this
111
+ # method will return without taking any action. Otherwise, this method
112
+ # does not return until the activity thread has stopped, or a specific
113
+ # number of iterations has passed since this method was called.
114
+ #
115
+ def wait( limit = nil )
116
+ return self unless running?
117
+ start_waiting_iterations = self.iterations
118
+ loop {
119
+ break unless running?
120
+ break if limit and self.iterations > ( start_waiting_iterations + limit )
121
+ }
122
+ end
123
+
99
124
  # If the activity thread is running, the calling thread will suspend
100
125
  # execution and run the activity thread. This method does not return until
101
126
  # the activity thread is stopped or until _limit_ seconds have passed.
@@ -115,6 +140,16 @@ module Servolux::Threaded
115
140
  @activity_thread_running
116
141
  end
117
142
 
143
+ # Returns +true+ if the activity thread has finished its maximum
144
+ # number of iterations or the thread is no longer running.
145
+ # Returns +false+ otherwise.
146
+ #
147
+ def finished_iterations?
148
+ return true unless running?
149
+ return true if maximum_iterations and (iterations >= maximum_iterations)
150
+ return false
151
+ end
152
+
118
153
  # Returns the status of threaded object.
119
154
  #
120
155
  # 'sleep' : sleeping or waiting on I/O
@@ -142,7 +177,50 @@ module Servolux::Threaded
142
177
  # threaded object's 'run' method.
143
178
  #
144
179
  def interval
145
- @activity_thread_interval
180
+ @activity_thread_interval ||= 60
181
+ end
182
+
183
+ # Sets the maximum number of invocations of the threaded object's
184
+ # 'run' method
185
+ #
186
+ def maximum_iterations=( value )
187
+ raise ArgumentError, "maximum iterations must be >= 1" unless value.to_i >= 1
188
+ @activity_thread_maximum_iterations = value.to_i
189
+ end
190
+
191
+ # Returns the maximum number of invocations of the threaded
192
+ # object's 'run' method
193
+ #
194
+ def maximum_iterations
195
+ return unless defined? @activity_thread_maximum_iterations
196
+ @activity_thread_maximum_iterations
197
+ end
198
+
199
+ # Returns the number of iterations of the threaded object's 'run' method
200
+ # completed thus far.
201
+ #
202
+ def iterations
203
+ @activity_thread_iterations ||= 0
204
+ end
205
+
206
+ # Set to +true+ to continue running the threaded object even if an error
207
+ # is raised by the +run+ method. The default behavior is to stop the
208
+ # activity thread when an error is raised by the run method.
209
+ #
210
+ # A SystemExit will never be caught; it will always cause the Ruby
211
+ # interpreter to exit.
212
+ #
213
+ def continue_on_error=( value )
214
+ @activity_thread_continue_on_error = (value ? true : false)
215
+ end
216
+
217
+ # Returns +true+ if the threded object should continue running even if an
218
+ # error is raised by the run method. The default is to return +false+. The
219
+ # threaded object will stop running when an error is raised.
220
+ #
221
+ def continue_on_error?
222
+ return @activity_thread_continue_on_error if defined? @activity_thread_continue_on_error
223
+ @activity_thread_continue_on_error = false
146
224
  end
147
225
 
148
226
  # :stopdoc:
data/lib/servolux.rb CHANGED
@@ -4,7 +4,7 @@ require 'logging'
4
4
  module Servolux
5
5
 
6
6
  # :stopdoc:
7
- VERSION = '0.5.0'
7
+ VERSION = '0.6.0'
8
8
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
9
9
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
10
10
  # :startdoc:
@@ -90,6 +90,32 @@ describe Servolux::Threaded do
90
90
  lambda { obj.join }.should raise_error(RuntimeError, 'ni')
91
91
  end
92
92
 
93
+ it "lives if told to continue on error" do
94
+ klass = Class.new(base) do
95
+ def run()
96
+ @sleep ||= false
97
+ if @sleep then sleep
98
+ else
99
+ @sleep = true
100
+ raise 'ni'
101
+ end
102
+ end
103
+ end
104
+
105
+ obj = klass.new
106
+ obj.continue_on_error = true
107
+
108
+ obj.start
109
+ obj.pass
110
+
111
+ obj.running?.should be_true
112
+ @log_output.readline
113
+ @log_output.readline.chomp.should == "ERROR Object : <RuntimeError> ni"
114
+
115
+ obj.stop(2)
116
+ obj.running?.should be_false
117
+ end
118
+
93
119
  it "complains loudly if you don't have a run method" do
94
120
  obj = base.new
95
121
  obj.start
@@ -100,6 +126,23 @@ describe Servolux::Threaded do
100
126
 
101
127
  lambda { obj.join }.should raise_error(NotImplementedError, 'The run method must be defined by the threaded object.')
102
128
  end
129
+
130
+ it "stops after a limited number of iterations" do
131
+ klass = Class.new( base ) do
132
+ def run() ; end
133
+ end
134
+ obj = klass.new
135
+ obj.maximum_iterations = 5
136
+ obj.iterations.should == 0
137
+ obj.start
138
+ obj.wait
139
+ obj.iterations.should == 5
140
+ end
141
+
142
+ it "complains loudly if you attempt to set a maximum number of iterations < 1" do
143
+ obj = base.new
144
+ lambda { obj.maximum_iterations = -1 }.should raise_error( ArgumentError, "maximum iterations must be >= 1" )
145
+ end
103
146
  end
104
147
 
105
148
  # EOF
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: servolux
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Pease
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-30 00:00:00 -06:00
12
+ date: 2009-07-07 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency