rufus-scheduler 2.0.6 → 2.0.7

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.
@@ -0,0 +1,2 @@
1
+ .rvmrc
2
+ rdoc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
@@ -2,6 +2,12 @@
2
2
  = rufus-scheduler CHANGELOG.txt
3
3
 
4
4
 
5
+ == rufus-scheduler - 2.0.7 released 2010/11/09
6
+
7
+ - cron and timezones, thanks Tanzeeb Khalili
8
+ - Scheduler#trigger_threads, thanks Tim Uckun
9
+
10
+
5
11
  == rufus-scheduler - 2.0.6 released 2010/05/01
6
12
 
7
13
  - timeout jobs not outliving their parent job anymore, thanks Joel Wood
@@ -4,6 +4,8 @@
4
4
 
5
5
  == Contributors
6
6
 
7
+ - Tanzeeb Khalili (http://github.com/tanzeeb) cron and timezones
8
+ - Adam Davies (http://github.com/adz), @allow_overlap = false
7
9
  - Klaas Jan Wierenga, at/every/in stress tests (1.0 and 2.0)
8
10
  - TobyH (http://github.com/tobyh), faster and cleaner CronLine#next_time
9
11
 
@@ -10,13 +10,14 @@ rufus-scheduler is no replacement for cron/at since it runs inside of Ruby.
10
10
 
11
11
  A list of related Ruby projects :
12
12
 
13
- http://github.com/javan/whenever
14
- http://github.com/yakischloba/em-timers/
13
+ * http://github.com/javan/whenever
14
+ * http://github.com/yakischloba/em-timers
15
+ * http://github.com/adamwiggins/clockwork
15
16
 
16
17
  More like complements :
17
18
 
18
- http://github.com/mojombo/chronic/
19
- http://github.com/hpoydar/chronic_duration
19
+ * http://github.com/mojombo/chronic
20
+ * http://github.com/hpoydar/chronic_duration
20
21
 
21
22
 
22
23
  == installation
@@ -69,6 +70,32 @@ Note that is there is EventMachine present and running,
69
70
  will return an instance of Rufus::Scheduler::EmScheduler (leveraging EventMachine).
70
71
 
71
72
 
73
+ == a note about cron jobs
74
+
75
+ This is a classical cron :
76
+
77
+ scheduler.cron '0 22 * * 1-5' do
78
+ # every day of the week at 22:00 (10pm)
79
+ end
80
+
81
+ Rufus-scheduler supports two variants to that notation : seconds and timezones.
82
+
83
+ scheduler.cron '13 0 22 * * 1-5' do
84
+ # every day of the week at 22:00:13
85
+ end
86
+
87
+ scheduler.cron '0 22 * * 1-5 Europe/Paris' do
88
+ # every day of the week when it's 22:00 in Paris
89
+ end
90
+ scheduler.cron '0 22 * * 1-5 Etc/GMT+2' do
91
+ # every day of the week when it's 22:00 in GMT+2
92
+ end
93
+
94
+ The timezones are the ones supported by the 'tzinfo' rubygem (http://tzinfo.rubyforge.org/).
95
+
96
+ The timezone support was contributed by Tanzeeb Khalili.
97
+
98
+
72
99
  == scheduler.join
73
100
 
74
101
  Note that if you have a tiny script like this one :
@@ -187,10 +214,10 @@ In this example, the 'every' job will unschedule itself when the crop is ready.
187
214
  Sometimes passing a block isn't that convenient :
188
215
 
189
216
  class JobThing
190
- def initialize (relevant_info)
217
+ def initialize(relevant_info)
191
218
  @ri = relevant_info
192
219
  end
193
- def call (job)
220
+ def call(job)
194
221
  do_something_about_it
195
222
  end
196
223
  end
@@ -205,7 +232,7 @@ rufus-scheduler accepts anything that responds to a call method with a unique pa
205
232
  For compatibility with older (1.x) versions, schedulables with a trigger methods are accepted :
206
233
 
207
234
  class JobThing
208
- def trigger (params)
235
+ def trigger(params)
209
236
  job = params[:job]
210
237
  end
211
238
  end
@@ -287,13 +314,13 @@ It's easy to customize that behaviour :
287
314
  # or
288
315
  #scheduler = Rufus::Scheduler::EmScheduler.start_new
289
316
 
290
- def scheduler.handle_exception (job, exception)
317
+ def scheduler.handle_exception(job, exception)
291
318
  puts "job #{job.job_id} caught exception '#{exception}'"
292
319
  end
293
320
 
294
321
  For backward compatibility, overriding #log_exception is still OK :
295
322
 
296
- def scheduler.log_exception (exception)
323
+ def scheduler.log_exception(exception)
297
324
  puts "caught exception '#{exception}'"
298
325
  end
299
326
 
@@ -334,13 +361,19 @@ More and more ruby applications are using EventMachine. This flavour of the sche
334
361
 
335
362
  == tested with
336
363
 
337
- ruby 1.8.6, ruby 1.9.1p0
338
- on jruby 1.2.0 it has some tiny issues (spec/blocking_spec.rb)
364
+ * 1.8.7-p249
365
+ * 1.9.1-p378
366
+ * 1.9.2-p0
367
+ * jruby-1.5.1
368
+
369
+ on Mac OS X (Snow Leopard).
339
370
 
340
371
 
341
372
  == dependencies
342
373
 
343
- the ruby gem 'eventmachine' if you use Rufus::Scheduler::EmScheduler, else no other dependencies.
374
+ The 'tzinfo' rubygem.
375
+
376
+ The ruby gem 'eventmachine' if you use Rufus::Scheduler::EmScheduler, else no other dependencies.
344
377
 
345
378
 
346
379
  == mailing list
data/Rakefile CHANGED
@@ -10,8 +10,18 @@ load 'lib/rufus/sc/version.rb'
10
10
  # CLEAN
11
11
 
12
12
  require 'rake/clean'
13
- CLEAN.include('pkg', 'tmp', 'html')
14
- task :default => [ :clean ]
13
+ CLEAN.include('pkg', 'tmp', 'rdoc')
14
+
15
+
16
+ #
17
+ # TEST / SPEC
18
+
19
+ task :spec do
20
+ sh 'rspec spec/'
21
+ end
22
+ task :test => :spec
23
+
24
+ task :default => :spec
15
25
 
16
26
 
17
27
  #
@@ -35,12 +45,11 @@ Jeweler::Tasks.new do |gem|
35
45
  gem.authors = [ 'John Mettraux' ]
36
46
  gem.rubyforge_project = 'rufus'
37
47
 
38
- gem.test_file = 'spec/spec.rb'
48
+ #gem.test_file = 'spec/spec.rb'
39
49
 
40
- #gem.add_dependency 'yajl-ruby'
50
+ gem.add_dependency 'tzinfo'
41
51
  gem.add_development_dependency 'rake'
42
- gem.add_development_dependency 'yard'
43
- gem.add_development_dependency 'bacon'
52
+ gem.add_development_dependency 'rspec'
44
53
  gem.add_development_dependency 'jeweler'
45
54
 
46
55
  # gemspec spec : http://www.rubygems.org/read/chapter/20
@@ -51,33 +60,29 @@ Jeweler::GemcutterTasks.new
51
60
  #
52
61
  # DOC
53
62
 
54
- begin
55
-
56
- require 'yard'
57
-
58
- YARD::Rake::YardocTask.new do |doc|
59
- doc.options = [
60
- '-o', 'html/rufus-scheduler', '--title',
61
- "rufus-scheduler #{Rufus::Scheduler::VERSION}"
62
- ]
63
- end
63
+ #
64
+ # make sure to have rdoc 2.5.x to run that
65
+ #
66
+ require 'rake/rdoctask'
67
+ Rake::RDocTask.new do |rd|
64
68
 
65
- rescue LoadError
69
+ rd.main = 'README.rdoc'
70
+ rd.rdoc_dir = 'rdoc/rufus-scheduler'
71
+ rd.title = "rufus-scheduler #{Rufus::Scheduler::VERSION}"
66
72
 
67
- task :yard do
68
- abort "YARD is not available : sudo gem install yard"
69
- end
73
+ rd.rdoc_files.include(
74
+ 'README.rdoc', 'CHANGELOG.txt', 'LICENSE.txt', 'CREDITS.txt', 'lib/**/*.rb')
70
75
  end
71
76
 
72
77
 
73
78
  #
74
79
  # TO THE WEB
75
80
 
76
- task :upload_website => [ :clean, :yard ] do
81
+ task :upload_rdoc => [ :clean, :rdoc ] do
77
82
 
78
83
  account = 'jmettraux@rubyforge.org'
79
84
  webdir = '/var/www/gforge-projects/rufus'
80
85
 
81
- sh "rsync -azv -e ssh html/rufus-scheduler #{account}:#{webdir}/"
86
+ sh "rsync -azv -e ssh rdoc/rufus-scheduler #{account}:#{webdir}/"
82
87
  end
83
88
 
@@ -22,6 +22,8 @@
22
22
  # Made in Japan.
23
23
  #++
24
24
 
25
+ require 'tzinfo'
26
+
25
27
 
26
28
  module Rufus
27
29
 
@@ -31,20 +33,19 @@ module Rufus
31
33
  #
32
34
  class CronLine
33
35
 
34
- #
35
36
  # The string used for creating this cronline instance.
36
37
  #
37
38
  attr_reader :original
38
39
 
39
- attr_reader \
40
- :seconds,
41
- :minutes,
42
- :hours,
43
- :days,
44
- :months,
45
- :weekdays
40
+ attr_reader :seconds
41
+ attr_reader :minutes
42
+ attr_reader :hours
43
+ attr_reader :days
44
+ attr_reader :months
45
+ attr_reader :weekdays
46
+ attr_reader :timezone
46
47
 
47
- def initialize (line)
48
+ def initialize(line)
48
49
 
49
50
  super()
50
51
 
@@ -52,10 +53,12 @@ module Rufus
52
53
 
53
54
  items = line.split
54
55
 
55
- unless items.length == 5 or items.length == 6
56
- raise(
57
- "cron '#{line}' string should hold 5 or 6 items, not #{items.length}")
58
- end
56
+ @timezone = (TZInfo::Timezone.get(items.last) rescue nil)
57
+ items.pop if @timezone
58
+
59
+ raise ArgumentError.new(
60
+ "not a valid cronline : '#{line}'"
61
+ ) unless items.length == 5 or items.length == 6
59
62
 
60
63
  offset = items.length - 5
61
64
 
@@ -67,13 +70,14 @@ module Rufus
67
70
  @weekdays = parse_weekdays(items[4 + offset])
68
71
  end
69
72
 
70
- #
71
73
  # Returns true if the given time matches this cron line.
72
74
  #
73
- def matches? (time)
75
+ def matches?(time)
74
76
 
75
77
  time = Time.at(time) unless time.kind_of?(Time)
76
78
 
79
+ time = @timezone.utc_to_local(time.getutc) if @timezone
80
+
77
81
  return false unless sub_match?(time.sec, @seconds)
78
82
  return false unless sub_match?(time.min, @minutes)
79
83
  return false unless sub_match?(time.hour, @hours)
@@ -83,17 +87,6 @@ module Rufus
83
87
  true
84
88
  end
85
89
 
86
- #
87
- # Returns an array of 6 arrays (seconds, minutes, hours, days,
88
- # months, weekdays).
89
- # This method is used by the cronline unit tests.
90
- #
91
- def to_array
92
-
93
- [ @seconds, @minutes, @hours, @days, @months, @weekdays ]
94
- end
95
-
96
- #
97
90
  # Returns the next time that this cron line is supposed to 'fire'
98
91
  #
99
92
  # This is raw, 3 secs to iterate over 1 year on my macbook :( brutal.
@@ -107,21 +100,26 @@ module Rufus
107
100
  # be passed if no start time is specified (search start time set to
108
101
  # Time.now))
109
102
  #
110
- # >> Rufus::CronLine.new('30 7 * * *').next_time( Time.mktime(2008,10,24,7,29) )
111
- # => Fri Oct 24 07:30:00 -0500 2008
103
+ # Rufus::CronLine.new('30 7 * * *').next_time(
104
+ # Time.mktime(2008, 10, 24, 7, 29))
105
+ # #=> Fri Oct 24 07:30:00 -0500 2008
112
106
  #
113
- # >> Rufus::CronLine.new('30 7 * * *').next_time( Time.utc(2008,10,24,7,29) )
114
- # => Fri Oct 24 07:30:00 UTC 2008
107
+ # Rufus::CronLine.new('30 7 * * *').next_time(
108
+ # Time.utc(2008, 10, 24, 7, 29))
109
+ # #=> Fri Oct 24 07:30:00 UTC 2008
115
110
  #
116
- # >> Rufus::CronLine.new('30 7 * * *').next_time( Time.utc(2008,10,24,7,29) ).localtime
117
- # => Fri Oct 24 02:30:00 -0500 2008
111
+ # Rufus::CronLine.new('30 7 * * *').next_time(
112
+ # Time.utc(2008, 10, 24, 7, 29)).localtime
113
+ # #=> Fri Oct 24 02:30:00 -0500 2008
118
114
  #
119
115
  # (Thanks to K Liu for the note and the examples)
120
116
  #
121
- def next_time (time=Time.now)
117
+ def next_time(now=Time.now)
118
+
119
+ time = @timezone ? @timezone.utc_to_local(now.getutc) : now
122
120
 
123
- time -= time.usec * 1e-6
124
- time += 1
121
+ time = time - time.usec * 1e-6 + 1
122
+ # little adjustment before starting
125
123
 
126
124
  loop do
127
125
 
@@ -129,17 +127,14 @@ module Rufus
129
127
  time += (24 - time.hour) * 3600 - time.min * 60 - time.sec
130
128
  next
131
129
  end
132
-
133
130
  unless sub_match?(time.hour, @hours)
134
131
  time += (60 - time.min) * 60 - time.sec
135
132
  next
136
133
  end
137
-
138
134
  unless sub_match?(time.min, @minutes)
139
135
  time += 60 - time.sec
140
136
  next
141
137
  end
142
-
143
138
  unless sub_match?(time.sec, @seconds)
144
139
  time += 1
145
140
  next
@@ -148,16 +143,37 @@ module Rufus
148
143
  break
149
144
  end
150
145
 
146
+ if @timezone
147
+ time = @timezone.local_to_utc(time)
148
+ time = time.getlocal unless now.utc?
149
+ end
150
+
151
151
  time
152
152
  end
153
153
 
154
+ # Returns an array of 6 arrays (seconds, minutes, hours, days,
155
+ # months, weekdays).
156
+ # This method is used by the cronline unit tests.
157
+ #
158
+ def to_array
159
+
160
+ [
161
+ @seconds,
162
+ @minutes,
163
+ @hours,
164
+ @days,
165
+ @months,
166
+ @weekdays,
167
+ @timezone ? @timezone.name : nil
168
+ ]
169
+ end
170
+
154
171
  private
155
172
 
156
173
  WDS = %w[ sun mon tue wed thu fri sat ]
157
- #
158
174
  # used by parse_weekday()
159
175
 
160
- def parse_weekdays (item)
176
+ def parse_weekdays(item)
161
177
 
162
178
  item = item.downcase
163
179
 
@@ -170,7 +186,7 @@ module Rufus
170
186
  r
171
187
  end
172
188
 
173
- def parse_item (item, min, max)
189
+ def parse_item(item, min, max)
174
190
 
175
191
  return nil if item == '*'
176
192
  return parse_list(item, min, max) if item.index(',')
@@ -184,14 +200,14 @@ module Rufus
184
200
  [ i ]
185
201
  end
186
202
 
187
- def parse_list (item, min, max)
203
+ def parse_list(item, min, max)
188
204
 
189
205
  item.split(',').inject([]) { |r, i|
190
206
  r.push(parse_range(i, min, max))
191
207
  }.flatten
192
208
  end
193
209
 
194
- def parse_range (item, min, max)
210
+ def parse_range(item, min, max)
195
211
 
196
212
  i = item.index('-')
197
213
  j = item.index('/')
@@ -235,16 +251,17 @@ module Rufus
235
251
  end
236
252
 
237
253
  def sub_match?(value, values)
254
+
238
255
  values.nil? || values.include?(value)
239
256
  end
240
257
 
241
258
  def date_match?(date)
259
+
242
260
  return false unless sub_match?(date.day, @days)
243
261
  return false unless sub_match?(date.month, @months)
244
262
  return false unless sub_match?(date.wday, @weekdays)
245
263
  true
246
264
  end
247
265
  end
248
-
249
266
  end
250
267
 
@@ -63,7 +63,7 @@ module Scheduler
63
63
 
64
64
  # Adds this job to the map.
65
65
  #
66
- def << (job)
66
+ def <<(job)
67
67
 
68
68
  @mutex.synchronize do
69
69
  delete(job.job_id)
@@ -74,7 +74,7 @@ module Scheduler
74
74
 
75
75
  # Removes a job (given its id). Returns nil if the job was not found.
76
76
  #
77
- def unschedule (job_id)
77
+ def unschedule(job_id)
78
78
 
79
79
  @mutex.synchronize { delete(job_id) }
80
80
  end
@@ -88,7 +88,7 @@ module Scheduler
88
88
 
89
89
  # Returns a list of jobs of the given type (:at|:in|:every)
90
90
  #
91
- def select (type)
91
+ def select(type)
92
92
 
93
93
  type = JOB_TYPES[type]
94
94
  @jobs.select { |j| j.is_a?(type) }
@@ -101,7 +101,7 @@ module Scheduler
101
101
 
102
102
  protected
103
103
 
104
- def delete (job_id)
104
+ def delete(job_id)
105
105
 
106
106
  j = @jobs.find { |j| j.job_id == job_id }
107
107
  @jobs.delete(j) if j
@@ -109,7 +109,7 @@ module Scheduler
109
109
 
110
110
  # Returns the next job to trigger. Returns nil if none eligible.
111
111
  #
112
- def job_to_trigger (now)
112
+ def job_to_trigger(now)
113
113
 
114
114
  @mutex.synchronize do
115
115
  if @jobs.size > 0 && now.to_f >= @jobs.first.at
@@ -146,7 +146,7 @@ module Scheduler
146
146
  jobs.each { |job| job.trigger_if_matches(now) }
147
147
  end
148
148
 
149
- def << (job)
149
+ def <<(job)
150
150
 
151
151
  @mutex.synchronize do
152
152
  delete(job.job_id)
@@ -154,7 +154,6 @@ module Scheduler
154
154
  end
155
155
  end
156
156
  end
157
-
158
157
  end
159
158
  end
160
159