recurring 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|