rufus-scheduler 3.0.9 → 3.1.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.
@@ -2,6 +2,13 @@
2
2
  = rufus-scheduler CHANGELOG.txt
3
3
 
4
4
 
5
+ == rufus-scheduler - 3.1.0 released 2015/04/18
6
+
7
+ - go without tzinfo (and its dependencies)
8
+ - include @ketan's #next_time improvements
9
+ - remove 2.x warning message on install
10
+
11
+
5
12
  == rufus-scheduler - 3.0.9 released 2014/08/30
6
13
 
7
14
  - fix TZ with underscores, thanks https://github.com/gnilrets
@@ -4,6 +4,8 @@
4
4
 
5
5
  == Contributors
6
6
 
7
+ - Ketan Padegaonkar (https://github.com/ketan) .brute_frequency improvement
8
+ - Gabriel Gilder (https://github.com/ggilder) LA DST specs
7
9
  - Sterling Paramore (https://github.com/gnilrets) underscore TZ fix
8
10
  - ecin (https://github.com/ecin) new lock mecha
9
11
  - Adam Jonas (https://github.com/adamjonas) migrate specs to "expect"
@@ -33,6 +35,7 @@
33
35
 
34
36
  == Feedback
35
37
 
38
+ - Michael Guymon - https://github.com/mguymon - #next_time vs :first_at
36
39
  - junhanamaki - https://github.com/junhanamaki - #next_time and dst ambiguities
37
40
  - kreynolds (tossrock) - inspiration for #occurrences
38
41
  - Matteo - https://github.com/m4ce - dst and cron issue
@@ -1,5 +1,5 @@
1
1
 
2
- Copyright (c) 2005-2014, John Mettraux, jmettraux@gmail.com
2
+ Copyright (c) 2005-2015, 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/README.md CHANGED
@@ -61,6 +61,7 @@ It does not persist your schedules. When the process is gone and the scheduler i
61
61
 
62
62
  * [whenever](https://github.com/javan/whenever) - let cron call back your Ruby code, trusted and reliable cron drives your schedule
63
63
  * [clockwork](https://github.com/tomykaira/clockwork) - rufus-scheduler inspired gem
64
+ * [crono](https://github.com/plashchynski/crono) - an in-Rails cron scheduler
64
65
 
65
66
  (please note: rufus-scheduler is not a cron replacement)
66
67
 
@@ -72,6 +73,11 @@ It's a complete rewrite of rufus-scheduler.
72
73
  There is no EventMachine-based scheduler anymore.
73
74
 
74
75
 
76
+ ## I don't know what this Ruby thing is, where are my Rails?
77
+
78
+ Sir, I'll drive you right to the [tracks](#so-rails).
79
+
80
+
75
81
  ## Notables changes:
76
82
 
77
83
  * As said, no more EventMachine-based scheduler
@@ -1370,19 +1376,6 @@ Rufus::Scheduler.parse("2013-12-12 14:00 Pacific/Saipan")
1370
1376
  # => 2013-12-12 04:00:00 UTC
1371
1377
  ```
1372
1378
 
1373
- Behind the scenes, rufus-scheduler uses [tzinfo](http://tzinfo.github.io/) to deal with timezones.
1374
-
1375
- Here is a [list of timezones](misc/tz_all.txt) known to my Debian GNU/Linux 7. It was generated with this script:
1376
-
1377
- ```ruby
1378
- require 'tzinfo'
1379
- TZInfo::Timezone.all.each { |tz| puts tz.name }
1380
- ```
1381
-
1382
- Unknown timezones, typos, will be rejected by tzinfo thus rufus-scheduler.
1383
-
1384
- On its own tzinfo derives the timezones from the system's information. On some system it needs some help, one can install the 'tzinfo-data' gem to provide the missing information.
1385
-
1386
1379
 
1387
1380
  ## so Rails?
1388
1381
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2006-2014, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2006-2015, 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
@@ -25,7 +25,7 @@
25
25
  require 'date' if RUBY_VERSION < '1.9.0'
26
26
  require 'time'
27
27
  require 'thread'
28
- require 'tzinfo'
28
+ #require 'tzinfo'
29
29
 
30
30
 
31
31
  module Rufus
@@ -33,12 +33,13 @@ module Rufus
33
33
  class Scheduler
34
34
 
35
35
  require 'rufus/scheduler/util'
36
+ require 'rufus/scheduler/zotime'
36
37
  require 'rufus/scheduler/jobs'
37
38
  require 'rufus/scheduler/cronline'
38
39
  require 'rufus/scheduler/job_array'
39
40
  require 'rufus/scheduler/locks'
40
41
 
41
- VERSION = '3.0.9'
42
+ VERSION = '3.1.0'
42
43
 
43
44
  #
44
45
  # A common error class for rufus-scheduler
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2006-2014, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2006-2015, 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
@@ -22,6 +22,8 @@
22
22
  # Made in Japan.
23
23
  #++
24
24
 
25
+ require 'set'
26
+
25
27
 
26
28
  class Rufus::Scheduler
27
29
 
@@ -54,8 +56,7 @@ class Rufus::Scheduler
54
56
 
55
57
  items = line.split
56
58
 
57
- @timezone = (TZInfo::Timezone.get(items.last) rescue nil)
58
- items.pop if @timezone
59
+ @timezone = items.pop if ZoTime.is_timezone?(items.last)
59
60
 
60
61
  raise ArgumentError.new(
61
62
  "not a valid cronline : '#{line}'"
@@ -82,9 +83,7 @@ class Rufus::Scheduler
82
83
  #
83
84
  def matches?(time)
84
85
 
85
- time = Time.at(time) unless time.kind_of?(Time)
86
-
87
- time = @timezone.utc_to_local(time.getutc) if @timezone
86
+ time = ZoTime.new(time.to_f, @timezone || ENV['TZ']).time
88
87
 
89
88
  return false unless sub_match?(time, :sec, @seconds)
90
89
  return false unless sub_match?(time, :min, @minutes)
@@ -122,37 +121,34 @@ class Rufus::Scheduler
122
121
  #
123
122
  def next_time(from=Time.now)
124
123
 
125
- time = local_time(from)
126
- time = round_to_seconds(time)
127
-
128
- # start at the next second
129
- time = time + 1
124
+ time = nil
125
+ zotime = ZoTime.new(from.to_i + 1, @timezone || ENV['TZ'])
130
126
 
131
127
  loop do
128
+
129
+ time = zotime.time
130
+
132
131
  unless date_match?(time)
133
- dst = time.isdst
134
- time += (24 - time.hour) * 3600 - time.min * 60 - time.sec
135
- time -= 3600 if time.isdst != dst # not necessary for winter, but...
132
+ zotime.add((24 - time.hour) * 3600 - time.min * 60 - time.sec)
136
133
  next
137
134
  end
138
135
  unless sub_match?(time, :hour, @hours)
139
- time += (60 - time.min) * 60 - time.sec; next
136
+ zotime.add((60 - time.min) * 60 - time.sec)
137
+ next
140
138
  end
141
139
  unless sub_match?(time, :min, @minutes)
142
- time += 60 - time.sec; next
140
+ zotime.add(60 - time.sec)
141
+ next
143
142
  end
144
143
  unless sub_match?(time, :sec, @seconds)
145
- time += 1; next
144
+ zotime.add(next_second(time))
145
+ next
146
146
  end
147
147
 
148
148
  break
149
149
  end
150
150
 
151
- global_time(time, from.utc?)
152
-
153
- rescue TZInfo::PeriodNotFound
154
-
155
- next_time(from + 3600)
151
+ time
156
152
  end
157
153
 
158
154
  # Returns the previous time the cronline matched. It's like next_time, but
@@ -160,35 +156,48 @@ class Rufus::Scheduler
160
156
  #
161
157
  def previous_time(from=Time.now)
162
158
 
163
- time = local_time(from)
164
- time = round_to_seconds(time)
165
-
166
- # start at the previous second
167
- time = time - 1
159
+ time = nil
160
+ zotime = ZoTime.new(from.to_i - 1, @timezone || ENV['TZ'])
168
161
 
169
162
  loop do
163
+
164
+ time = zotime.time
165
+
170
166
  unless date_match?(time)
171
- time -= time.hour * 3600 + time.min * 60 + time.sec + 1; next
167
+ zotime.substract(time.hour * 3600 + time.min * 60 + time.sec + 1)
168
+ next
172
169
  end
173
170
  unless sub_match?(time, :hour, @hours)
174
- time -= time.min * 60 + time.sec + 1; next
171
+ zotime.substract(time.min * 60 + time.sec + 1)
172
+ next
175
173
  end
176
174
  unless sub_match?(time, :min, @minutes)
177
- time -= time.sec + 1; next
175
+ zotime.substract(time.sec + 1)
176
+ next
178
177
  end
179
178
  unless sub_match?(time, :sec, @seconds)
180
- time -= 1; next
179
+ zotime.substract(prev_second(time))
180
+ next
181
181
  end
182
182
 
183
183
  break
184
184
  end
185
185
 
186
- global_time(time, from.utc?)
187
-
188
- rescue TZInfo::PeriodNotFound
186
+ time
187
+ end
189
188
 
190
- previous_time(time)
189
+ if RUBY_VERSION >= '1.9'
190
+ def toa(item)
191
+ item == nil ? nil : item.to_a
192
+ end
193
+ else
194
+ def toi(item); item.is_a?(String) ? item.hash.abs : item.to_i; end
195
+ protected :toi
196
+ def toa(item)
197
+ item.is_a?(Set) ? item.to_a.sort_by { |e| toi(e) } : item
198
+ end
191
199
  end
200
+ protected :toa
192
201
 
193
202
  # Returns an array of 6 arrays (seconds, minutes, hours, days,
194
203
  # months, weekdays).
@@ -197,14 +206,14 @@ class Rufus::Scheduler
197
206
  def to_array
198
207
 
199
208
  [
200
- @seconds,
201
- @minutes,
202
- @hours,
203
- @days,
204
- @months,
205
- @weekdays,
206
- @monthdays,
207
- @timezone ? @timezone.name : nil
209
+ toa(@seconds),
210
+ toa(@minutes),
211
+ toa(@hours),
212
+ toa(@days),
213
+ toa(@months),
214
+ toa(@weekdays),
215
+ toa(@monthdays),
216
+ @timezone
208
217
  ]
209
218
  end
210
219
 
@@ -212,7 +221,7 @@ class Rufus::Scheduler
212
221
  # cron line.
213
222
  #
214
223
  # #brute_frequency, on the other hand, will compute the frequency by
215
- # examining a whole, that can take more than seconds for a seconds
224
+ # examining a whole year, that can take more than seconds for a seconds
216
225
  # level cron...
217
226
  #
218
227
  def frequency
@@ -220,9 +229,10 @@ class Rufus::Scheduler
220
229
  return brute_frequency unless @seconds && @seconds.length > 1
221
230
 
222
231
  delta = 60
223
- prev = @seconds[0]
232
+ secs = toa(@seconds)
233
+ prev = secs[0]
224
234
 
225
- @seconds[1..-1].each do |sec|
235
+ secs[1..-1].each do |sec|
226
236
  d = sec - prev
227
237
  delta = d if d < delta
228
238
  end
@@ -270,7 +280,7 @@ class Rufus::Scheduler
270
280
  delta = d if d < delta
271
281
 
272
282
  break if @months == nil && t1.month == 2
273
- break if t1.year == 2001
283
+ break if t1.year >= 2001
274
284
 
275
285
  t0 = t1
276
286
  end
@@ -280,6 +290,26 @@ class Rufus::Scheduler
280
290
 
281
291
  protected
282
292
 
293
+ def next_second(time)
294
+
295
+ secs = @seconds.sort
296
+
297
+ return secs.last + 60 - time.sec if time.sec > secs.last
298
+
299
+ secs.shift while secs.first < time.sec
300
+
301
+ secs.first - time.sec
302
+ end
303
+
304
+ def prev_second(time)
305
+
306
+ secs = @seconds.sort
307
+
308
+ secs.pop while time.sec < secs.last
309
+
310
+ time.sec - secs.last
311
+ end
312
+
283
313
  WEEKDAYS = %w[ sun mon tue wed thu fri sat ]
284
314
  DAY_S = 24 * 3600
285
315
  WEEK_S = 7 * DAY_S
@@ -336,7 +366,7 @@ class Rufus::Scheduler
336
366
  "found duplicates in #{item.inspect}"
337
367
  ) if r.uniq.size < r.size
338
368
 
339
- r
369
+ Set.new(r)
340
370
  end
341
371
 
342
372
  RANGE_REGEX = /^(\*|\d{1,2})(?:-(\d{1,2}))?(?:\/(\d{1,2}))?$/
@@ -435,32 +465,6 @@ class Rufus::Scheduler
435
465
 
436
466
  [ "#{WEEKDAYS[date.wday]}##{pos}", "#{WEEKDAYS[date.wday]}##{neg}" ]
437
467
  end
438
-
439
- def local_time(time)
440
-
441
- @timezone ? @timezone.utc_to_local(time.getutc) : time
442
- end
443
-
444
- def global_time(time, from_in_utc)
445
-
446
- if @timezone
447
- time =
448
- begin
449
- @timezone.local_to_utc(time)
450
- rescue TZInfo::AmbiguousTime
451
- @timezone.local_to_utc(time, time.isdst)
452
- end
453
- time = time.getlocal unless from_in_utc
454
- end
455
-
456
- time
457
- end
458
-
459
- def round_to_seconds(time)
460
-
461
- # Ruby 1.8 doesn't have #round
462
- time.respond_to?(:round) ? time.round : time - time.usec * 1e-6
463
- end
464
468
  end
465
469
  end
466
470
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2006-2014, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2006-2015, 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
@@ -22,6 +22,7 @@
22
22
  # Made in Japan.
23
23
  #++
24
24
 
25
+
25
26
  module Rufus
26
27
 
27
28
  class Scheduler
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2006-2014, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2006-2015, 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
@@ -340,7 +340,7 @@ module Rufus
340
340
 
341
341
  def occurrences(time0, time1)
342
342
 
343
- time >= time0 && time <= time1 ? [ time ] : []
343
+ (time >= time0 && time <= time1) ? [ time ] : []
344
344
  end
345
345
 
346
346
  protected
@@ -409,15 +409,17 @@ module Rufus
409
409
  self.first_at =
410
410
  opts[:first] || opts[:first_time] ||
411
411
  opts[:first_at] || opts[:first_in] ||
412
- 0
412
+ nil
413
413
  self.last_at =
414
414
  opts[:last] || opts[:last_at] || opts[:last_in]
415
415
  end
416
416
 
417
417
  def first_at=(first)
418
418
 
419
+ return @first_at = nil if first == nil
420
+
419
421
  n = Time.now
420
- first = n + 0.001 if first == :now || first == :immediately
422
+ first = n + 0.003 if first == :now || first == :immediately
421
423
 
422
424
  @first_at = Rufus::Scheduler.parse_to_time(first)
423
425
 
@@ -440,9 +442,6 @@ module Rufus
440
442
  def trigger(time)
441
443
 
442
444
  return if @paused_at
443
- return if time < @first_at
444
- #
445
- # TODO: remove me when @first_at gets reworked
446
445
 
447
446
  return (@next_time = nil) if @times && @times < 1
448
447
  return (@next_time = nil) if @last_at && time >= @last_at
@@ -538,10 +537,8 @@ module Rufus
538
537
  return if is_post
539
538
 
540
539
  @next_time =
541
- if trigger_time
542
- trigger_time + @frequency
543
- elsif @first_at < Time.now
544
- Time.now + @frequency
540
+ if @first_at == nil || @first_at < Time.now
541
+ (trigger_time || Time.now) + @frequency
545
542
  else
546
543
  @first_at
547
544
  end
@@ -579,7 +576,7 @@ module Rufus
579
576
  if is_post
580
577
  Time.now + @interval
581
578
  elsif trigger_time.nil?
582
- if @first_at < Time.now
579
+ if @first_at == nil || @first_at < Time.now
583
580
  Time.now + @interval
584
581
  else
585
582
  @first_at
@@ -602,7 +599,7 @@ module Rufus
602
599
  super(scheduler, cronline, opts, block)
603
600
 
604
601
  @cron_line = opts[:_t] || CronLine.new(cronline)
605
- @next_time = @cron_line.next_time
602
+ set_next_time(nil)
606
603
  end
607
604
 
608
605
  def frequency
@@ -619,12 +616,16 @@ module Rufus
619
616
 
620
617
  def set_next_time(trigger_time, is_post=false)
621
618
 
622
- @next_time = @cron_line.next_time
619
+ @next_time = next_time_from(trigger_time || Time.now)
623
620
  end
624
621
 
625
622
  def next_time_from(time)
626
623
 
627
- @cron_line.next_time(time)
624
+ if @first_at == nil || @first_at < time
625
+ @cron_line.next_time(time)
626
+ else
627
+ @first_at
628
+ end
628
629
  end
629
630
  end
630
631
  end