rufus-scheduler 2.0.11 → 2.0.12

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/CHANGELOG.txt CHANGED
@@ -2,6 +2,13 @@
2
2
  = rufus-scheduler CHANGELOG.txt
3
3
 
4
4
 
5
+ == rufus-scheduler - 2.0.12 released 2011/10/28
6
+
7
+ - hardened exception handling. Thanks Sam Gibson
8
+ - accepting #handle_exception, #log_exception or #on_exception
9
+ - scheduler.in '1s', :mutex => 'that_mutex_name'
10
+
11
+
5
12
  == rufus-scheduler - 2.0.11 released 2011/09/30
6
13
 
7
14
  - require 'rufus-scheduler' works
data/CREDITS.txt CHANGED
@@ -14,6 +14,7 @@
14
14
 
15
15
  == Feedback
16
16
 
17
+ - Sam Gibson - https://github.com/samfoo - exception handling hardening
17
18
  - sha1dy - https://github.com/sha1dy - every and overlapping exception issue
18
19
  - Defusal - unschedule_by_tag
19
20
  - pickerel - https://github.com/pickerel
data/README.rdoc CHANGED
@@ -174,25 +174,82 @@ Jobs scheduled with the :blocking parameter will run in the thread of the schedu
174
174
 
175
175
  Hence, our espresso will come in 22 minutes instead of 21.
176
176
 
177
+ Warning, 'cron' behaves a bit differently than 'in' and 'at', if the scheduler is blocked working on a task, it may skip crons (while ins and ats get scheduled after).
178
+
179
+ scheduler.cron '0 16 * * * *' do
180
+ puts "four o'clock tea"
181
+ end
182
+
183
+ If at 4pm the scheduler is in a blocking task, there will be no four o'clock tea.
184
+
185
+
186
+ == :mutex => 'that_mutex'
187
+
188
+ :blocking is nice but it is blocking the whole scheduler. What about something more fine-grained ? And also something that can be used with in, at, every and cron ?
189
+
190
+ scheduler.in '20m', :mutex => 'that_mutex' do
191
+ puts "order ristretto"
192
+ sleep 2 * 60
193
+ puts "ah, that was delicious"
194
+ end
195
+ scheduler.in '21m' :mutex => 'that_mutex' do
196
+ puts "order espresso"
197
+ end
198
+
199
+ the "order espresso" will only get triggered once the ristretto has been consumed. Rufus-scheduler, will create a 'that_mutex' mutex and keep track of it. Don't go on passing too many different mutex names, rufus-scheduler will keep track of each of them (they won't get garbage collected).
200
+
201
+ It's OK to use a mutex directly:
202
+
203
+ m = Mutex.new
204
+ # ...
205
+ scheduler.cron '0 18 * * *', :mutex => m do
206
+ # ...
207
+ end
208
+ scheduler.in '21m' :mutex => m do
209
+ # ...
210
+ end
211
+
212
+ It can be handy for even more fine-grained control:
213
+
214
+ m = Mutex.new
215
+ # ...
216
+ scheduler.cron '0 18 * * *', :mutex => m do
217
+ # ...
218
+ end
219
+ scheduler.in '21m' do
220
+ # non-critical
221
+ m.synchronize do
222
+ # critical
223
+ end
224
+ # non-critical
225
+ end
226
+
177
227
 
178
228
  == :allow_overlapping => false
179
229
 
180
- By default, every and cron jobs will "overlap" :
230
+ By default, every and cron jobs will "overlap":
181
231
 
182
232
  scheduler.every '3s' do
183
- 4.times do
184
- puts "hello!"
233
+ 4.times do |i|
234
+ puts "hello #{i}"
185
235
  sleep 1
186
236
  end
187
237
  end
188
238
 
189
- This every job, will have overlaps. To prevent that :
239
+ You mind end up with something that looks like
240
+
241
+ hello 0
242
+ hello 1
243
+ hello 2
244
+ hello 3
245
+ hello 3
246
+ hello 4
247
+ ...
248
+
249
+ This every job, will have overlaps. To prevent that:
190
250
 
191
251
  scheduler.every '3s', :allow_overlapping => false do
192
- 4.times do
193
- puts "hello!"
194
- sleep 1
195
- end
252
+ # ...
196
253
  end
197
254
 
198
255
 
@@ -347,6 +404,17 @@ It's easy to customize that behaviour :
347
404
  puts "job #{job.job_id} caught exception '#{exception}'"
348
405
  end
349
406
 
407
+ These are OK too:
408
+
409
+ def scheduler.on_exception(job, exception)
410
+ puts "job #{job.job_id} caught exception '#{exception}'"
411
+ end
412
+
413
+ # or
414
+
415
+ def scheduler.on_exception(exception)
416
+ puts "caught exception '#{exception}'"
417
+
350
418
  For backward compatibility, overriding #log_exception is still OK :
351
419
 
352
420
  def scheduler.log_exception(exception)
@@ -398,8 +466,7 @@ https://github.com/jmettraux/rufus-scheduler/issues/issue/10
398
466
  == tested with
399
467
 
400
468
  * 1.8.7-p249
401
- * 1.9.1-p378
402
- * 1.9.2-p0
469
+ * 1.9.2-p290
403
470
  * jruby-1.5.1
404
471
 
405
472
  on Mac OS X (Snow Leopard).
data/lib/rufus/sc/jobs.rb CHANGED
@@ -133,7 +133,7 @@ module Scheduler
133
133
 
134
134
  @running = true
135
135
 
136
- @scheduler.send(:trigger_job, @params[:blocking]) do
136
+ @scheduler.send(:trigger_job, @params) do
137
137
  #
138
138
  # Note that #trigger_job is protected, hence the #send
139
139
  # (Only jobs know about this method of the scheduler)
@@ -153,7 +153,7 @@ module Scheduler
153
153
 
154
154
  rescue Exception => e
155
155
 
156
- @scheduler.handle_exception(self, e)
156
+ @scheduler.do_handle_exception(self, e)
157
157
  end
158
158
 
159
159
  @running = false
@@ -105,6 +105,8 @@ module Rufus::Scheduler
105
105
  @cron_jobs = get_queue(:cron, opts)
106
106
 
107
107
  @frequency = @options[:frequency] || 0.330
108
+
109
+ @mutexes = {}
108
110
  end
109
111
 
110
112
  # Instantiates and starts a new Rufus::Scheduler.
@@ -198,25 +200,42 @@ module Rufus::Scheduler
198
200
  # MISC
199
201
  #++
200
202
 
201
- # Feel free to override this method. The default implementation simply
202
- # outputs the error message to STDOUT
203
+ # Determines if there is #log_exception, #handle_exception or #on_exception
204
+ # method. If yes, hands the exception to it, else defaults to outputting
205
+ # details to $stderr.
203
206
  #
204
- def handle_exception(job, exception)
207
+ def do_handle_exception(job, exception)
205
208
 
206
- if self.respond_to?(:log_exception)
207
- #
208
- # some kind of backward compatibility
209
+ begin
209
210
 
210
- log_exception(exception)
211
+ [ :log_exception, :handle_exception, :on_exception ].each do |m|
211
212
 
212
- else
213
+ next unless self.respond_to?(m)
214
+
215
+ if method(m).arity == 1
216
+ self.send(m, exception)
217
+ else
218
+ self.send(m, job, exception)
219
+ end
220
+
221
+ return
222
+ # exception was handled successfully
223
+ end
213
224
 
214
- puts '=' * 80
215
- puts "scheduler caught exception :"
216
- puts exception
217
- exception.backtrace.each { |l| puts l }
218
- puts '=' * 80
225
+ rescue Exception => e
226
+
227
+ $stderr.puts '*' * 80
228
+ $stderr.puts 'the exception handling method itself had an issue:'
229
+ $stderr.puts e
230
+ $stderr.puts *e.backtrace
231
+ $stderr.puts '*' * 80
219
232
  end
233
+
234
+ $stderr.puts '=' * 80
235
+ $stderr.puts 'scheduler caught exception:'
236
+ $stderr.puts exception
237
+ $stderr.puts *exception.backtrace
238
+ $stderr.puts '=' * 80
220
239
  end
221
240
 
222
241
  #--
@@ -339,10 +358,13 @@ module Rufus::Scheduler
339
358
  # TODO : clarify, the blocking here blocks the whole scheduler, while
340
359
  # EmScheduler blocking triggers for the next tick. Not the same thing ...
341
360
  #
342
- def trigger_job(blocking, &block)
361
+ def trigger_job(params, &block)
343
362
 
344
- if blocking
363
+ if params[:blocking]
345
364
  block.call
365
+ elsif m = params[:mutex]
366
+ m = (@mutexes[m.to_s] ||= Mutex.new) unless m.is_a?(Mutex)
367
+ Thread.new { m.synchronize { block.call } }
346
368
  else
347
369
  Thread.new { block.call }
348
370
  end
@@ -471,14 +493,20 @@ module Rufus::Scheduler
471
493
  # If 'blocking' is set to true, the block will get called at the
472
494
  # 'next_tick'. Else the block will get called via 'defer' (own thread).
473
495
  #
474
- def trigger_job(blocking, &block)
496
+ def trigger_job(params, &block)
475
497
 
476
- m = blocking ? :next_tick : :defer
477
- #
478
- # :next_tick monopolizes the EM
479
- # :defer executes its block in another thread
498
+ # :next_tick monopolizes the EM
499
+ # :defer executes its block in another thread
500
+ # (if I read the doc carefully...)
480
501
 
481
- EM.send(m) { block.call }
502
+ if params[:blocking]
503
+ EM.next_tick { block.call }
504
+ elsif m = params[:mutex]
505
+ m = (@mutexes[m.to_s] ||= Mutex.new) unless m.is_a?(Mutex)
506
+ EM.defer { m.synchronize { block.call } }
507
+ else
508
+ EM.defer { block.call }
509
+ end
482
510
  end
483
511
  end
484
512
 
@@ -26,7 +26,7 @@
26
26
  module Rufus
27
27
  module Scheduler
28
28
 
29
- VERSION = '2.0.11'
29
+ VERSION = '2.0.12'
30
30
  end
31
31
  end
32
32
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2006-2010, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2006-2011, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
data/release.txt ADDED
@@ -0,0 +1,9 @@
1
+ Rufus-scheduler is a thread-based scheduler written in Ruby. It lets you write code like
2
+
3
+ [sourcecode language="ruby"]
4
+ Rufus::Scheduler.start
5
+
6
+ Rufus::Scheduler.every '10m' do
7
+ end
8
+ [/sourcecode]
9
+
@@ -28,7 +28,7 @@ job scheduler for Ruby (at, cron, in and every jobs).
28
28
  s.add_runtime_dependency 'tzinfo', '>= 0.3.23'
29
29
 
30
30
  s.add_development_dependency 'rake'
31
- s.add_development_dependency 'rspec', '>= 2.0'
31
+ s.add_development_dependency 'rspec', '>= 2.7.0'
32
32
 
33
33
  s.require_path = 'lib'
34
34
  end
data/spec/at_in_spec.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # Sun Mar 22 16:47:28 JST 2009
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), 'spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe SCHEDULER_CLASS do
data/spec/at_spec.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # Sat Mar 21 20:19:30 JST 2009
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), 'spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe "#{SCHEDULER_CLASS}#schedule_at" do
@@ -5,7 +5,7 @@
5
5
  # Sat Mar 21 17:36:36 JST 2009
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), 'spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe SCHEDULER_CLASS do
@@ -29,26 +29,32 @@ describe SCHEDULER_CLASS do
29
29
  end
30
30
  end
31
31
 
32
- it "doesn't block when :blocking => nil" do
32
+ context ':blocking => nil' do
33
33
 
34
- $var = []
35
- @s.in('1s') { JOB.call(1) }
36
- @s.in('1s') { JOB.call(2) }
34
+ it "doesn't block" do
37
35
 
38
- sleep 5.0
36
+ $var = []
37
+ @s.in('1s') { JOB.call(1) }
38
+ @s.in('1s') { JOB.call(2) }
39
39
 
40
- [ %w{ a1 a2 b1 b2 }, %w{ a1 a2 b2 b1 } ].should include($var)
40
+ sleep 5.0
41
+
42
+ [ %w{ a1 a2 b1 b2 }, %w{ a1 a2 b2 b1 } ].should include($var)
43
+ end
41
44
  end
42
45
 
43
- it 'blocks when :blocking => true' do
46
+ context ':blocking => true' do
44
47
 
45
- $var = []
46
- @s.in('1s', :blocking => true) { JOB.call(8) }
47
- @s.in('1s', :blocking => true) { JOB.call(9) }
48
+ it 'blocks' do
48
49
 
49
- sleep 4.5
50
+ $var = []
51
+ @s.in('1s', :blocking => true) { JOB.call(8) }
52
+ @s.in('1s', :blocking => true) { JOB.call(9) }
50
53
 
51
- $var.should == %w[ a8 b8 a9 b9 ]
54
+ sleep 4.5
55
+
56
+ $var.should == %w[ a8 b8 a9 b9 ]
57
+ end
52
58
  end
53
59
  end
54
60
 
data/spec/cron_spec.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # Sun Mar 22 19:59:12 JST 2009
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), 'spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe "#{SCHEDULER_CLASS}#cron" do
@@ -5,7 +5,7 @@
5
5
  # Sat Mar 21 12:55:27 JST 2009
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), 'spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe Rufus::CronLine do
data/spec/every_spec.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # Sun Mar 22 12:26:07 JST 2009
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), 'spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe "#{SCHEDULER_CLASS}#every" do
@@ -5,7 +5,7 @@
5
5
  # Mon May 4 17:07:17 JST 2009
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), '/spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe SCHEDULER_CLASS do
@@ -17,13 +17,13 @@ describe SCHEDULER_CLASS do
17
17
  stop_scheduler(@s)
18
18
  end
19
19
 
20
- it 'emits exception messages to stdout' do
20
+ it 'emits exception messages to stderr' do
21
21
 
22
22
  require 'stringio' unless defined?(StringIO) # ruby 1.9
23
23
 
24
- stdout = $stdout
24
+ stderr = $stderr
25
25
  s = StringIO.new
26
- $stdout = s
26
+ $stderr = s
27
27
 
28
28
  @s.in 0.400 do
29
29
  raise 'Houston we have a problem'
@@ -31,7 +31,7 @@ describe SCHEDULER_CLASS do
31
31
 
32
32
  sleep 0.500
33
33
  sleep 0.500
34
- $stdout = stdout
34
+ $stderr = stderr
35
35
  s.close
36
36
 
37
37
  s.string.should match(/Houston we have a problem/)
@@ -55,7 +55,7 @@ describe SCHEDULER_CLASS do
55
55
  $job.class.should == Rufus::Scheduler::InJob
56
56
  end
57
57
 
58
- it 'accepts overriding #log_exception' do
58
+ it 'accepts defining #log_exception' do
59
59
 
60
60
  $e = nil
61
61
 
@@ -72,5 +72,26 @@ describe SCHEDULER_CLASS do
72
72
 
73
73
  $e.to_s.should == 'Houston we have a problem'
74
74
  end
75
+
76
+ it 'accepts defining #on_exception' do
77
+
78
+ $j = nil
79
+ $e = nil
80
+
81
+ def @s.on_exception(j, e)
82
+ $j = j
83
+ $e = e
84
+ end
85
+
86
+ @s.in 0.400 do
87
+ raise 'Houston we have a problem'
88
+ end
89
+
90
+ sleep 0.500
91
+ sleep 0.500
92
+
93
+ $j.class.should == Rufus::Scheduler::InJob
94
+ $e.to_s.should == 'Houston we have a problem'
95
+ end
75
96
  end
76
97
 
data/spec/in_spec.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # Sat Mar 21 17:36:36 JST 2009
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), 'spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe "#{SCHEDULER_CLASS}#in" do
data/spec/job_spec.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # Wed Apr 27 00:51:07 JST 2011
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), 'spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe 'job classes' do
@@ -0,0 +1,93 @@
1
+
2
+ #
3
+ # Specifying rufus-scheduler
4
+ #
5
+ # Fri Oct 7 17:30:45 JST 2011
6
+ #
7
+
8
+ require 'spec_base'
9
+
10
+
11
+ describe SCHEDULER_CLASS do
12
+
13
+ before(:each) do
14
+ @s = start_scheduler
15
+ end
16
+ after(:each) do
17
+ stop_scheduler(@s)
18
+ end
19
+
20
+ MJOB = Proc.new do |x|
21
+ begin
22
+ $var << "in#{x}"
23
+ sleep 0.500
24
+ $var << "out#{x}"
25
+ rescue Exception => e
26
+ puts '=' * 80
27
+ p e
28
+ puts '=' * 80
29
+ end
30
+ end
31
+
32
+ context ':mutex => String' do
33
+
34
+ it 'prevents overlapping' do
35
+
36
+ $var = ''
37
+
38
+ @s.in('1s', :mutex => 'toto') { MJOB.call(0) }
39
+ @s.in('1s', :mutex => 'toto') { MJOB.call(1) }
40
+
41
+ sleep 3.0
42
+
43
+ %w[ in0out0in1out1 in1out1in0out0 ].should include($var)
44
+ end
45
+
46
+ it 'creates a new mutex when the name is first encountered' do
47
+
48
+ @s.instance_variable_get(:@mutexes).size.should == 0
49
+
50
+ @s.in('1s', :mutex => 'fruit') { sleep 0.1 }
51
+
52
+ sleep 1.5
53
+
54
+ @s.instance_variable_get(:@mutexes).size.should == 1
55
+ end
56
+
57
+ it 'creates a unique mutex for a given name' do
58
+
59
+ @s.in('1s', :mutex => 'gum') { sleep 0.1 }
60
+ @s.in('1s', :mutex => 'gum') { sleep 0.1 }
61
+
62
+ sleep 1.5
63
+
64
+ @s.instance_variable_get(:@mutexes).size.should == 1
65
+ end
66
+ end
67
+
68
+ context ':mutex => Mutex' do
69
+
70
+ it 'prevents overlapping' do
71
+
72
+ $var = ''
73
+ m = Mutex.new
74
+
75
+ @s.in('1s', :mutex => m) { MJOB.call(0) }
76
+ @s.in('1s', :mutex => m) { MJOB.call(1) }
77
+
78
+ sleep 3.0
79
+
80
+ %w[ in0out0in1out1 in1out1in0out0 ].should include($var)
81
+ end
82
+
83
+ it 'does not register the mutex' do
84
+
85
+ @s.in('1s', :mutex => Mutex.new) { sleep 0.1 }
86
+
87
+ sleep 1.5
88
+
89
+ @s.instance_variable_get(:@mutexes).size.should == 0
90
+ end
91
+ end
92
+ end
93
+
data/spec/rtime_spec.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # Fri Mar 20 23:46:32 JST 2009
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), 'spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe 'rufus/otime' do
@@ -5,7 +5,7 @@
5
5
  # Tue May 5 14:47:16 JST 2009
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), '/spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe Rufus::Scheduler::Schedulable do
@@ -5,7 +5,7 @@
5
5
  # Sat Mar 21 17:43:23 JST 2009
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), 'spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe SCHEDULER_CLASS do
data/spec/spec_base.rb CHANGED
@@ -5,12 +5,15 @@
5
5
  # Fri Mar 20 22:53:33 JST 2009
6
6
  #
7
7
 
8
- $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
8
+ $:.unshift(File.expand_path('../../lib', __FILE__))
9
9
 
10
10
  require 'rubygems'
11
11
  require 'fileutils'
12
12
 
13
13
 
14
+ Thread.abort_on_exception = true
15
+
16
+
14
17
  #$:.unshift(File.expand_path('~/tmp/bacon/lib')) # my own bacon for a while
15
18
  #require 'bacon'
16
19
  #puts
@@ -22,7 +25,7 @@ require 'fileutils'
22
25
 
23
26
  # EM or plain ?
24
27
 
25
- $plain = ! ARGV.include?('--em')
28
+ $plain = ! ENV['EVENTMACHINE']
26
29
 
27
30
  require 'rufus/scheduler'
28
31
 
@@ -64,12 +67,12 @@ def stop_scheduler(s)
64
67
  end
65
68
 
66
69
  def wait_next_tick
67
- if defined?(EM)
68
- t = Thread.current
69
- EM.next_tick { t.wakeup }
70
- Thread.stop
71
- else
72
- sleep 0.500
73
- end
70
+ #if defined?(EM)
71
+ # t = Thread.current
72
+ # EM.next_tick { t.wakeup }
73
+ # Thread.stop
74
+ #else
75
+ sleep 0.500
76
+ #end
74
77
  end
75
78
 
@@ -3,7 +3,7 @@
3
3
  # a spec by Klaas Jan Wierenga
4
4
  #
5
5
 
6
- require File.join(File.dirname(__FILE__), '/spec_base')
6
+ require 'spec_base'
7
7
 
8
8
 
9
9
 
data/spec/timeout_spec.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # Sun May 3 15:44:28 JST 2009
6
6
  #
7
7
 
8
- require File.join(File.dirname(__FILE__), '/spec_base')
8
+ require 'spec_base'
9
9
 
10
10
 
11
11
  describe "#{SCHEDULER_CLASS} timeouts" do
@@ -94,10 +94,10 @@ describe "#{SCHEDULER_CLASS} timeouts" do
94
94
  end
95
95
  end
96
96
 
97
- sleep 5
97
+ sleep 5.5
98
98
 
99
99
  timeouts.size.should == 3
100
- timeouts.each { |to| (to * 10).to_i.should == 16 }
100
+ timeouts.each { |to| to.should be_within(0.5).of(1.5) }
101
101
  end
102
102
 
103
103
  it 'points to their "parent" job' do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rufus-scheduler
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
8
  - 0
9
- - 11
10
- version: 2.0.11
9
+ - 12
10
+ version: 2.0.12
11
11
  platform: ruby
12
12
  authors:
13
13
  - John Mettraux
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-30 00:00:00 +09:00
18
+ date: 2011-10-28 00:00:00 +09:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -56,11 +56,12 @@ dependencies:
56
56
  requirements:
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- hash: 3
59
+ hash: 19
60
60
  segments:
61
61
  - 2
62
+ - 7
62
63
  - 0
63
- version: "2.0"
64
+ version: 2.7.0
64
65
  type: :development
65
66
  version_requirements: *id003
66
67
  description: job scheduler for Ruby (at, cron, in and every jobs).
@@ -92,6 +93,7 @@ files:
92
93
  - spec/exception_spec.rb
93
94
  - spec/in_spec.rb
94
95
  - spec/job_spec.rb
96
+ - spec/mutex_spec.rb
95
97
  - spec/rtime_spec.rb
96
98
  - spec/schedulable_spec.rb
97
99
  - spec/scheduler_spec.rb
@@ -105,6 +107,7 @@ files:
105
107
  - CREDITS.txt
106
108
  - dump.txt
107
109
  - LICENSE.txt
110
+ - release.txt
108
111
  - t.txt
109
112
  - TODO.txt
110
113
  - README.rdoc