rufus-scheduler 3.0.7 → 3.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.txt CHANGED
@@ -2,13 +2,21 @@
2
2
  = rufus-scheduler CHANGELOG.txt
3
3
 
4
4
 
5
+ == rufus-scheduler - 3.0.8 released 2014/06/09
6
+
7
+ - handle TZInfo errors on DST transitions, thanks https://github.com/junhanamaki
8
+ - implement Scheduler#up?
9
+ - let schedule and schedule_at use Chronic if present
10
+ - let Rufus::Scheduler.parse use Chronic if present
11
+
12
+
5
13
  == rufus-scheduler - 3.0.7 released 2014/03/18
6
14
 
7
15
  - implement Scheduler #occurrences and #timeline, inspired by kreynolds
8
16
  - implement Job #last_work_time and #mean_work_time
9
17
  - implement Job#count
10
18
  - add more info to the stderr error output (scheduler/tz info)
11
- - prevent skipping a day on swith to summertime, gh-114, thanks Matteo
19
+ - prevent skipping a day on switch to summertime, gh-114, thanks Matteo
12
20
 
13
21
 
14
22
  == rufus-scheduler - 3.0.6 released 2014/02/14
data/CREDITS.txt CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  == Contributors
6
6
 
7
+ - Adam Jonas (https://github.com/adamjonas) migrate specs to "expect"
7
8
  - Yassen Bantchev (https://github.com/yassenb) CronLine#previous_time rewrite
8
9
  - Eric Lindvall (https://github.com/eric) Zookeeper locked example
9
10
  - Ted Pennings (https://github.com/tedpennings) typo in post_install_message
@@ -30,6 +31,7 @@
30
31
 
31
32
  == Feedback
32
33
 
34
+ - junhanamaki - https://github.com/junhanamaki - #next_time and dst ambiguities
33
35
  - kreynolds (tossrock) - inspiration for #occurrences
34
36
  - Matteo - https://github.com/m4ce - dst and cron issue
35
37
  - Tobias Bielohlawek - https://github.com/rngtng - missing assertion
data/README.md CHANGED
@@ -394,8 +394,8 @@ This option is for repeat jobs (cron / every) only.
394
394
 
395
395
  It's used to specify the first time after which the repeat job should trigger for the first time.
396
396
 
397
- In the case of an "every" job, this will be the first time (module the scheduler frequency) the job triggers.
398
- For a "cron" job, it's the time after which the first schedule will trigger.
397
+ In the case of an "every" job, this will be the first time (modulo the scheduler frequency) the job triggers.
398
+ For a "cron" job, it's the time *after* which the first schedule will trigger.
399
399
 
400
400
  ```ruby
401
401
  scheduler.every '2d', :first_at => Time.now + 10 * 3600 do
@@ -405,6 +405,10 @@ end
405
405
  scheduler.every '2d', :first_in => '10h' do
406
406
  # ... every two days, but start in 10 hours
407
407
  end
408
+
409
+ scheduler.cron '00 14 * * *', :first_in => '3d' do
410
+ # ... every day at 14h00, but start after 3 * 24 hours
411
+ end
408
412
  ```
409
413
 
410
414
  :first, :first_at and :first_in all accept a point in time or a duration (number or time string). Use the symbol you think make your schedule more readable.
@@ -1135,7 +1139,7 @@ Rufus::Scheduler.s.every '10s' { puts "hello, world!" }
1135
1139
 
1136
1140
  ## advanced lock schemes
1137
1141
 
1138
- As seen above, rufus-scheduler proposes the :lockfile system out of the box. If in a group of schedulers only one is supposed to run, the lockfile mecha prevents schedulers that have not set/created the lockfile from running.
1142
+ As seen above, rufus-scheduler proposes the [:lockfile](#lockfile--mylockfiletxt) system out of the box. If in a group of schedulers only one is supposed to run, the lockfile mecha prevents schedulers that have not set/created the lockfile from running.
1139
1143
 
1140
1144
  There are situation where this is not sufficient.
1141
1145
 
data/TODO.txt CHANGED
@@ -145,3 +145,7 @@
145
145
  end
146
146
  end
147
147
 
148
+ ~~~
149
+
150
+ [ ] scheduler.at('chronic string', chronic_options...)
151
+
@@ -38,7 +38,7 @@ module Rufus
38
38
  require 'rufus/scheduler/cronline'
39
39
  require 'rufus/scheduler/job_array'
40
40
 
41
- VERSION = '3.0.7'
41
+ VERSION = '3.0.8'
42
42
 
43
43
  #
44
44
  # A common error class for rufus-scheduler
@@ -165,6 +165,11 @@ module Rufus
165
165
  ! @started_at
166
166
  end
167
167
 
168
+ def up?
169
+
170
+ !! @started_at
171
+ end
172
+
168
173
  def paused?
169
174
 
170
175
  @paused
@@ -236,9 +241,9 @@ module Rufus
236
241
 
237
242
  def schedule(arg, callable=nil, opts={}, &block)
238
243
 
239
- # TODO: eventually, spare one parse call
244
+ opts[:_t] = Scheduler.parse(arg, opts)
240
245
 
241
- case Scheduler.parse(arg)
246
+ case opts[:_t]
242
247
  when CronLine then schedule_cron(arg, callable, opts, &block)
243
248
  when Time then schedule_at(arg, callable, opts, &block)
244
249
  else schedule_in(arg, callable, opts, &block)
@@ -247,9 +252,9 @@ module Rufus
247
252
 
248
253
  def repeat(arg, callable=nil, opts={}, &block)
249
254
 
250
- # TODO: eventually, spare one parse call
255
+ opts[:_t] = Scheduler.parse(arg, opts)
251
256
 
252
- case Scheduler.parse(arg)
257
+ case opts[:_t]
253
258
  when CronLine then schedule_cron(arg, callable, opts, &block)
254
259
  else schedule_every(arg, callable, opts, &block)
255
260
  end
@@ -612,8 +617,8 @@ module Rufus
612
617
  job_class =
613
618
  case job_type
614
619
  when :once
615
- tt = Rufus::Scheduler.parse(t)
616
- tt.is_a?(Time) ? AtJob : InJob
620
+ opts[:_t] ||= Rufus::Scheduler.parse(t, opts)
621
+ opts[:_t].is_a?(Time) ? AtJob : InJob
617
622
  when :every
618
623
  EveryJob
619
624
  when :interval
@@ -149,6 +149,10 @@ class Rufus::Scheduler
149
149
  end
150
150
 
151
151
  global_time(time, from.utc?)
152
+
153
+ rescue TZInfo::PeriodNotFound
154
+
155
+ next_time(from + 3600)
152
156
  end
153
157
 
154
158
  # Returns the previous time the cronline matched. It's like next_time, but
@@ -180,6 +184,10 @@ class Rufus::Scheduler
180
184
  end
181
185
 
182
186
  global_time(time, from.utc?)
187
+
188
+ rescue TZInfo::PeriodNotFound
189
+
190
+ previous_time(time)
183
191
  end
184
192
 
185
193
  # Returns an array of 6 arrays (seconds, minutes, hours, days,
@@ -429,12 +437,19 @@ class Rufus::Scheduler
429
437
  end
430
438
 
431
439
  def local_time(time)
432
- time = @timezone ? @timezone.utc_to_local(time.getutc) : time
440
+
441
+ @timezone ? @timezone.utc_to_local(time.getutc) : time
433
442
  end
434
443
 
435
444
  def global_time(time, from_in_utc)
445
+
436
446
  if @timezone
437
- time = @timezone.local_to_utc(time)
447
+ time =
448
+ begin
449
+ @timezone.local_to_utc(time)
450
+ rescue TZInfo::AmbiguousTime
451
+ @timezone.local_to_utc(time, time.isdst)
452
+ end
438
453
  time = time.getlocal unless from_in_utc
439
454
  end
440
455
 
@@ -442,6 +457,7 @@ class Rufus::Scheduler
442
457
  end
443
458
 
444
459
  def round_to_seconds(time)
460
+
445
461
  # Ruby 1.8 doesn't have #round
446
462
  time.respond_to?(:round) ? time.round : time - time.usec * 1e-6
447
463
  end
@@ -368,7 +368,8 @@ module Rufus
368
368
 
369
369
  super(scheduler, time, opts, block)
370
370
 
371
- @next_time = Rufus::Scheduler.parse_at(time)
371
+ @next_time =
372
+ opts[:_t] || Rufus::Scheduler.parse_at(time, opts)
372
373
  end
373
374
  end
374
375
 
@@ -378,7 +379,9 @@ module Rufus
378
379
 
379
380
  super(scheduler, duration, opts, block)
380
381
 
381
- @next_time = @scheduled_at + Rufus::Scheduler.parse_in(duration)
382
+ @next_time =
383
+ @scheduled_at +
384
+ opts[:_t] || Rufus::Scheduler.parse_in(duration, opts)
382
385
  end
383
386
  end
384
387
 
@@ -597,7 +600,7 @@ module Rufus
597
600
 
598
601
  super(scheduler, cronline, opts, block)
599
602
 
600
- @cron_line = CronLine.new(cronline)
603
+ @cron_line = opts[:_t] || CronLine.new(cronline)
601
604
  @next_time = @cron_line.next_time
602
605
  end
603
606
 
@@ -31,9 +31,9 @@ module Rufus
31
31
  # time and string methods
32
32
  #++
33
33
 
34
- def self.parse(o)
34
+ def self.parse(o, opts={})
35
35
 
36
- opts = { :no_error => true }
36
+ opts[:no_error] = true
37
37
 
38
38
  parse_cron(o, opts) ||
39
39
  parse_in(o, opts) || # covers 'every' schedule strings
@@ -52,6 +52,9 @@ module Rufus
52
52
 
53
53
  return o if o.is_a?(Time)
54
54
 
55
+ # TODO: deal with tz if suffixed to Chronic string?
56
+ return Chronic.parse(o, opts) if defined?(Chronic)
57
+
55
58
  tz = nil
56
59
  s =
57
60
  o.to_s.gsub(TZ_REGEX) { |m|
@@ -68,9 +71,7 @@ module Rufus
68
71
 
69
72
  t = Time.parse(s)
70
73
 
71
- t = tz.local_to_utc(t) if tz
72
-
73
- t
74
+ tz ? tz.local_to_utc(t) : t
74
75
 
75
76
  rescue StandardError => se
76
77
 
@@ -30,6 +30,7 @@ job scheduler for Ruby (at, cron, in and every jobs).
30
30
 
31
31
  s.add_development_dependency 'rake'
32
32
  s.add_development_dependency 'rspec', '>= 2.13.0'
33
+ s.add_development_dependency 'chronic'
33
34
 
34
35
  s.require_path = 'lib'
35
36
 
@@ -0,0 +1,49 @@
1
+
2
+ #
3
+ # Specifying rufus-scheduler
4
+ #
5
+ # Sun Jun 1 05:52:24 JST 2014
6
+ #
7
+
8
+ require 'spec_helper'
9
+
10
+
11
+ describe 'basics' do
12
+
13
+ def tts(time)
14
+
15
+ time.strftime('%Y-%m-%d %H:%M:%S %z') + (time.dst? ? ' dst' : '')
16
+ end
17
+
18
+ describe 'Time.new' do
19
+
20
+ it 'accepts a timezone final argument' do
21
+
22
+ pending if jruby? or ruby18?
23
+
24
+ expect(
25
+ tts(Time.new(2014, 1, 1, 1, 0, 0, '+01:00'))
26
+ ).to eq('2014-01-01 01:00:00 +0100')
27
+ expect(
28
+ tts(Time.new(2014, 8, 1, 1, 0, 0, '+01:00'))
29
+ ).to eq('2014-08-01 01:00:00 +0100')
30
+ expect(
31
+ tts(Time.new(2014, 8, 1, 1, 0, 0, '+01:00'))
32
+ ).to eq('2014-08-01 01:00:00 +0100')
33
+ end
34
+ end
35
+
36
+ describe 'Time.local' do
37
+
38
+ it 'works as expected' do
39
+
40
+ expect(
41
+ tts(in_zone('Europe/Berlin') { Time.local(2014, 1, 1, 1, 0, 0) })
42
+ ).to eq('2014-01-01 01:00:00 +0100')
43
+ expect(
44
+ tts(in_zone('Europe/Berlin') { Time.local(2014, 8, 1, 1, 0, 0) })
45
+ ).to eq('2014-08-01 01:00:00 +0200 dst')
46
+ end
47
+ end
48
+ end
49
+
@@ -16,13 +16,13 @@ describe Rufus::Scheduler::CronLine do
16
16
  end
17
17
 
18
18
  def match(line, time)
19
- cl(line).matches?(time).should == true
19
+ expect(cl(line).matches?(time)).to eq(true)
20
20
  end
21
21
  def no_match(line, time)
22
- cl(line).matches?(time).should == false
22
+ expect(cl(line).matches?(time)).to eq(false)
23
23
  end
24
24
  def to_a(line, array)
25
- cl(line).to_array.should == array
25
+ expect(cl(line).to_array).to eq(array)
26
26
  end
27
27
 
28
28
  describe '.new' do
@@ -59,17 +59,17 @@ describe Rufus::Scheduler::CronLine do
59
59
 
60
60
  it 'rejects invalid weekday expressions' do
61
61
 
62
- lambda { cl '0 17 * * MON_FRI' }.should raise_error
62
+ expect { cl '0 17 * * MON_FRI' }.to raise_error
63
63
  # underline instead of dash
64
64
 
65
- lambda { cl '* * * * 9' }.should raise_error
66
- lambda { cl '* * * * 0-12' }.should raise_error
67
- lambda { cl '* * * * BLABLA' }.should raise_error
65
+ expect { cl '* * * * 9' }.to raise_error
66
+ expect { cl '* * * * 0-12' }.to raise_error
67
+ expect { cl '* * * * BLABLA' }.to raise_error
68
68
  end
69
69
 
70
70
  it 'rejects invalid cronlines' do
71
71
 
72
- lambda { cl '* nada * * 9' }.should raise_error(ArgumentError)
72
+ expect { cl '* nada * * 9' }.to raise_error(ArgumentError)
73
73
  end
74
74
 
75
75
  it 'interprets cron strings with TZ correctly' do
@@ -84,8 +84,8 @@ describe Rufus::Scheduler::CronLine do
84
84
  '* * * * * * America/New_York',
85
85
  [ nil, nil, nil, nil, nil, nil, nil, 'America/New_York' ])
86
86
 
87
- lambda { cl '* * * * * NotATimeZone' }.should raise_error
88
- lambda { cl '* * * * * * NotATimeZone' }.should raise_error
87
+ expect { cl '* * * * * NotATimeZone' }.to raise_error
88
+ expect { cl '* * * * * * NotATimeZone' }.to raise_error
89
89
  end
90
90
 
91
91
  it 'interprets cron strings with / (slashes) correctly' do
@@ -118,59 +118,69 @@ describe Rufus::Scheduler::CronLine do
118
118
 
119
119
  it 'rejects / for days (every other wednesday)' do
120
120
 
121
- lambda {
121
+ expect {
122
122
  Rufus::Scheduler::CronLine.new('* * * * wed/2')
123
- }.should raise_error(ArgumentError)
123
+ }.to raise_error(ArgumentError)
124
124
  end
125
125
 
126
126
  it 'does not support ranges for monthdays (sun#1-sun#2)' do
127
127
 
128
- lambda {
128
+ expect {
129
129
  Rufus::Scheduler::CronLine.new('* * * * sun#1-sun#2')
130
- }.should raise_error(ArgumentError)
130
+ }.to raise_error(ArgumentError)
131
131
  end
132
132
 
133
133
  it 'accepts items with initial 0' do
134
134
 
135
- to_a '09 * * * *', [ [0], [9], nil, nil, nil, nil, nil, nil ]
136
- to_a '09-12 * * * *', [ [0], [9, 10, 11, 12], nil, nil, nil, nil, nil, nil ]
137
- to_a '07-08 * * * *', [ [0], [7, 8], nil, nil, nil, nil, nil, nil ]
138
- to_a '* */08 * * *', [ [0], nil, [0, 8, 16], nil, nil, nil, nil, nil ]
139
- to_a '* */07 * * *', [ [0], nil, [0, 7, 14, 21], nil, nil, nil, nil, nil ]
140
- to_a '* 01-09/04 * * *', [ [0], nil, [1, 5, 9], nil, nil, nil, nil, nil ]
141
- to_a '* * * * 06', [ [0], nil, nil, nil, nil, [6], nil, nil ]
135
+ to_a(
136
+ '09 * * * *', [ [0], [9], nil, nil, nil, nil, nil, nil ])
137
+ to_a(
138
+ '09-12 * * * *', [ [0], [9, 10, 11, 12], nil, nil, nil, nil, nil, nil ])
139
+ to_a(
140
+ '07-08 * * * *', [ [0], [7, 8], nil, nil, nil, nil, nil, nil ])
141
+ to_a(
142
+ '* */08 * * *', [ [0], nil, [0, 8, 16], nil, nil, nil, nil, nil ])
143
+ to_a(
144
+ '* */07 * * *', [ [0], nil, [0, 7, 14, 21], nil, nil, nil, nil, nil ])
145
+ to_a(
146
+ '* 01-09/04 * * *', [ [0], nil, [1, 5, 9], nil, nil, nil, nil, nil ])
147
+ to_a(
148
+ '* * * * 06', [ [0], nil, nil, nil, nil, [6], nil, nil ])
142
149
  end
143
150
 
144
151
  it 'interprets cron strings with L correctly' do
145
152
 
146
- to_a '* * L * *', [[0], nil, nil, ['L'], nil, nil, nil, nil ]
147
- to_a '* * 2-5,L * *', [[0], nil, nil, [2,3,4,5,'L'], nil, nil, nil, nil ]
148
- to_a '* * */8,L * *', [[0], nil, nil, [1,9,17,25,'L'], nil, nil, nil, nil ]
153
+ to_a(
154
+ '* * L * *', [[0], nil, nil, ['L'], nil, nil, nil, nil ])
155
+ to_a(
156
+ '* * 2-5,L * *', [[0], nil, nil, [2,3,4,5,'L'], nil, nil, nil, nil ])
157
+ to_a(
158
+ '* * */8,L * *', [[0], nil, nil, [1,9,17,25,'L'], nil, nil, nil, nil ])
149
159
  end
150
160
 
151
161
  it 'does not support ranges for L' do
152
162
 
153
- lambda { cl '* * 15-L * *'}.should raise_error(ArgumentError)
154
- lambda { cl '* * L/4 * *'}.should raise_error(ArgumentError)
163
+ expect { cl '* * 15-L * *'}.to raise_error(ArgumentError)
164
+ expect { cl '* * L/4 * *'}.to raise_error(ArgumentError)
155
165
  end
156
166
 
157
167
  it 'does not support multiple Ls' do
158
168
 
159
- lambda { cl '* * L,L * *'}.should raise_error(ArgumentError)
169
+ expect { cl '* * L,L * *'}.to raise_error(ArgumentError)
160
170
  end
161
171
 
162
172
  it 'raises if L is used for something else than days' do
163
173
 
164
- lambda { cl '* L * * *'}.should raise_error(ArgumentError)
174
+ expect { cl '* L * * *'}.to raise_error(ArgumentError)
165
175
  end
166
176
 
167
177
  it 'raises for out of range input' do
168
178
 
169
- lambda { cl '60-62 * * * *'}.should raise_error(ArgumentError)
170
- lambda { cl '62 * * * *'}.should raise_error(ArgumentError)
171
- lambda { cl '60 * * * *'}.should raise_error(ArgumentError)
172
- lambda { cl '* 25-26 * * *'}.should raise_error(ArgumentError)
173
- lambda { cl '* 25 * * *'}.should raise_error(ArgumentError)
179
+ expect { cl '60-62 * * * *'}.to raise_error(ArgumentError)
180
+ expect { cl '62 * * * *'}.to raise_error(ArgumentError)
181
+ expect { cl '60 * * * *'}.to raise_error(ArgumentError)
182
+ expect { cl '* 25-26 * * *'}.to raise_error(ArgumentError)
183
+ expect { cl '* 25 * * *'}.to raise_error(ArgumentError)
174
184
  #
175
185
  # as reported by Aimee Rose in
176
186
  # https://github.com/jmettraux/rufus-scheduler/pull/58
@@ -182,64 +192,69 @@ describe Rufus::Scheduler::CronLine do
182
192
  def nt(cronline, now)
183
193
  Rufus::Scheduler::CronLine.new(cronline).next_time(now)
184
194
  end
195
+ def ntz(cronline, now)
196
+ tz = cronline.split.last
197
+ tu = nt(cronline, now).utc
198
+ in_zone(tz) { tu.getlocal }
199
+ end
185
200
 
186
201
  it 'computes the next occurence correctly' do
187
202
 
188
203
  now = Time.at(0).getutc # Thu Jan 01 00:00:00 UTC 1970
189
204
 
190
- nt('* * * * *', now).should == now + 60
191
- nt('* * * * sun', now).should == now + 259200
192
- nt('* * * * * *', now).should == now + 1
193
- nt('* * 13 * fri', now).should == now + 3715200
205
+ expect(nt('* * * * *', now)).to eq(now + 60)
206
+ expect(nt('* * * * sun', now)).to eq(now + 259200)
207
+ expect(nt('* * * * * *', now)).to eq(now + 1)
208
+ expect(nt('* * 13 * fri', now)).to eq(now + 3715200)
194
209
 
195
- nt('10 12 13 12 *', now).should == now + 29938200
210
+ expect(nt('10 12 13 12 *', now)).to eq(now + 29938200)
196
211
  # this one is slow (1 year == 3 seconds)
197
212
  #
198
213
  # historical note:
199
214
  # (comment made in 2006 or 2007, the underlying libs got better and
200
215
  # that slowness is gone)
201
216
 
202
- nt('0 0 * * thu', now).should == now + 604800
203
- nt('00 0 * * thu', now).should == now + 604800
217
+ expect(nt('0 0 * * thu', now)).to eq(now + 604800)
218
+ expect(nt('00 0 * * thu', now)).to eq(now + 604800)
204
219
 
205
- nt('0 0 * * *', now).should == now + 24 * 3600
206
- nt('0 24 * * *', now).should == now + 24 * 3600
220
+ expect(nt('0 0 * * *', now)).to eq(now + 24 * 3600)
221
+ expect(nt('0 24 * * *', now)).to eq(now + 24 * 3600)
207
222
 
208
223
  now = local(2008, 12, 31, 23, 59, 59, 0)
209
224
 
210
- nt('* * * * *', now).should == now + 1
225
+ expect(nt('* * * * *', now)).to eq(now + 1)
211
226
  end
212
227
 
213
228
  it 'computes the next occurence correctly in UTC (TZ not specified)' do
214
229
 
215
230
  now = utc(1970, 1, 1)
216
231
 
217
- nt('* * * * *', now).should == utc(1970, 1, 1, 0, 1)
218
- nt('* * * * sun', now).should == utc(1970, 1, 4)
219
- nt('* * * * * *', now).should == utc(1970, 1, 1, 0, 0, 1)
220
- nt('* * 13 * fri', now).should == utc(1970, 2, 13)
232
+ expect(nt('* * * * *', now)).to eq(utc(1970, 1, 1, 0, 1))
233
+ expect(nt('* * * * sun', now)).to eq(utc(1970, 1, 4))
234
+ expect(nt('* * * * * *', now)).to eq(utc(1970, 1, 1, 0, 0, 1))
235
+ expect(nt('* * 13 * fri', now)).to eq(utc(1970, 2, 13))
221
236
 
222
- nt('10 12 13 12 *', now).should == utc(1970, 12, 13, 12, 10)
237
+ expect(nt('10 12 13 12 *', now)).to eq(utc(1970, 12, 13, 12, 10))
223
238
  # this one is slow (1 year == 3 seconds)
224
- nt('* * 1 6 *', now).should == utc(1970, 6, 1)
239
+ expect(nt('* * 1 6 *', now)).to eq(utc(1970, 6, 1))
225
240
 
226
- nt('0 0 * * thu', now).should == utc(1970, 1, 8)
241
+ expect(nt('0 0 * * thu', now)).to eq(utc(1970, 1, 8))
227
242
  end
228
243
 
229
244
  it 'computes the next occurence correctly in local TZ (TZ not specified)' do
230
245
 
231
246
  now = local(1970, 1, 1)
232
247
 
233
- nt('* * * * *', now).should == local(1970, 1, 1, 0, 1)
234
- nt('* * * * sun', now).should == local(1970, 1, 4)
235
- nt('* * * * * *', now).should == local(1970, 1, 1, 0, 0, 1)
236
- nt('* * 13 * fri', now).should == local(1970, 2, 13)
248
+ expect(nt('* * * * *', now)).to eq(local(1970, 1, 1, 0, 1))
249
+ expect(nt('* * * * sun', now)).to eq(local(1970, 1, 4))
250
+ expect(nt('* * * * * *', now)).to eq(local(1970, 1, 1, 0, 0, 1))
251
+ expect(nt('* * 13 * fri', now)).to eq(local(1970, 2, 13))
237
252
 
238
- nt('10 12 13 12 *', now).should == local(1970, 12, 13, 12, 10)
253
+ expect(nt('10 12 13 12 *', now)).to eq(local(1970, 12, 13, 12, 10))
239
254
  # this one is slow (1 year == 3 seconds)
240
- nt('* * 1 6 *', now).should == local(1970, 6, 1)
255
+ expect(nt('* * 1 6 *', now)).to eq(local(1970, 6, 1))
241
256
 
242
- nt('0 0 * * thu', now).should == local(1970, 1, 8)
257
+ expect(nt('0 0 * * thu', now)).to eq(local(1970, 1, 8))
243
258
  end
244
259
 
245
260
  it 'computes the next occurence correctly in UTC (TZ specified)' do
@@ -249,15 +264,15 @@ describe Rufus::Scheduler::CronLine do
249
264
  now = tz.local_to_utc(local(1970, 1, 1))
250
265
  # Midnight in zone, UTC
251
266
 
252
- nt("* * * * * #{zone}", now).should == utc(1969, 12, 31, 23, 1)
253
- nt("* * * * sun #{zone}", now).should == utc(1970, 1, 3, 23)
254
- nt("* * * * * * #{zone}", now).should == utc(1969, 12, 31, 23, 0, 1)
255
- nt("* * 13 * fri #{zone}", now).should == utc(1970, 2, 12, 23)
267
+ expect(nt("* * * * * #{zone}", now)).to eq(utc(1969, 12, 31, 23, 1))
268
+ expect(nt("* * * * sun #{zone}", now)).to eq(utc(1970, 1, 3, 23))
269
+ expect(nt("* * * * * * #{zone}", now)).to eq(utc(1969, 12, 31, 23, 0, 1))
270
+ expect(nt("* * 13 * fri #{zone}", now)).to eq(utc(1970, 2, 12, 23))
256
271
 
257
- nt("10 12 13 12 * #{zone}", now).should == utc(1970, 12, 13, 11, 10)
258
- nt("* * 1 6 * #{zone}", now).should == utc(1970, 5, 31, 23)
272
+ expect(nt("10 12 13 12 * #{zone}", now)).to eq(utc(1970, 12, 13, 11, 10))
273
+ expect(nt("* * 1 6 * #{zone}", now)).to eq(utc(1970, 5, 31, 23))
259
274
 
260
- nt("0 0 * * thu #{zone}", now).should == utc(1970, 1, 7, 23)
275
+ expect(nt("0 0 * * thu #{zone}", now)).to eq(utc(1970, 1, 7, 23))
261
276
  end
262
277
 
263
278
  #it 'computes the next occurence correctly in local TZ (TZ specified)' do
@@ -276,45 +291,85 @@ describe Rufus::Scheduler::CronLine do
276
291
 
277
292
  it 'computes the next time correctly when there is a sun#2 involved' do
278
293
 
279
- nt('* * * * sun#1', local(1970, 1, 1)).should == local(1970, 1, 4)
280
- nt('* * * * sun#2', local(1970, 1, 1)).should == local(1970, 1, 11)
294
+ expect(nt('* * * * sun#1', local(1970, 1, 1))).to eq(local(1970, 1, 4))
295
+ expect(nt('* * * * sun#2', local(1970, 1, 1))).to eq(local(1970, 1, 11))
281
296
 
282
- nt('* * * * sun#2', local(1970, 1, 12)).should == local(1970, 2, 8)
297
+ expect(nt('* * * * sun#2', local(1970, 1, 12))).to eq(local(1970, 2, 8))
283
298
  end
284
299
 
285
- it 'computes the next time correctly when there is a sun#2,sun#3 involved' do
300
+ it 'computes next time correctly when there is a sun#2,sun#3 involved' do
286
301
 
287
- nt('* * * * sun#2,sun#3', local(1970, 1, 1)).should == local(1970, 1, 11)
288
- nt('* * * * sun#2,sun#3', local(1970, 1, 12)).should == local(1970, 1, 18)
302
+ expect(
303
+ nt('* * * * sun#2,sun#3', local(1970, 1, 1))).to eq(local(1970, 1, 11))
304
+ expect(
305
+ nt('* * * * sun#2,sun#3', local(1970, 1, 12))).to eq(local(1970, 1, 18))
289
306
  end
290
307
 
291
308
  it 'understands sun#L' do
292
309
 
293
- nt('* * * * sun#L', local(1970, 1, 1)).should == local(1970, 1, 25)
310
+ expect(nt('* * * * sun#L', local(1970, 1, 1))).to eq(local(1970, 1, 25))
294
311
  end
295
312
 
296
313
  it 'understands sun#-1' do
297
314
 
298
- nt('* * * * sun#-1', local(1970, 1, 1)).should == local(1970, 1, 25)
315
+ expect(nt('* * * * sun#-1', local(1970, 1, 1))).to eq(local(1970, 1, 25))
299
316
  end
300
317
 
301
318
  it 'understands sun#-2' do
302
319
 
303
- nt('* * * * sun#-2', local(1970, 1, 1)).should == local(1970, 1, 18)
320
+ expect(nt('* * * * sun#-2', local(1970, 1, 1))).to eq(local(1970, 1, 18))
304
321
  end
305
322
 
306
323
  it 'computes the next time correctly when "L" (last day of month)' do
307
324
 
308
- nt('* * L * *', lo(1970, 1, 1)).should == lo(1970, 1, 31)
309
- nt('* * L * *', lo(1970, 2, 1)).should == lo(1970, 2, 28)
310
- nt('* * L * *', lo(1972, 2, 1)).should == lo(1972, 2, 29)
311
- nt('* * L * *', lo(1970, 4, 1)).should == lo(1970, 4, 30)
325
+ expect(nt('* * L * *', lo(1970, 1, 1))).to eq(lo(1970, 1, 31))
326
+ expect(nt('* * L * *', lo(1970, 2, 1))).to eq(lo(1970, 2, 28))
327
+ expect(nt('* * L * *', lo(1972, 2, 1))).to eq(lo(1972, 2, 29))
328
+ expect(nt('* * L * *', lo(1970, 4, 1))).to eq(lo(1970, 4, 30))
312
329
  end
313
330
 
314
331
  it 'returns a time with subseconds chopped off' do
315
332
 
316
- nt('* * * * *', Time.now).usec.should == 0
317
- nt('* * * * *', Time.now).iso8601(10).match(/\.0+[^\d]/).should_not == nil
333
+ expect(
334
+ nt('* * * * *', Time.now).usec).to eq(0)
335
+ expect(
336
+ nt('* * * * *', Time.now).iso8601(10).match(/\.0+[^\d]/)).not_to eq(nil)
337
+ end
338
+
339
+ # New York EST: UTC-5
340
+ # summer (dst) EDT: UTC-4
341
+
342
+ # gh-127
343
+ #
344
+ it 'survives TZInfo::AmbiguousTime' do
345
+
346
+ if ruby18? or jruby?
347
+ expect(
348
+ ntz(
349
+ '30 1 31 10 * America/New_York',
350
+ ltz('America/New_York', 2004, 10, 1)
351
+ ).strftime('%Y-%m-%d %H:%M:%S')
352
+ ).to eq('2004-10-31 01:30:00')
353
+ else
354
+ expect(
355
+ ntz(
356
+ '30 1 31 10 * America/New_York',
357
+ ltz('America/New_York', 2004, 10, 1)
358
+ )
359
+ ).to eq(ltz('America/New_York', 2004, 10, 31, 1, 30, 0))
360
+ end
361
+ end
362
+
363
+ # gh-127
364
+ #
365
+ it 'survives TZInfo::PeriodNotFound' do
366
+
367
+ expect(
368
+ ntz(
369
+ '0 2 9 3 * America/New_York',
370
+ ltz('America/New_York', 2014, 3, 1)
371
+ )
372
+ ).to eq(ltz('America/New_York', 2015, 3, 9, 2, 0, 0))
318
373
  end
319
374
  end
320
375
 
@@ -323,15 +378,61 @@ describe Rufus::Scheduler::CronLine do
323
378
  def pt(cronline, now)
324
379
  Rufus::Scheduler::CronLine.new(cronline).previous_time(now)
325
380
  end
381
+ def ptz(cronline, now)
382
+ tz = cronline.split.last
383
+ tu = pt(cronline, now).utc
384
+ in_zone(tz) { tu.getlocal }
385
+ end
326
386
 
327
387
  it 'returns the previous time the cron should have triggered' do
328
388
 
329
- pt('* * * * sun', lo(1970, 1, 1)).should == lo(1969, 12, 28, 23, 59, 00)
330
- pt('* * 13 * *', lo(1970, 1, 1)).should == lo(1969, 12, 13, 23, 59, 00)
331
- pt('0 12 13 * *', lo(1970, 1, 1)).should == lo(1969, 12, 13, 12, 00)
332
- pt('0 0 2 1 *', lo(1970, 1, 1)).should == lo(1969, 1, 2, 0, 00)
389
+ expect(
390
+ pt('* * * * sun', lo(1970, 1, 1))).to eq(lo(1969, 12, 28, 23, 59, 00))
391
+ expect(
392
+ pt('* * 13 * *', lo(1970, 1, 1))).to eq(lo(1969, 12, 13, 23, 59, 00))
393
+ expect(
394
+ pt('0 12 13 * *', lo(1970, 1, 1))).to eq(lo(1969, 12, 13, 12, 00))
395
+ expect(
396
+ pt('0 0 2 1 *', lo(1970, 1, 1))).to eq(lo(1969, 1, 2, 0, 00))
397
+
398
+ expect(
399
+ pt('* * * * * sun', lo(1970, 1, 1))).to eq(lo(1969, 12, 28, 23, 59, 59))
400
+ end
401
+
402
+ # New York EST: UTC-5
403
+ # summer (dst) EDT: UTC-4
404
+
405
+ # gh-127
406
+ #
407
+ it 'survives TZInfo::AmbiguousTime' do
408
+
409
+ if ruby18? or jruby?
410
+ expect(
411
+ ptz(
412
+ '30 1 31 10 * America/New_York',
413
+ ltz('America/New_York', 2004, 10, 31, 14, 30, 0)
414
+ ).strftime('%Y-%m-%d %H:%M:%S')
415
+ ).to eq('2004-10-31 01:30:00')
416
+ else
417
+ expect(
418
+ ptz(
419
+ '30 1 31 10 * America/New_York',
420
+ ltz('America/New_York', 2004, 10, 31, 14, 30, 0)
421
+ )
422
+ ).to eq(ltz('America/New_York', 2004, 10, 31, 1, 30, 0))
423
+ end
424
+ end
425
+
426
+ # gh-127
427
+ #
428
+ it 'survives TZInfo::PeriodNotFound' do
333
429
 
334
- pt('* * * * * sun', lo(1970, 1, 1)).should == lo(1969, 12, 28, 23, 59, 59)
430
+ expect(
431
+ ptz(
432
+ '0 2 9 3 * America/New_York',
433
+ ltz('America/New_York', 2015, 3, 9, 12, 0, 0)
434
+ )
435
+ ).to eq(ltz('America/New_York', 2015, 3, 9, 2, 0, 0))
335
436
  end
336
437
  end
337
438
 
@@ -432,11 +533,11 @@ describe Rufus::Scheduler::CronLine do
432
533
 
433
534
  cl = Rufus::Scheduler::CronLine.new('* * * * *')
434
535
 
435
- cl.monthdays(local(1970, 1, 1)).should == %w[ thu#1 thu#-5 ]
436
- cl.monthdays(local(1970, 1, 7)).should == %w[ wed#1 wed#-4 ]
437
- cl.monthdays(local(1970, 1, 14)).should == %w[ wed#2 wed#-3 ]
536
+ expect(cl.monthdays(local(1970, 1, 1))).to eq(%w[ thu#1 thu#-5 ])
537
+ expect(cl.monthdays(local(1970, 1, 7))).to eq(%w[ wed#1 wed#-4 ])
538
+ expect(cl.monthdays(local(1970, 1, 14))).to eq(%w[ wed#2 wed#-3 ])
438
539
 
439
- cl.monthdays(local(2011, 3, 11)).should == %w[ fri#2 fri#-3 ]
540
+ expect(cl.monthdays(local(2011, 3, 11))).to eq(%w[ fri#2 fri#-3 ])
440
541
  end
441
542
  end
442
543
 
@@ -444,20 +545,20 @@ describe Rufus::Scheduler::CronLine do
444
545
 
445
546
  it 'returns the shortest delta between two occurrences' do
446
547
 
447
- Rufus::Scheduler::CronLine.new(
448
- '* * * * *').frequency.should == 60
449
- Rufus::Scheduler::CronLine.new(
450
- '* * * * * *').frequency.should == 1
548
+ expect(Rufus::Scheduler::CronLine.new(
549
+ '* * * * *').frequency).to eq(60)
550
+ expect(Rufus::Scheduler::CronLine.new(
551
+ '* * * * * *').frequency).to eq(1)
451
552
 
452
- Rufus::Scheduler::CronLine.new(
453
- '5 23 * * *').frequency.should == 24 * 3600
454
- Rufus::Scheduler::CronLine.new(
455
- '5 * * * *').frequency.should == 3600
456
- Rufus::Scheduler::CronLine.new(
457
- '10,20,30 * * * *').frequency.should == 600
553
+ expect(Rufus::Scheduler::CronLine.new(
554
+ '5 23 * * *').frequency).to eq(24 * 3600)
555
+ expect(Rufus::Scheduler::CronLine.new(
556
+ '5 * * * *').frequency).to eq(3600)
557
+ expect(Rufus::Scheduler::CronLine.new(
558
+ '10,20,30 * * * *').frequency).to eq(600)
458
559
 
459
- Rufus::Scheduler::CronLine.new(
460
- '10,20,30 * * * * *').frequency.should == 10
560
+ expect(Rufus::Scheduler::CronLine.new(
561
+ '10,20,30 * * * * *').frequency).to eq(10)
461
562
  end
462
563
  end
463
564
 
@@ -465,17 +566,17 @@ describe Rufus::Scheduler::CronLine do
465
566
 
466
567
  it 'returns the shortest delta between two occurrences' do
467
568
 
468
- Rufus::Scheduler::CronLine.new(
469
- '* * * * *').brute_frequency.should == 60
470
- Rufus::Scheduler::CronLine.new(
471
- '* * * * * *').brute_frequency.should == 1
569
+ expect(Rufus::Scheduler::CronLine.new(
570
+ '* * * * *').brute_frequency).to eq(60)
571
+ expect(Rufus::Scheduler::CronLine.new(
572
+ '* * * * * *').brute_frequency).to eq(1)
472
573
 
473
- Rufus::Scheduler::CronLine.new(
474
- '5 23 * * *').brute_frequency.should == 24 * 3600
475
- Rufus::Scheduler::CronLine.new(
476
- '5 * * * *').brute_frequency.should == 3600
477
- Rufus::Scheduler::CronLine.new(
478
- '10,20,30 * * * *').brute_frequency.should == 600
574
+ expect(Rufus::Scheduler::CronLine.new(
575
+ '5 23 * * *').brute_frequency).to eq(24 * 3600)
576
+ expect(Rufus::Scheduler::CronLine.new(
577
+ '5 * * * *').brute_frequency).to eq(3600)
578
+ expect(Rufus::Scheduler::CronLine.new(
579
+ '10,20,30 * * * *').brute_frequency).to eq(600)
479
580
 
480
581
  #Rufus::Scheduler::CronLine.new(
481
582
  # '10,20,30 * * * * *').brute_frequency.should == 10
@@ -513,8 +614,8 @@ describe Rufus::Scheduler::CronLine do
513
614
 
514
615
  # verify the playground...
515
616
  #
516
- friday.isdst.should == false
517
- (friday + 24 * 3600 * 3).isdst.should == true
617
+ expect(friday.isdst).to eq(false)
618
+ expect((friday + 24 * 3600 * 3).isdst).to eq(true)
518
619
 
519
620
  cl0 = Rufus::Scheduler::CronLine.new('02 00 * * 1,2,3,4,5')
520
621
  cl1 = Rufus::Scheduler::CronLine.new('45 08 * * 1,2,3,4,5')
@@ -522,14 +623,16 @@ describe Rufus::Scheduler::CronLine do
522
623
  n0 = cl0.next_time(friday)
523
624
  n1 = cl1.next_time(friday)
524
625
 
525
- n0.strftime('%H:%M:%S %^a').should == '00:02:00 MON'
526
- n1.strftime('%H:%M:%S %^a').should == '08:45:00 MON'
626
+ expect(n0.strftime('%H:%M:%S %^a')).to eq('00:02:00 MON')
627
+ expect(n1.strftime('%H:%M:%S %^a')).to eq('08:45:00 MON')
527
628
 
528
- n0.isdst.should == true
529
- n1.isdst.should == true
629
+ expect(n0.isdst).to eq(true)
630
+ expect(n1.isdst).to eq(true)
530
631
 
531
- (n0 - 24 * 3600 * 3).strftime('%H:%M:%S %^a').should == '23:02:00 THU'
532
- (n1 - 24 * 3600 * 3).strftime('%H:%M:%S %^a').should == '07:45:00 FRI'
632
+ expect(
633
+ (n0 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('23:02:00 THU')
634
+ expect(
635
+ (n1 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('07:45:00 FRI')
533
636
  end
534
637
  end
535
638
 
@@ -552,8 +655,8 @@ describe Rufus::Scheduler::CronLine do
552
655
 
553
656
  # verify the playground...
554
657
  #
555
- friday.isdst.should == true
556
- (friday + 24 * 3600 * 3).isdst.should == false
658
+ expect(friday.isdst).to eq(true)
659
+ expect((friday + 24 * 3600 * 3).isdst).to eq(false)
557
660
 
558
661
  cl0 = Rufus::Scheduler::CronLine.new('02 00 * * 1,2,3,4,5')
559
662
  cl1 = Rufus::Scheduler::CronLine.new('45 08 * * 1,2,3,4,5')
@@ -561,14 +664,16 @@ describe Rufus::Scheduler::CronLine do
561
664
  n0 = cl0.next_time(friday)
562
665
  n1 = cl1.next_time(friday)
563
666
 
564
- n0.strftime('%H:%M:%S %^a').should == '00:02:00 MON'
565
- n1.strftime('%H:%M:%S %^a').should == '08:45:00 MON'
667
+ expect(n0.strftime('%H:%M:%S %^a')).to eq('00:02:00 MON')
668
+ expect(n1.strftime('%H:%M:%S %^a')).to eq('08:45:00 MON')
566
669
 
567
- n0.isdst.should == false
568
- n1.isdst.should == false
670
+ expect(n0.isdst).to eq(false)
671
+ expect(n1.isdst).to eq(false)
569
672
 
570
- (n0 - 24 * 3600 * 3).strftime('%H:%M:%S %^a').should == '01:02:00 FRI'
571
- (n1 - 24 * 3600 * 3).strftime('%H:%M:%S %^a').should == '09:45:00 FRI'
673
+ expect(
674
+ (n0 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('01:02:00 FRI')
675
+ expect(
676
+ (n1 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('09:45:00 FRI')
572
677
  end
573
678
  end
574
679
  end