rufus-scheduler 3.0.7 → 3.0.8

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,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