recurring 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +5 -0
- data/Manifest.txt +6 -0
- data/README.txt +65 -0
- data/Rakefile +25 -0
- data/lib/recurring.rb +304 -0
- data/spec/recurring_spec.rb +602 -0
- metadata +58 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
Recurring::Schedule
|
2
|
+
by Chris Anderson
|
3
|
+
http://recurring.rubyforge.org
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Recurring allows you to define Schedules, which can tell you whether or not a given Time falls in the Schedule, as well as being able to return a list of times which match the Schedule within a given range.
|
8
|
+
|
9
|
+
Schedules can be like:
|
10
|
+
* Every Tuesday at 5pm
|
11
|
+
* The 1st and 15th of every other month
|
12
|
+
* Every 2 hours
|
13
|
+
* The first Friday of every month at 11:15am and 4:45:15pm
|
14
|
+
|
15
|
+
== FEATURES/PROBLEMS:
|
16
|
+
|
17
|
+
= Features
|
18
|
+
* Fast searching of long ranges for matching times.
|
19
|
+
* Ability to define Schedules in a few flexible ways.
|
20
|
+
* Extensive RSpec specifications (run "rake spec" to see them)
|
21
|
+
* Extensive RSpec specifications (run "rake spec" to see them)
|
22
|
+
|
23
|
+
= Problems / Todo
|
24
|
+
* Untested timezone support
|
25
|
+
* Plans to offer complex Schedule and Masks
|
26
|
+
|
27
|
+
== SYNOPSYS:
|
28
|
+
|
29
|
+
# This Schedule will match every Tuesday at 5pm
|
30
|
+
@rs = Recurring::Schedule.new :unit => 'weeks', :weekdays => 'tuesday', :times => '5pm'
|
31
|
+
@rs.include?(Time.utc(2006,12,12,17)) #=> true
|
32
|
+
@rs.include?(Time.utc(2006,12,13,17)) #=> false
|
33
|
+
|
34
|
+
== REQUIREMENTS:
|
35
|
+
|
36
|
+
* RSpec >= 0.7.4 to run the specs.
|
37
|
+
|
38
|
+
== INSTALL:
|
39
|
+
|
40
|
+
* just run <tt>gem install recurring</tt>
|
41
|
+
|
42
|
+
== LICENSE:
|
43
|
+
|
44
|
+
(The MIT License)
|
45
|
+
|
46
|
+
Copyright (c) 2006 Chris Anderson
|
47
|
+
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
49
|
+
a copy of this software and associated documentation files (the
|
50
|
+
'Software'), to deal in the Software without restriction, including
|
51
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
52
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
53
|
+
permit persons to whom the Software is furnished to do so, subject to
|
54
|
+
the following conditions:
|
55
|
+
|
56
|
+
The above copyright notice and this permission notice shall be
|
57
|
+
included in all copies or substantial portions of the Software.
|
58
|
+
|
59
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
60
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
61
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
62
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
63
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
64
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
65
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
#require_gem 'rspec'
|
6
|
+
#require 'rspec/lib/spec/rake/spectask'
|
7
|
+
require './lib/recurring.rb'
|
8
|
+
|
9
|
+
Hoe.new('recurring', Recurring::VERSION) do |p|
|
10
|
+
p.rubyforge_name = 'recurring'
|
11
|
+
p.summary = 'A scheduling library for recurring events'
|
12
|
+
p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
13
|
+
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
14
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Run the specs"
|
18
|
+
task :spec do
|
19
|
+
system "spec spec/recurring_spec.rb -f specdoc"
|
20
|
+
end
|
21
|
+
#Spec::Rake::SpecTask.new('spec') do |t|
|
22
|
+
# t.spec_files = FileList['examples/**/*.rb']
|
23
|
+
#end
|
24
|
+
|
25
|
+
# vim: syntax=Ruby
|
data/lib/recurring.rb
ADDED
@@ -0,0 +1,304 @@
|
|
1
|
+
module Recurring
|
2
|
+
VERSION = '0.1.0'
|
3
|
+
|
4
|
+
class << self
|
5
|
+
# returns a number starting with 1
|
6
|
+
def week_in_month date
|
7
|
+
(((date.day - 1).to_f / 7.0) + 1).floor
|
8
|
+
end
|
9
|
+
|
10
|
+
# just a wrapper for strftime
|
11
|
+
def week_of_year date
|
12
|
+
date.strftime('%U').to_i
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# Initialize a Schedule object with the proper options to calculate occurances in
|
18
|
+
# that schedule. Schedule#new take a hash of options <tt>:unit, :frequency, :anchor, :weeks, :monthdays, :weekdays, :times</tt>
|
19
|
+
#
|
20
|
+
# = Monthly
|
21
|
+
# [Every two months from an anchor time] <tt>Recurring::Schedule.new :unit => 'months', :frequency => 2, :anchor => Time.utc(2006,4,15,10,30)</tt>
|
22
|
+
# [The first and fifteenth of every month] <tt>Recurring::Schedule.new :unit => 'months', :monthdays => [1,15]</tt>
|
23
|
+
# [The first and eighteenth of every third month] <tt>Recurring::Schedule.new :unit => 'months', :frequency => 3, :anchor => Time.utc(2006,4,15,10,30), :monthdays => [10,18]</tt>
|
24
|
+
# [The third Monday of every month at 6:30pm] <tt>Recurring::Schedule.new :unit => 'months', :weeks => 3, :weekdays => :monday, :times => '6:30pm'</tt>
|
25
|
+
# = Weekly
|
26
|
+
# [Monday, Wednesday, and Friday of every week] <tt>Recurring::Schedule.new :unit => 'weeks', :weekdays => %w{monday weds friday}</tt>
|
27
|
+
# [Every week at the same time on the same day of the week as the anchor (Weds at 5:30pm)] <tt>Recurring::Schedule.new :unit => 'weeks', :anchor => Time.utc(2006,12,6,17,30)</tt>
|
28
|
+
# [Equivalently, Every Wednesday at 5:30] <tt>Recurring::Schedule.new :unit => 'weeks', :weekdays => 'weds', :times => '5:30pm'</tt>
|
29
|
+
# = Daily
|
30
|
+
# [Everyday at the time of the anchor] <tt>Recurring::Schedule.new :unit => 'days', :anchor => Time.utc(2006,11,1,10,15,22)</tt>
|
31
|
+
# [Everyday at 7am and 5:45:20pm] <tt>Recurring::Schedule.new :unit => 'days', :times => '7am 5:45:20pm'</tt>
|
32
|
+
# = Hourly
|
33
|
+
# [Every hour at 15 minutes, 30 minutes, and 45 minutes and 30 seconds] <tt>Recurring::Schedule.new :unit => 'hours', :times => '0:15 4:30 0:45:30'</tt>
|
34
|
+
# [Offset every 2 hours from the anchor] <tt>Recurring::Schedule.new :unit => 'hours', :anchor => Time.utc(2001,5,15,11,17)</tt>
|
35
|
+
# = Minutely
|
36
|
+
# [Every five minutes offset from the anchor] <tt>Recurring::Schedule.new :unit => 'minutes', :frequency => 5, :anchor => Time.utc(2006,9,1,10,30)</tt>
|
37
|
+
# [Every minute at second 15] <tt>Recurring::Schedule.new :unit => 'minutes', :times => '0:0:15'</tt>
|
38
|
+
#
|
39
|
+
# See the specs using "rake spec" for even more examples.
|
40
|
+
class Schedule
|
41
|
+
|
42
|
+
attr_reader :unit, :frequency, :anchor, :weeks, :monthdays, :weekdays, :times
|
43
|
+
|
44
|
+
# * options is a hash with keys <tt>:unit, :frequency, :anchor, :weeks, :monthdays, :weekdays, :times</tt>
|
45
|
+
# * valid units are <tt>months, weeks, days, hours, and minutes</tt>
|
46
|
+
# * :frequency defaults to 1
|
47
|
+
# * :anchor is required if the frequency is other than one
|
48
|
+
# * :weeks alongside :weekdays is used to specify the nth instance of a weekday in a month.
|
49
|
+
# * :weekdays takes an array of strings like <tt>%w{monday weds friday}</tt>
|
50
|
+
# * :monthdays takes an array of days of the month, eg. <tt>[1,7,15]</tt>
|
51
|
+
# * :times takes a string with a simple format. <tt>"4pm 5:15pm 6:45:30pm"</tt>
|
52
|
+
def initialize options
|
53
|
+
raise ArgumentError, 'specify a valid unit' unless options[:unit] &&
|
54
|
+
%w{months weeks days hours minutes}.include?(options[:unit])
|
55
|
+
raise ArgumentError, 'frequency > 1 requires an anchor Time' if options[:frequency] && !options[:anchor]
|
56
|
+
@unit = options[:unit].to_sym
|
57
|
+
@frequency = options[:frequency] || 1
|
58
|
+
@anchor = options[:anchor]
|
59
|
+
@times = parse_times options[:times]
|
60
|
+
@weeks = Array(options[:weeks]) if options[:weeks]
|
61
|
+
@weekdays = Array(options[:weekdays]).collect{|d|d.to_sym} if options[:weekdays]
|
62
|
+
@monthdays = Array(options[:monthdays]) if options[:monthdays]
|
63
|
+
|
64
|
+
@anchor_multiple = options[:times].nil? && options[:weeks].nil? && options[:weekdays].nil? && options[:monthdays].nil?
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# Returns true or false depending on whether or not the time is included in the schedule.
|
69
|
+
def include? date
|
70
|
+
@resolution = nil
|
71
|
+
return true if check_anchor? && date == @anchor
|
72
|
+
return mismatch(:month) unless month_matches?(date) if @unit == :months
|
73
|
+
return mismatch(:week) unless week_matches?(date) if [:months, :weeks].include?(@unit)
|
74
|
+
if [:months, :weeks, :days].include?(@unit)
|
75
|
+
return mismatch(:day) unless day_matches?(date)
|
76
|
+
return mismatch(:time) unless time_matches?(date)
|
77
|
+
end
|
78
|
+
if @unit == :hours
|
79
|
+
return mismatch(:hour) unless hour_matches?(date)
|
80
|
+
return mismatch(:sub_hour) unless sub_hour_matches?(date)
|
81
|
+
end
|
82
|
+
if @unit == :minutes
|
83
|
+
return mismatch(:minute) unless minute_matches?(date)
|
84
|
+
return mismatch(:second) unless second_matches?(date)
|
85
|
+
end
|
86
|
+
@resolution = nil
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
# Starts from the argument, and returns the next included time. Returns the argument if it is included in the schedule.
|
91
|
+
def find_next date
|
92
|
+
loop do
|
93
|
+
return date if include?(date)
|
94
|
+
date = beginning_of_next @resolution, date
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Takes a range, which can specified as two Times, or as an object that returns times from the methods .first and .last
|
99
|
+
#
|
100
|
+
# <tt>rs.find_in_range(Time.now, Time.now+24*60*60)</tt>
|
101
|
+
#
|
102
|
+
# or
|
103
|
+
#
|
104
|
+
# <tt>range = (Time.now..Time.now+24*60*60)</tt>
|
105
|
+
#
|
106
|
+
# <tt>rs.find_in_range(range)</tt>
|
107
|
+
def find_in_range *range
|
108
|
+
range = range[0] if range.length == 1
|
109
|
+
start = range.first
|
110
|
+
result = []
|
111
|
+
loop do
|
112
|
+
rnext = find_next start
|
113
|
+
break if rnext > range.last
|
114
|
+
result << rnext
|
115
|
+
start = rnext + 1
|
116
|
+
end
|
117
|
+
result
|
118
|
+
end
|
119
|
+
|
120
|
+
# Two Schedules are equal if they have the same attributes.
|
121
|
+
def == other
|
122
|
+
[:unit, :frequency, :anchor, :weeks, :monthdays, :weekdays, :times].all? do |attribute|
|
123
|
+
self.send(attribute) == other.send(attribute)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def beginning_of_next scope, date
|
130
|
+
case scope
|
131
|
+
when :year
|
132
|
+
Time.utc(date.year + 1)
|
133
|
+
when :month
|
134
|
+
date.month < 12 ? Time.utc(date.year, date.month+1) : beginning_of_next(:year, date)
|
135
|
+
when :week
|
136
|
+
to_sunday = 7 - date.wday
|
137
|
+
next_week = (date + to_sunday*24*60*60)
|
138
|
+
Time.utc(next_week.year, next_week.month, next_week.day)
|
139
|
+
when :day
|
140
|
+
dayp = date + (24*60*60)
|
141
|
+
Time.utc(dayp.year, dayp.month, dayp.day)
|
142
|
+
when :time
|
143
|
+
next_time date
|
144
|
+
else
|
145
|
+
date + 1
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def next_time date
|
150
|
+
me = {:hour => date.hour, :minute => date.min, :second => date.sec, :me => true}
|
151
|
+
my_times = times + [me]
|
152
|
+
my_times += [{:hour => @anchor.hour, :minute => @anchor.min, :second => @anchor.sec}] if check_anchor?
|
153
|
+
my_times.sort! do |a,b|
|
154
|
+
v = a[:hour] <=> b[:hour]
|
155
|
+
v = a[:minute] <=> b[:minute] if v == 0
|
156
|
+
v = a[:second] <=> b[:second] if v == 0
|
157
|
+
v
|
158
|
+
end
|
159
|
+
ntime = my_times[my_times.index(me)+1]
|
160
|
+
if ntime
|
161
|
+
Time.utc(date.year, date.month, date.day, ntime[:hour], ntime[:minute], ntime[:second])
|
162
|
+
else
|
163
|
+
beginning_of_next :day, date
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def mismatch unit
|
168
|
+
@resolution = unit
|
169
|
+
false
|
170
|
+
end
|
171
|
+
|
172
|
+
def month_matches? date
|
173
|
+
#only concerned with multiples
|
174
|
+
return true if @frequency == 1
|
175
|
+
(date.month - @anchor.month) % @frequency == 0
|
176
|
+
end
|
177
|
+
|
178
|
+
def week_matches? date
|
179
|
+
if @unit == :weeks
|
180
|
+
return true if @frequency == 1
|
181
|
+
return (Recurring.week_of_year(date) - Recurring.week_of_year(@anchor)) % @frequency == 0
|
182
|
+
end
|
183
|
+
if @weeks
|
184
|
+
@weeks.include?(Recurring.week_in_month(date))
|
185
|
+
else
|
186
|
+
true
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def day_matches? date
|
191
|
+
if @unit == :days
|
192
|
+
return true if @frequency == 1
|
193
|
+
return (date.day - @anchor.day) % @frequency == 0
|
194
|
+
end
|
195
|
+
return @monthdays.include?(date.day) if @monthdays
|
196
|
+
if @weekdays
|
197
|
+
day_nums = @weekdays.collect{|w| ordinal_weekday w}
|
198
|
+
return day_nums.include?(date.wday)
|
199
|
+
end
|
200
|
+
if @unit == :weeks && check_anchor?
|
201
|
+
return @anchor.wday == date.wday
|
202
|
+
end
|
203
|
+
return true if check_anchor? && date.day == @anchor.day
|
204
|
+
end
|
205
|
+
|
206
|
+
def time_matches? date
|
207
|
+
#concerned with groups of hour minute second
|
208
|
+
if check_anchor?
|
209
|
+
return @anchor.hour == date.hour && @anchor.min == date.min && @anchor.sec == date.sec
|
210
|
+
end
|
211
|
+
@times.any? do |time|
|
212
|
+
time[:hour] == date.hour && time[:minute] == date.min && time[:second] == date.sec
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def hour_matches? date
|
217
|
+
#only concerned with multiples
|
218
|
+
return true if @frequency == 1
|
219
|
+
(date.hour - @anchor.hour) % @frequency == 0
|
220
|
+
end
|
221
|
+
|
222
|
+
def sub_hour_matches? date
|
223
|
+
if check_anchor?
|
224
|
+
return @anchor.min == date.min && @anchor.sec == date.sec
|
225
|
+
end
|
226
|
+
times.any? do |time|
|
227
|
+
time[:minute] == date.min && time[:second] == date.sec
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def minute_matches? date
|
232
|
+
#only concerned with multiples
|
233
|
+
return true if @frequency == 1
|
234
|
+
(date.min - @anchor.min) % @frequency == 0
|
235
|
+
end
|
236
|
+
|
237
|
+
def second_matches? date
|
238
|
+
if check_anchor?
|
239
|
+
return @anchor.sec == date.sec
|
240
|
+
end
|
241
|
+
times.any? do |time|
|
242
|
+
time[:second] == date.sec
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def check_anchor?
|
247
|
+
@anchor && @anchor_multiple
|
248
|
+
end
|
249
|
+
|
250
|
+
def ordinal_weekday symbol
|
251
|
+
lookup = {0 => [:sunday, :sun],
|
252
|
+
1 => [:monday, :mon],
|
253
|
+
2 => [:tuesday, :tues],
|
254
|
+
3 => [:wednesday, :weds],
|
255
|
+
4 => [:thursday, :thurs],
|
256
|
+
5 => [:friday, :fri],
|
257
|
+
6 => [:saturday, :sat]}
|
258
|
+
lookup.select{|k,v| v.include?(symbol)}.first.first
|
259
|
+
end
|
260
|
+
|
261
|
+
# def ordinal_month symbol
|
262
|
+
# lookup = {1 => [:january, :jan],
|
263
|
+
# 2 => [:february, :feb],
|
264
|
+
# 3 => [:march, :mar],
|
265
|
+
# 4 => [:april, :apr],
|
266
|
+
# 5 => [:may],
|
267
|
+
# 6 => [:june, :jun],
|
268
|
+
# 7 => [:july, :jul],
|
269
|
+
# 8 => [:august, :aug],
|
270
|
+
# 9 => [:september, :sept],
|
271
|
+
# 10 => [:october, :oct],
|
272
|
+
# 11 => [:november, :nov],
|
273
|
+
# 12 => [:december, :dec]}
|
274
|
+
# lookup.select{|k,v| v.include?(symbol)}.first.first
|
275
|
+
# end
|
276
|
+
|
277
|
+
def parse_times string
|
278
|
+
unless string
|
279
|
+
return [{:hour => 0, :minute => 0, :second => 0}]
|
280
|
+
end
|
281
|
+
times = string.downcase.gsub(',','').split(' ')
|
282
|
+
parsed = times.collect do |st|
|
283
|
+
st = st.gsub /pm|am/, ''
|
284
|
+
am_pm = $&
|
285
|
+
time = {}
|
286
|
+
time[:hour], time[:minute], time[:second] = st.split(':').collect {|n| n.to_i}
|
287
|
+
time[:minute] ||= 0
|
288
|
+
time[:second] ||= 0
|
289
|
+
time[:hour] = time[:hour] + 12 if am_pm == 'pm'
|
290
|
+
time
|
291
|
+
end
|
292
|
+
parsed
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
|
298
|
+
# RDS does not match ranges as such, just times specified to varying precision
|
299
|
+
# eg, you can construct a Schedule that matches all of February, by not specifying the
|
300
|
+
# week, day, or time. If you want February through August, you'll have to specify all the months
|
301
|
+
# individually.
|
302
|
+
|
303
|
+
# Change of Behaviour in Recurring: Schedules include only points in time. The Mask model handles ranges.
|
304
|
+
|
@@ -0,0 +1,602 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require_gem 'rspec'
|
3
|
+
require File.dirname(__FILE__) + "/../lib/recurring"
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
def results_should_be_included results, schedule
|
7
|
+
results.each do |t|
|
8
|
+
schedule.should_include t
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def should_find_in_range schedule, length, *range
|
13
|
+
result = schedule.find_in_range(range.first, range.last)
|
14
|
+
result.length.should_be length
|
15
|
+
results_should_be_included result, schedule
|
16
|
+
end
|
17
|
+
|
18
|
+
context "Initializing a Schedule" do
|
19
|
+
|
20
|
+
specify "should accept the frequency, unit, and anchor params" do
|
21
|
+
rs = Recurring::Schedule.new :unit => 'days', :frequency => 2, :anchor => Time.utc(2006,8,11)
|
22
|
+
rs.unit.should_be :days
|
23
|
+
rs.frequency.should_be 2
|
24
|
+
rs.anchor.should == Time.utc(2006,8,11)
|
25
|
+
end
|
26
|
+
|
27
|
+
specify "should check for valid units" do
|
28
|
+
lambda{@rs = Recurring::Schedule.new :unit => 'day', :times => '4:29am'}.should_raise ArgumentError
|
29
|
+
end
|
30
|
+
|
31
|
+
specify "should parse the time param" do
|
32
|
+
rs = Recurring::Schedule.new :unit => 'days', :times => '4:30pm 5pm 3:30:30'
|
33
|
+
rs.times.should == [{:hour => 16, :minute => 30, :second => 0}, {:hour => 17, :minute => 0, :second => 0}, {:hour => 3, :minute => 30, :second => 30}]
|
34
|
+
end
|
35
|
+
|
36
|
+
specify "should provide a sensible default time param" do
|
37
|
+
rs = Recurring::Schedule.new :unit => 'days'
|
38
|
+
rs.times.should == [{:hour => 0, :minute => 0, :second => 0}]
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "should flip out if the units are not provided" do
|
42
|
+
lambda{Recurring::Schedule.new :argument => 'no units, dogg'}.should_raise ArgumentError
|
43
|
+
end
|
44
|
+
|
45
|
+
specify "should accept weeks and days params" do
|
46
|
+
rs = Recurring::Schedule.new :unit => 'months', :weeks => [1,2], :weekdays => %w{monday wednesday}
|
47
|
+
rs.weeks.should == [1,2]
|
48
|
+
rs.weekdays.should == [:monday, :wednesday]
|
49
|
+
end
|
50
|
+
|
51
|
+
specify "should accept days as integers" do
|
52
|
+
rs = Recurring::Schedule.new :unit => 'months', :monthdays => [1,15]
|
53
|
+
rs.monthdays.should == [1,15]
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
context "A complex Schedule" do
|
59
|
+
setup do
|
60
|
+
@rs = Recurring::Schedule.new :unit => 'months', :frequency => 2, :anchor => Time.utc(2006,4,15,10,30), :monthdays => [3,7], :times => '5pm 4:45:12am'
|
61
|
+
end
|
62
|
+
|
63
|
+
specify "should be marshallable" do
|
64
|
+
rm = Marshal.dump(@rs)
|
65
|
+
Marshal.load(rm).should == @rs
|
66
|
+
end
|
67
|
+
|
68
|
+
specify "should be YAMLable" do
|
69
|
+
rm = YAML.dump(@rs)
|
70
|
+
YAML.load(rm).should == @rs
|
71
|
+
end
|
72
|
+
|
73
|
+
specify "should be equal to a schedule with the same params" do
|
74
|
+
r2 = Recurring::Schedule.new :unit => 'months', :frequency => 2, :anchor => Time.utc(2006,4,15,10,30), :monthdays => [3,7], :times => '5pm 4:45:12am'
|
75
|
+
r2.should == @rs
|
76
|
+
end
|
77
|
+
|
78
|
+
specify "should not be equal to a slightly different schedule" do
|
79
|
+
r2 = Recurring::Schedule.new :unit => 'months', :frequency => 2, :anchor => Time.utc(2006,4,15,10,30), :monthdays => [3,7], :times => '5pm 4:45:11am'
|
80
|
+
r2.should_not_equal @rs
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
#MONTHS
|
86
|
+
|
87
|
+
context "A bi-monthly Schedule without more params" do
|
88
|
+
|
89
|
+
setup do
|
90
|
+
@rs = Recurring::Schedule.new :unit => 'months', :frequency => 2, :anchor => Time.utc(2006,4,15,10,30)
|
91
|
+
end
|
92
|
+
|
93
|
+
specify "should include the anchor date" do
|
94
|
+
@rs.should_include Time.utc(2006,4,15,10,30)
|
95
|
+
end
|
96
|
+
|
97
|
+
specify "should include dates offset by the frequency" do
|
98
|
+
@rs.should_include Time.utc(2006,6,15,10,30)
|
99
|
+
end
|
100
|
+
|
101
|
+
specify "should not include the beginnings of days for which it includes points in the middle" do
|
102
|
+
@rs.should_not_include Time.utc(2006,6,15)
|
103
|
+
@rs.should_not_include Time.utc(2006,4,15)
|
104
|
+
end
|
105
|
+
|
106
|
+
specify "should not include dates with wrong months" do
|
107
|
+
@rs.should_not_include Time.utc(2006,5,15,10,30)
|
108
|
+
end
|
109
|
+
|
110
|
+
specify "should not include dates without matching time parts" do
|
111
|
+
@rs.should_not_include Time.utc(2006,4,16)
|
112
|
+
@rs.should_not_include Time.utc(2006,6,15,10,15)
|
113
|
+
end
|
114
|
+
|
115
|
+
specify "should find that the start point is the next included date when the start point matches" do
|
116
|
+
included = Time.utc(2006,6,15,10,30)
|
117
|
+
@rs.find_next(included).should == included
|
118
|
+
end
|
119
|
+
|
120
|
+
specify "should find the next date when the start point doesn't match" do
|
121
|
+
@rs.find_next(Time.utc(2006,6,15)).should == Time.utc(2006,6,15,10,30)
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
context "A monthly schedule with monthday params" do
|
127
|
+
setup do
|
128
|
+
@rs = Recurring::Schedule.new :unit => 'months', :monthdays => [1,15]
|
129
|
+
# @rs.anchor = Time.utc(2006,6,18,12,30) #should react appropriately to the presence of a (no longer useless) anchor
|
130
|
+
end
|
131
|
+
|
132
|
+
specify "should include the start of matching days" do
|
133
|
+
@rs.should_include Time.utc(2006,6,15)
|
134
|
+
@rs.should_include Time.utc(2006,7,1)
|
135
|
+
end
|
136
|
+
|
137
|
+
specify "should not include the middle of matching days" do
|
138
|
+
@rs.should_not_include Time.utc(2006,6,15,14)
|
139
|
+
@rs.should_not_include Time.utc(2006,7,1,11,30)
|
140
|
+
@rs.should_not_include Time.utc(2006,7,1,0,0,30)
|
141
|
+
end
|
142
|
+
|
143
|
+
specify "should not include the start of non-matching days" do
|
144
|
+
@rs.should_not_include Time.utc(2006,6,14)
|
145
|
+
@rs.should_not_include Time.utc(2006,7,2)
|
146
|
+
end
|
147
|
+
|
148
|
+
specify "should not include times with no matching component" do
|
149
|
+
@rs.should_not_include Time.utc(2006,6,14,11,8)
|
150
|
+
@rs.should_not_include Time.utc(2006,7,2,5,30)
|
151
|
+
end
|
152
|
+
|
153
|
+
specify "should find the next date" do
|
154
|
+
@rs.find_next(Time.utc(2006,3,4)).should == Time.utc(2006,3,15)
|
155
|
+
@rs.find_next(Time.utc(2006,3,17)).should == Time.utc(2006,4,1)
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
context "A bi-monthly Schedule with monthday params" do
|
161
|
+
|
162
|
+
setup do
|
163
|
+
@rs = Recurring::Schedule.new :unit => 'months', :frequency => 2, :anchor => Time.utc(2006,4,15,10,30), :monthdays => [10,18]
|
164
|
+
end
|
165
|
+
|
166
|
+
specify "should include the beginnings of matching days" do
|
167
|
+
@rs.should_include Time.utc(2006,6,10)
|
168
|
+
@rs.should_include Time.utc(2006,8,18)
|
169
|
+
end
|
170
|
+
|
171
|
+
specify "should not include the beginnings of non_matching days" do
|
172
|
+
@rs.should_not_include Time.utc(2006,6,11)
|
173
|
+
end
|
174
|
+
|
175
|
+
specify "should not include the beginning of the anchor day" do
|
176
|
+
@rs.should_not_include Time.utc(2006,4,15)
|
177
|
+
end
|
178
|
+
|
179
|
+
specify "should not include the anchor time" do
|
180
|
+
@rs.should_not_include Time.utc(2006,4,15,10,30)
|
181
|
+
end
|
182
|
+
|
183
|
+
specify "should find the next date when the start point doesn't match" do
|
184
|
+
@rs.find_next(Time.utc(2006,6,15)).should == Time.utc(2006,6,18)
|
185
|
+
end
|
186
|
+
|
187
|
+
specify "should find the next date" do
|
188
|
+
@rs.find_next(Time.utc(2006,5,4)).should == Time.utc(2006,6,10)
|
189
|
+
@rs.find_next(Time.utc(2006,6,11)).should == Time.utc(2006,6,18)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context "A monthly schedule with week params" do
|
194
|
+
end
|
195
|
+
|
196
|
+
context "A third-monthly schedule with week params" do
|
197
|
+
|
198
|
+
setup do
|
199
|
+
lambda{@rs = Recurring::Schedule.new :unit => 'months', :week => 1, :frequency => 3}.should_raise ArgumentError
|
200
|
+
end
|
201
|
+
|
202
|
+
specify "should walk up the stairs" do
|
203
|
+
end
|
204
|
+
|
205
|
+
# should = *specify
|
206
|
+
#
|
207
|
+
# should "walk up the stairs" do
|
208
|
+
# @rs.should_include Time.utc(2007,11,14)
|
209
|
+
# end
|
210
|
+
end
|
211
|
+
|
212
|
+
context "A monthly schedule with week params and weekday params" do
|
213
|
+
|
214
|
+
setup do
|
215
|
+
@rs = Recurring::Schedule.new :unit => 'months', :weeks => 1, :weekdays => :monday
|
216
|
+
end
|
217
|
+
|
218
|
+
specify "should include the beginnings of matching days" do
|
219
|
+
@rs.should_include Time.utc(2006,12,4)
|
220
|
+
end
|
221
|
+
|
222
|
+
specify "should not include the matching days in off weeks" do
|
223
|
+
@rs.should_not_include Time.utc(2006,12,18)
|
224
|
+
@rs.should_not_include Time.utc(2006,11,27)
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
context "A monthly schedule with weekday params but no week params" do
|
230
|
+
end
|
231
|
+
|
232
|
+
context "A six-monthly schedule with week, weekday, and times params" do
|
233
|
+
end
|
234
|
+
|
235
|
+
#WEEKLY
|
236
|
+
|
237
|
+
context "A weekly schedule with weekday params" do
|
238
|
+
|
239
|
+
setup do
|
240
|
+
@rs = Recurring::Schedule.new :unit => 'weeks', :weekdays => %w{sunday monday weds friday}
|
241
|
+
end
|
242
|
+
|
243
|
+
specify "should include the beginnings of matching days" do
|
244
|
+
@rs.should_include Time.utc(2006,12,3)
|
245
|
+
@rs.should_include Time.utc(2006,12,6)
|
246
|
+
@rs.should_include Time.utc(2006,11,27)
|
247
|
+
end
|
248
|
+
|
249
|
+
specify "should not include the middle of matching days" do
|
250
|
+
@rs.should_not_include Time.utc(2006,12,6,10,30)
|
251
|
+
@rs.should_not_include Time.utc(2006,11,27,0,30)
|
252
|
+
@rs.should_not_include Time.utc(2006,12,7)
|
253
|
+
end
|
254
|
+
|
255
|
+
specify "should find the next date" do
|
256
|
+
@rs.find_next(Time.utc(2006,12,2)).should == Time.utc(2006,12,3)
|
257
|
+
@rs.find_next(Time.utc(2006,11,30)).should == Time.utc(2006,12,1)
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
|
262
|
+
context "A weekly schedule with only an anchor" do
|
263
|
+
|
264
|
+
setup do
|
265
|
+
@rs = Recurring::Schedule.new :unit => 'weeks', :anchor => Time.utc(2006,12,6,17,30)
|
266
|
+
end
|
267
|
+
|
268
|
+
specify "should include times that are offset by one week" do
|
269
|
+
@rs.should_include Time.utc(2006,12,20,17,30)
|
270
|
+
end
|
271
|
+
|
272
|
+
specify "should not include times that are not offset by one week" do
|
273
|
+
@rs.should_not_include Time.utc(2006,12,19,17,30)
|
274
|
+
@rs.should_not_include Time.utc(2006,12,20)
|
275
|
+
@rs.should_not_include Time.utc(2006,5,6,17,30)
|
276
|
+
end
|
277
|
+
|
278
|
+
specify "should find the next date" do
|
279
|
+
@rs.find_next(Time.utc(2006,5,4)).should == Time.utc(2006,5,10,17,30)
|
280
|
+
@rs.find_next(Time.utc(2006,6,11)).should == Time.utc(2006,6,14,17,30)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
context "A third-weekly schedule with weekday and times params" do
|
285
|
+
|
286
|
+
setup do
|
287
|
+
@rs = Recurring::Schedule.new :unit => 'weeks', :frequency => 3, :anchor => Time.utc(2006,12,1), :weekdays => %w{mon fri sat}, :times => '3pm'
|
288
|
+
end
|
289
|
+
|
290
|
+
specify "should include the proper times on the right days of matching weeks" do
|
291
|
+
@rs.should_include Time.utc(2006,11,27,15)
|
292
|
+
@rs.should_include Time.utc(2006,12,1,15)
|
293
|
+
@rs.should_include Time.utc(2006,12,2,15)
|
294
|
+
@rs.should_include Time.utc(2006,12,18,15)
|
295
|
+
end
|
296
|
+
|
297
|
+
specify "should not include the beginnings of matching days" do
|
298
|
+
@rs.should_not_include Time.utc(2006,12,1)
|
299
|
+
end
|
300
|
+
|
301
|
+
specify "should not include the proper times on the right days of non-matching weeks" do
|
302
|
+
@rs.should_not_include Time.utc(2006,12,4,15)
|
303
|
+
end
|
304
|
+
|
305
|
+
specify "should find the next date" do
|
306
|
+
@rs.find_next(Time.utc(2006,12,4)).should == Time.utc(2006,12,18,15)
|
307
|
+
@rs.find_next(Time.utc(2006,12,18)).should == Time.utc(2006,12,18,15)
|
308
|
+
end
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
context "Recurring.week_of_year" do
|
313
|
+
|
314
|
+
specify "should return the same value for days in the same week" do
|
315
|
+
[[2006,12,1],
|
316
|
+
[2006,12,2],
|
317
|
+
[2006,11,28],
|
318
|
+
[2006,11,26]].collect do |args|
|
319
|
+
Time.utc *args
|
320
|
+
end.each do |t|
|
321
|
+
Recurring.week_of_year(t).should == 48
|
322
|
+
end
|
323
|
+
|
324
|
+
[[2006,12,7],
|
325
|
+
[2006,12,9],
|
326
|
+
[2006,12,3]].collect do |args|
|
327
|
+
Time.utc *args
|
328
|
+
end.each do |t|
|
329
|
+
Recurring.week_of_year(t).should == 49
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
context "A weekly schedule with times params but no days params" do
|
336
|
+
|
337
|
+
setup do
|
338
|
+
@rs = Recurring::Schedule.new :unit => 'weeks', :times => '4pm'
|
339
|
+
end
|
340
|
+
|
341
|
+
specify "should flip out hard" do
|
342
|
+
lambda{@rs.find_next(Time.utc(2006,1,1,16))}.should_raise RangeError
|
343
|
+
end
|
344
|
+
|
345
|
+
end
|
346
|
+
|
347
|
+
#DAILY
|
348
|
+
|
349
|
+
context "A daily schedule with no other params" do
|
350
|
+
|
351
|
+
setup do
|
352
|
+
@rs = Recurring::Schedule.new :unit => 'days'
|
353
|
+
end
|
354
|
+
|
355
|
+
specify "should match the beginning of every day" do
|
356
|
+
@rs.should_include Time.utc(2006,11,5)
|
357
|
+
@rs.should_include Time.mktime(2006,11,5)
|
358
|
+
end
|
359
|
+
|
360
|
+
specify "should not match the middle of any day" do
|
361
|
+
@rs.should_not_include Time.utc(2006,11,5,5)
|
362
|
+
@rs.should_not_include Time.utc(2006,11,5,0,0,22)
|
363
|
+
end
|
364
|
+
|
365
|
+
specify "should find the next date" do
|
366
|
+
@rs.find_next(Time.utc(2006,5,4,2)).should == Time.utc(2006,5,5)
|
367
|
+
@rs.find_next(Time.utc(2006,6,13,5)).should == Time.utc(2006,6,14)
|
368
|
+
end
|
369
|
+
|
370
|
+
end
|
371
|
+
|
372
|
+
context "A daily schedule with an anchor" do
|
373
|
+
setup do
|
374
|
+
@rs = Recurring::Schedule.new :unit => 'days', :anchor => Time.utc(2006,11,1,10,15,22)
|
375
|
+
end
|
376
|
+
|
377
|
+
specify "should include daily mulitples of the anchor" do
|
378
|
+
@rs.should_include Time.utc(2006,11,7,10,15,22)
|
379
|
+
end
|
380
|
+
|
381
|
+
specify "should not include other times in any day" do
|
382
|
+
@rs.should_not_include Time.utc(2006,11,7)
|
383
|
+
@rs.should_not_include Time.utc(2006,11,7,10,15,21)
|
384
|
+
end
|
385
|
+
|
386
|
+
specify "should find the next date" do
|
387
|
+
@rs.find_next(Time.utc(2006,5,4,12)).should == Time.utc(2006,5,5,10,15,22)
|
388
|
+
@rs.find_next(Time.utc(2006,6,13,5)).should == Time.utc(2006,6,13,10,15,22)
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
context "A fourth-daily schedule with only the unit and frequency != 1" do
|
393
|
+
specify "should have an ArgumentError" do
|
394
|
+
lambda{@rs = Recurring::Schedule.new :unit => 'days', :frequency => 4}.should_raise ArgumentError
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
context "A fourth-daily schedule with no other params" do
|
399
|
+
|
400
|
+
setup do
|
401
|
+
@rs = Recurring::Schedule.new :unit => 'days', :frequency => 4, :anchor => Time.utc(2006,11,1,9,30)
|
402
|
+
end
|
403
|
+
|
404
|
+
specify "should check the anchor" do
|
405
|
+
@rs.send(:check_anchor?).should == true
|
406
|
+
end
|
407
|
+
|
408
|
+
specify "should include the anchor" do
|
409
|
+
@rs.should_include Time.utc(2006,11,1,9,30)
|
410
|
+
end
|
411
|
+
|
412
|
+
specify "should not include the beginning of the anchor day" do
|
413
|
+
@rs.should_not_include Time.utc(2006,11,1)
|
414
|
+
end
|
415
|
+
|
416
|
+
specify "should include the time of the anchor, every four days" do
|
417
|
+
@rs.should_include Time.utc(2006,11,5,9,30)
|
418
|
+
end
|
419
|
+
|
420
|
+
specify "should not include the beginnings of matching days" do
|
421
|
+
@rs.should_not_include Time.utc(2006,11,5)
|
422
|
+
end
|
423
|
+
|
424
|
+
end
|
425
|
+
|
426
|
+
context "A daily schedule with times params" do
|
427
|
+
end
|
428
|
+
|
429
|
+
context "A third-daily schedule with times params" do
|
430
|
+
end
|
431
|
+
|
432
|
+
context "A daily schedule with monthday params" do
|
433
|
+
end
|
434
|
+
|
435
|
+
#HOURLY
|
436
|
+
|
437
|
+
context "An hourly schedule with no other params" do
|
438
|
+
|
439
|
+
setup do
|
440
|
+
@rs = Recurring::Schedule.new :unit => 'hours'
|
441
|
+
end
|
442
|
+
|
443
|
+
specify "should include the top of every hour" do
|
444
|
+
@rs.should_include Time.utc(2006,3,4,5)
|
445
|
+
end
|
446
|
+
|
447
|
+
specify "should not include times with non zero minutes or seconds" do
|
448
|
+
@rs.should_not_include Time.utc(2006,3,4,5,6)
|
449
|
+
@rs.should_not_include Time.utc(2006,3,4,5,0,6)
|
450
|
+
end
|
451
|
+
|
452
|
+
end
|
453
|
+
|
454
|
+
context "An hourly schedule with an anchor" do
|
455
|
+
setup do
|
456
|
+
@rs = Recurring::Schedule.new :unit => 'hours', :anchor => Time.utc(2001,5,15,11,17)
|
457
|
+
end
|
458
|
+
|
459
|
+
specify "should include any time with the same sub hour parts" do
|
460
|
+
@rs.should_include Time.utc(2006,5,15,14,17)
|
461
|
+
end
|
462
|
+
|
463
|
+
specify "should include the anchor time" do
|
464
|
+
end
|
465
|
+
|
466
|
+
specify "should not include any times with different sub hour parts" do
|
467
|
+
end
|
468
|
+
|
469
|
+
end
|
470
|
+
|
471
|
+
context "An bi-hourly schedule with time params" do
|
472
|
+
|
473
|
+
setup do
|
474
|
+
@rs = Recurring::Schedule.new :unit => 'hours', :frequency => 2, :times => '0:22 0:13:14', :anchor => Time.utc(2006)
|
475
|
+
end
|
476
|
+
|
477
|
+
specify "should find 4 times in 4 hours" do
|
478
|
+
should_find_in_range(@rs, 4, Time.utc(2006,12,12), Time.utc(2006,12,12,4) )
|
479
|
+
end
|
480
|
+
|
481
|
+
specify "should include times every other hour with the valid minutes and seconds" do
|
482
|
+
@rs.should_include Time.utc(2006,1,1,0,22)
|
483
|
+
@rs.should_include Time.utc(2006,1,1,0,13,14)
|
484
|
+
@rs.should_include Time.utc(2006,1,1,2,22)
|
485
|
+
@rs.should_include Time.utc(2006,1,1,16,13,14)
|
486
|
+
end
|
487
|
+
|
488
|
+
specify "should not include times with mismatched minutes or hours" do
|
489
|
+
@rs.should_not_include Time.utc(2006,12,12)
|
490
|
+
@rs.should_not_include Time.utc(2006,1,1,1,22)
|
491
|
+
@rs.should_not_include Time.utc(2006,1,1,3,13,14)
|
492
|
+
@rs.should_not_include Time.utc(2006,1,1,2,23)
|
493
|
+
@rs.should_not_include Time.utc(2006,1,1,16,13,24)
|
494
|
+
end
|
495
|
+
|
496
|
+
end
|
497
|
+
|
498
|
+
context "An hourly schedule with times params" do
|
499
|
+
|
500
|
+
setup do
|
501
|
+
@rs = Recurring::Schedule.new :unit => 'hours', :times => '0:15 4:30 0:45:30'
|
502
|
+
end
|
503
|
+
|
504
|
+
specify "should include matching times" do
|
505
|
+
@rs.should_include Time.utc(2001,11,11,11,15)
|
506
|
+
@rs.should_include Time.utc(2001,1,1,1,30)
|
507
|
+
@rs.should_include Time.utc(2009,12,14,3,45,30)
|
508
|
+
end
|
509
|
+
|
510
|
+
specify "should not include non matching times" do
|
511
|
+
@rs.should_not_include Time.utc(2001,11,11,11,15,05)
|
512
|
+
@rs.should_not_include Time.utc(2001,1,1,1,30,1)
|
513
|
+
@rs.should_not_include Time.utc(2001,1,1,1,35)
|
514
|
+
@rs.should_not_include Time.utc(2009,12,14,3,45)
|
515
|
+
end
|
516
|
+
|
517
|
+
specify "should find the next date" do
|
518
|
+
@rs.find_next(Time.utc(2006,5,4,12)).should == Time.utc(2006,5,4,12,15)
|
519
|
+
@rs.find_next(Time.utc(2006,6,13,5,31)).should == Time.utc(2006,6,13,5,45,30)
|
520
|
+
end
|
521
|
+
|
522
|
+
end
|
523
|
+
|
524
|
+
context "An eight-hourly schedule with times params" do
|
525
|
+
end
|
526
|
+
|
527
|
+
context "An hourly schedule with monthday params" do
|
528
|
+
|
529
|
+
specify "should ignore the monthday params" do
|
530
|
+
end
|
531
|
+
|
532
|
+
end
|
533
|
+
|
534
|
+
#MINUTELY
|
535
|
+
|
536
|
+
context "A minutely schedule with times params" do
|
537
|
+
|
538
|
+
end
|
539
|
+
|
540
|
+
context "A 5-minutely schedule with no other params" do
|
541
|
+
|
542
|
+
setup do
|
543
|
+
@rs = Recurring::Schedule.new :unit => 'minutes', :frequency => 5, :anchor => Time.utc(2006,9,1,10,30)
|
544
|
+
end
|
545
|
+
|
546
|
+
specify "should include a five minute multiples of the anchor time" do
|
547
|
+
@rs.should_include Time.utc(2006,9,1,10,30)
|
548
|
+
@rs.should_include Time.utc(2006,9,1,10,35)
|
549
|
+
@rs.should_include Time.utc(2006,9,1,20,30)
|
550
|
+
end
|
551
|
+
|
552
|
+
specify "should not include times with different seconds" do
|
553
|
+
@rs.should_not_include Time.utc(2006,9,1,10,30,30)
|
554
|
+
end
|
555
|
+
|
556
|
+
specify "should find the next date" do
|
557
|
+
@rs.find_next(Time.utc(2006,5,4,12,1)).should == Time.utc(2006,5,4,12,5)
|
558
|
+
@rs.find_next(Time.utc(2006,6,13,5,31)).should == Time.utc(2006,6,13,5,35)
|
559
|
+
end
|
560
|
+
|
561
|
+
specify "should ignore higher than second precision from the anchor" do
|
562
|
+
end
|
563
|
+
|
564
|
+
specify "should find 7 times in a 30 minute range" do
|
565
|
+
should_find_in_range(@rs, 7, Time.utc(2006,12,12,0,45), Time.utc(2006,12,12,1,15))
|
566
|
+
@rs.find_in_range( Time.utc(2006,12,12,0,45), Time.utc(2006,12,12,1,15) ).first.class.should_be Time
|
567
|
+
end
|
568
|
+
|
569
|
+
specify "should find in a range given as an object with first and last params" do
|
570
|
+
range = mock('range')
|
571
|
+
range.should_receive(:first).and_return(Time.utc(2006,12,12,0,45))
|
572
|
+
range.should_receive(:last).any_number_of_times.and_return(Time.utc(2006,12,12,1,15))
|
573
|
+
@rs.find_in_range(range).first.class.should_be Time
|
574
|
+
end
|
575
|
+
|
576
|
+
specify "should find in a range given as a Range" do
|
577
|
+
range = (Time.utc(2006,12,12,0,45)..Time.utc(2006,12,12,1,15))
|
578
|
+
@rs.find_in_range(range).first.class.should_be Time
|
579
|
+
end
|
580
|
+
|
581
|
+
specify "should find 10 times in a 45 minute range" do
|
582
|
+
should_find_in_range(@rs, 10, Time.utc(2006,12,12,1), Time.utc(2006,12,12,1,45))
|
583
|
+
@rs.find_in_range( Time.utc(2006,12,12,0,45), Time.utc(2006,12,12,1,15) ).first.class.should_be Time
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
#SECONDLY
|
588
|
+
|
589
|
+
|
590
|
+
#ETC
|
591
|
+
|
592
|
+
context "a daily schedule with a time 4:29am" do
|
593
|
+
setup do
|
594
|
+
@rs = Recurring::Schedule.new :unit => 'days', :times => '4:29am'
|
595
|
+
end
|
596
|
+
specify "should include any day at the time specified" do
|
597
|
+
@rs.should_include Time.utc(2001,3,4,4,29)
|
598
|
+
end
|
599
|
+
specify "should not include times other than 4:29am" do
|
600
|
+
@rs.should_not_include Time.utc(2004,5,17,1,39)
|
601
|
+
end
|
602
|
+
end
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: recurring
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2006-12-10 00:00:00 -08:00
|
8
|
+
summary: A scheduling library for recurring events
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: ryand-ruby@zenspider.com
|
12
|
+
homepage: " by Chris Anderson"
|
13
|
+
rubyforge_project: recurring
|
14
|
+
description: "Schedules can be like: * Every Tuesday at 5pm * The 1st and 15th of every other month * Every 2 hours * The first Friday of every month at 11:15am and 4:45:15pm == FEATURES/PROBLEMS: = Features * Fast searching of long ranges for matching times. * Ability to define Schedules in a few flexible ways. * Extensive RSpec specifications (run \"rake spec\" to see them) * Extensive RSpec specifications (run \"rake spec\" to see them) = Problems / Todo * Untested timezone support * Plans to offer complex Schedule and Masks == SYNOPSYS:"
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
authors:
|
29
|
+
- Ryan Davis
|
30
|
+
files:
|
31
|
+
- History.txt
|
32
|
+
- Manifest.txt
|
33
|
+
- README.txt
|
34
|
+
- Rakefile
|
35
|
+
- lib/recurring.rb
|
36
|
+
- spec/recurring_spec.rb
|
37
|
+
test_files: []
|
38
|
+
|
39
|
+
rdoc_options: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
executables: []
|
44
|
+
|
45
|
+
extensions: []
|
46
|
+
|
47
|
+
requirements: []
|
48
|
+
|
49
|
+
dependencies:
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: hoe
|
52
|
+
version_requirement:
|
53
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 1.1.6
|
58
|
+
version:
|