EdvardM-recurrence 0.1.14
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/README +70 -0
- data/spec/recurrence_spec.rb +482 -0
- metadata +53 -0
data/README
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
= Recurrence
|
2
|
+
|
3
|
+
== Overview
|
4
|
+
|
5
|
+
Recurrence provides a simple class for handling recurring, time-associated objects. The goal is to create a general-purpose,
|
6
|
+
loosely coupled class library to provide common functionality for events occurring at predetermined intervals.
|
7
|
+
|
8
|
+
Short example:
|
9
|
+
|
10
|
+
require 'recurrence'
|
11
|
+
|
12
|
+
first_of_june = [2008, 6, 1]
|
13
|
+
r = Recurrence.new(first_of_june, :every_other => :week, :until => '2010-06-01')
|
14
|
+
|
15
|
+
my_cal = MyCalendar.new_default
|
16
|
+
my_cal.each_day { |date|
|
17
|
+
time = Time.parse(date) # assuming date can be parsed with Time.parse
|
18
|
+
puts 'Yay! today is the day!' if r.recurs_on?(time)
|
19
|
+
}
|
20
|
+
|
21
|
+
== Set-like operations
|
22
|
+
|
23
|
+
Real power of Recurrence lies in it's support for set-like operations +join+, +intersect+, +diff+ and +complement+. For example,
|
24
|
+
given the start date of 2008-06-01, recur something every thursday and friday:
|
25
|
+
|
26
|
+
require 'recurrence'
|
27
|
+
|
28
|
+
start_date = '2008-06-01'
|
29
|
+
r1 = Recurrence.new(start_date, :every => :thursday)
|
30
|
+
r2 = Recurrence.new(start_date, :every => :friday)
|
31
|
+
r = r1.join(r2)
|
32
|
+
|
33
|
+
Another example, a tad contrived perhaps:
|
34
|
+
|
35
|
+
# Recur something every friday, except if it is last friday of the month:
|
36
|
+
|
37
|
+
dow = :friday
|
38
|
+
r1 = Recurrence.new(:epoch, :every => dow)
|
39
|
+
r2 = Recurrence.new(:epoch, :every_last => dow, :of => :month)
|
40
|
+
|
41
|
+
r = r1.diff(r2)
|
42
|
+
|
43
|
+
Nested set-like operations are also possible. So, for arbitrary recurrences a and b and any time t, the following should always apply:
|
44
|
+
|
45
|
+
r1 = (a.join(b)).complement
|
46
|
+
r2 = (a.complement).intersect(b.complement)
|
47
|
+
|
48
|
+
r1.recurs_on?(t) == r2.recurs_on?(t) # De Morgan's law - complement of a union is the same as intersection of the complements
|
49
|
+
|
50
|
+
See RecurrenceBase::SetOperations for more.
|
51
|
+
|
52
|
+
== Installation
|
53
|
+
|
54
|
+
Enter
|
55
|
+
|
56
|
+
rake gem
|
57
|
+
|
58
|
+
on the command line in the same directory as this README file, it should produce the gem under the pkg directory.
|
59
|
+
Then you should be able to say
|
60
|
+
|
61
|
+
sudo gem install pkg/recurrence*.gem
|
62
|
+
|
63
|
+
to install the gem to your local system.
|
64
|
+
|
65
|
+
KTHXBAI
|
66
|
+
|
67
|
+
== License
|
68
|
+
|
69
|
+
MIT (see MIT-LICENSE)
|
70
|
+
|
@@ -0,0 +1,482 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Recurrence do
|
4
|
+
def recur_on(date)
|
5
|
+
# TODO: replace this with more heavy-weight custom matcher which results in more informative
|
6
|
+
# failure messages
|
7
|
+
simple_matcher("recurs on #{date}") { |obj| obj.recurs_on?(date) }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'initialization' do
|
11
|
+
it "should accept a Time object" do
|
12
|
+
Recurrence.new(Date.new(2008, 8, 27), :every => :day)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should accept Date.new style argument list" do
|
16
|
+
Recurrence.new([2008, 8, 27], :every => :day).start_date.should == Date.new(2008, 8, 27)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should accept a time string" do
|
20
|
+
Recurrence.new('2008-08-27', :every => :day).start_date.should == Date.new(2008, 8, 27)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should accept the symbol epoch" do
|
24
|
+
Recurrence.new(:epoch, :every => :day).start_date.should == Date.new(1970, 1, 1)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should return initialization time" do
|
29
|
+
r = Recurrence.new([2008, 8, 27], :every => :day)
|
30
|
+
r.start_date.should == Date.new(2008, 8, 27)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should allow time string argument for recurs_on?" do
|
34
|
+
r = Recurrence.new('2008-08-27', :every => :day)
|
35
|
+
r.should recur_on('2008-08-30')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return starting date of week" do
|
39
|
+
r = Recurrence.new([2008, 8, 27], :every => :day)
|
40
|
+
r.starting_dow.should == :wednesday
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should return starting date of week in short form" do
|
44
|
+
r = Recurrence.new([2008, 8, 27], :every => :day)
|
45
|
+
r.starting_dow(:short).should == :wed
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "recurring every <interval>" do
|
49
|
+
it "should not recur before initial date" do
|
50
|
+
Recurrence.new('2008-08-27', :every => :day).should_not recur_on('2008-08-26')
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not recur after final date" do
|
54
|
+
Recurrence.new('2008-08-27', :every => :day, :until => '2008-10-1').should_not recur_on('2008-10-2')
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should recur daily" do
|
58
|
+
r = Recurrence.new([2008, 9, 2], :every => :day)
|
59
|
+
|
60
|
+
(2..30).each do |day|
|
61
|
+
t = Date.new(2008, 9, day)
|
62
|
+
r.should recur_on(t)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should recur ad infinitum if until is not specified (well, 2038-01-19 is the day Time instances go boink unless fixed)" do
|
67
|
+
Recurrence.new(:epoch, :every => :day).should recur_on('2038-01-18')
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should recur weekly" do
|
71
|
+
r = Recurrence.new(Date.new(2008, 8, 1), :every => :week)
|
72
|
+
|
73
|
+
(2..7).each do |day|
|
74
|
+
r.should_not recur_on(Date.new(2008, 8, day))
|
75
|
+
end
|
76
|
+
r.should recur_on(Date.new(2008, 8, 8))
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should recur every given weekday" do
|
80
|
+
year, mon = 2008, 9
|
81
|
+
r = Recurrence.new(Date.new(year, mon, 1), :every => :wednesday)
|
82
|
+
|
83
|
+
[1, 2, 4, 5, 6, 7, 8, 9, 11].each do |day|
|
84
|
+
r.should_not recur_on(Date.new(year, mon, day))
|
85
|
+
end
|
86
|
+
[3, 10].each do |day|
|
87
|
+
r.should recur_on(Date.new(year, mon, day))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
it "should recur monthly" do
|
93
|
+
r = Recurrence.new(Date.new(2008, 8, 24), :every => :month)
|
94
|
+
|
95
|
+
(1..23).each do |day|
|
96
|
+
r.should_not recur_on(Date.new(2008, 9, day))
|
97
|
+
end
|
98
|
+
r.should recur_on(Date.new(2008, 9, 24))
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should recur yearly" do
|
102
|
+
r = Recurrence.new(Date.new(2008, 8, 13), :every => :year)
|
103
|
+
|
104
|
+
(1..31).each do |day|
|
105
|
+
r.should_not recur_on(Date.new(2009, 1, day))
|
106
|
+
end
|
107
|
+
r.should recur_on(Date.new(2009, 8, 13))
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should recur every weekend" do
|
111
|
+
r = Recurrence.new(:epoch, :every => :weekend)
|
112
|
+
|
113
|
+
(2..3).each do |day| # saturday, sunday
|
114
|
+
r.should recur_on(Date.new(2008, 8, day))
|
115
|
+
end
|
116
|
+
(4..8).each do |day|
|
117
|
+
r.should_not recur_on(Date.new(2008, 8, day))
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should recur every workday" do
|
122
|
+
r = Recurrence.new(:epoch, :every => :workday)
|
123
|
+
|
124
|
+
(2..3).each do |day|
|
125
|
+
r.should_not recur_on(Date.new(2008, 8, day))
|
126
|
+
end
|
127
|
+
(4..8).each do |day|
|
128
|
+
r.should recur_on(Date.new(2008, 8, day))
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should raise ArgumentError when given invalid repeat type" do
|
133
|
+
lambda { Recurrence.new(Date.new(2008, 8, 22), :foo => :workday) }.should raise_error(ArgumentError)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should raise ArgumentError when given invalid recurrence type" do
|
137
|
+
lambda { Recurrence.new(Date.new(2008, 8, 22), :every => :homersimpson) }.should raise_error(ArgumentError)
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "recurring every_second <interval>" do
|
143
|
+
it "should recur every second day" do
|
144
|
+
year, month = 2008, 8
|
145
|
+
r = Recurrence.new(Date.new(year, month, 1), :every_second => :day)
|
146
|
+
|
147
|
+
[1, 3, 5, 7, 9, 23].each { |day| r.should recur_on(Date.new(year, month, day)) }
|
148
|
+
[2, 4, 8, 10, 12, 26].each { |day| r.should_not recur_on(Date.new(year, month, day)) }
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should recur every other week" do
|
152
|
+
year, month = 2008, 8
|
153
|
+
r = Recurrence.new(Date.new(year, month, 2), :every_second => :week)
|
154
|
+
|
155
|
+
(3..15).each { |day| r.should_not recur_on(Date.new(year, month, day)) }
|
156
|
+
[16, 30].each { |day| r.should recur_on(Date.new(year, month, day)) }
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should recur every other month" do
|
160
|
+
year, month, day = 2008, 1, 1
|
161
|
+
r = Recurrence.new(Date.new(year, month, 1), :every_second => :month)
|
162
|
+
|
163
|
+
[2, 4, 6].each { |m| r.should_not recur_on(Date.new(year, m, day)) }
|
164
|
+
[1, 3, 5].each { |m| r.should recur_on(Date.new(year, m, day)) }
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should recur every other year" do
|
168
|
+
month, day = 4, 29
|
169
|
+
r = Recurrence.new(Date.new(2000, month, day), :every_second => :year)
|
170
|
+
|
171
|
+
[2005, 2007, 2009].each { |y| r.should_not recur_on(Date.new(y, month, day)) }
|
172
|
+
[2006, 2004, 2010].each { |y| r.should recur_on(Date.new(y, month, day)) }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "recurring every_third <interval>" do
|
177
|
+
it "should recur every third day" do
|
178
|
+
year, month = 2008, 8
|
179
|
+
r = Recurrence.new(Date.new(year, month, 8), :every_third => :day)
|
180
|
+
|
181
|
+
[8, 11, 14, 17, 20].each { |day| r.should recur_on(Date.new(year, month, day)) }
|
182
|
+
[9, 10, 12, 13, 15, 16, 18, 19].each { |day| r.should_not recur_on(Date.new(year, month, day)) }
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should recur every third week" do
|
186
|
+
year, month = 2008, 8
|
187
|
+
r = Recurrence.new(Date.new(year, month, 1), :every_third => :week)
|
188
|
+
|
189
|
+
(2..21).each { |day| r.should_not recur_on(Date.new(year, month, day)) }
|
190
|
+
r.should recur_on(Date.new(year, month, 22))
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should recur every third month" do
|
194
|
+
year, day = 2008, 1
|
195
|
+
r = Recurrence.new(Date.new(year, 1, day), :every_third => :month)
|
196
|
+
|
197
|
+
[1, 4, 7, 10].each { |m| r.should recur_on(Date.new(year, m, day)) }
|
198
|
+
[2, 3, 5, 6, 8, 9].each { |m| r.should_not recur_on(Date.new(year, m, day)) }
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should recur every third year" do
|
202
|
+
month, day = 9, 21
|
203
|
+
r = Recurrence.new(Date.new(2001, month, day), :every_third => :year)
|
204
|
+
|
205
|
+
[2004, 2007, 2010].each { |y| r.should recur_on(Date.new(y, month, day)) }
|
206
|
+
[2002, 2005, 2006].each { |y| r.should_not recur_on(Date.new(y, month, day)) }
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe "recurring every 10th <interval>" do
|
211
|
+
it "should recur every 10th day" do
|
212
|
+
year, month = 2008, 1
|
213
|
+
r = Recurrence.new([year, month, 1], :every_nth => :day, :interval => 10)
|
214
|
+
|
215
|
+
[11, 21, 31].each do |d|
|
216
|
+
r.should recur_on([year, month, d])
|
217
|
+
end
|
218
|
+
|
219
|
+
(2..10).each { |d| r.should_not recur_on([year, month, d]) }
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should recur every 10th month" do
|
223
|
+
year, day = 2008, 28
|
224
|
+
r = Recurrence.new([year, 1, day], :every_nth => :month, :interval => 10)
|
225
|
+
|
226
|
+
[1, 11].each { |m| r.should recur_on([year, m, day]) }
|
227
|
+
|
228
|
+
(2..10).each { |m| r.should_not recur_on([year, m, day]) }
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "set operations" do
|
233
|
+
it "should be able to form union (OR) of two recurrences" do
|
234
|
+
# 1 2 3 4 5 6 7 8 9 10
|
235
|
+
# | | | | | # recur every other day since first
|
236
|
+
|
237
|
+
# 1 2 3 4 5 6 7 8 9 10
|
238
|
+
# | | | | # recur every third day since first
|
239
|
+
|
240
|
+
# 1 2 3 4 5 6 7 8 9 10
|
241
|
+
# | | | | | | | # union of recurrences above
|
242
|
+
start_date = '2008-08-01'
|
243
|
+
r = Recurrence.new(start_date, :every_second => :day).join(Recurrence.new(start_date, :every_third => :day))
|
244
|
+
[1, 3, 4, 5, 7, 9, 10].each { |d| r.should recur_on([2008, 8, d]) }
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should be able to form intersection (AND) of two recurrences" do
|
248
|
+
# 1 2 3 4 5 6 7 8 9 10
|
249
|
+
# | | | | | # recur every other day since first
|
250
|
+
|
251
|
+
# 1 2 3 4 5 6 7 8 9 10
|
252
|
+
# | | | | # recur every third day since first
|
253
|
+
|
254
|
+
# 1 2 3 4 5 6 7 8 9 10
|
255
|
+
# | | # intersection of recurrences above
|
256
|
+
start_date = '2008-08-01'
|
257
|
+
r = Recurrence.new(start_date, :every_second => :day).intersect(Recurrence.new(start_date, :every_third => :day))
|
258
|
+
[1, 7].each { |d| r.should recur_on(Date.new(2008, 8, d)) }
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should be able to form difference (\) of two recurrences" do
|
262
|
+
# 1 2 3 4 5 6 7 8 9 10
|
263
|
+
# | | | | | # recur every other day since first
|
264
|
+
|
265
|
+
# 1 2 3 4 5 6 7 8 9 10
|
266
|
+
# | | | | # recur every third day since first
|
267
|
+
|
268
|
+
# 1 2 3 4 5 6 7 8 9 10
|
269
|
+
# | | | # difference of recurrences above
|
270
|
+
|
271
|
+
start_date = '2008-08-01'
|
272
|
+
r = Recurrence.new(start_date, :every_second => :day).diff(Recurrence.new(start_date, :every_third => :day))
|
273
|
+
[3, 5, 9].each { |d| r.should recur_on([2008, 8, d]) }
|
274
|
+
[1, 2, 4, 6, 7, 8].each { |d| r.should_not recur_on([2008, 8, d]) }
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should be able to form complement (NOT) of a recurrence" do
|
278
|
+
r = Recurrence.new('2008-08-01', :every_second => :day).complement
|
279
|
+
orig = r.complement
|
280
|
+
|
281
|
+
[2, 4, 6, 8, 10].each { |day|
|
282
|
+
date = Date.new(2008, 8, day)
|
283
|
+
r.should recur_on(date)
|
284
|
+
orig.should_not recur_on(date)
|
285
|
+
}
|
286
|
+
|
287
|
+
[1, 3, 5, 7, 9].each { |day|
|
288
|
+
date = Date.new(2008, 8, day)
|
289
|
+
r.should_not recur_on(date)
|
290
|
+
orig.should recur_on(date)
|
291
|
+
}
|
292
|
+
end
|
293
|
+
|
294
|
+
it "should be able to support nested set-like operations" do
|
295
|
+
# 1 2 3 4 5 6 7 8 9 10
|
296
|
+
# | | | | | # recur every other day since first
|
297
|
+
|
298
|
+
# 1 2 3 4 5 6 7 8 9 10
|
299
|
+
# | | | | # recur every third day since first
|
300
|
+
|
301
|
+
# 1 2 3 4 5 6 7 8 9 10
|
302
|
+
# ! | | # complement of (A union B) == (NOT A) AND (NOT B)
|
303
|
+
|
304
|
+
start_date = '2008-01-01'
|
305
|
+
a = Recurrence.new(start_date, :every_second => :day)
|
306
|
+
b = Recurrence.new(start_date, :every_third => :day)
|
307
|
+
|
308
|
+
# De Morgan's
|
309
|
+
complement_of_union = (a.join(b)).complement
|
310
|
+
intersection_of_complements = (a.complement).intersect(b.complement)
|
311
|
+
|
312
|
+
|
313
|
+
[2, 6, 8].each { |d|
|
314
|
+
date = [2008, 1, d]
|
315
|
+
complement_of_union.should recur_on(date)
|
316
|
+
intersection_of_complements.should recur_on(date)
|
317
|
+
}
|
318
|
+
[1, 3, 4, 5, 7, 9, 10].each { |d|
|
319
|
+
date = [2008, 1, d]
|
320
|
+
complement_of_union.should_not recur_on(date)
|
321
|
+
intersection_of_complements.should_not recur_on(date)
|
322
|
+
}
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
describe "recurring every nth of <weekday> of a <period>" do
|
327
|
+
it "should recur every first thursday of a month" do
|
328
|
+
r = Recurrence.new(:epoch, :every_first => :thursday, :of => :month)
|
329
|
+
(1..30).each { |day|
|
330
|
+
# 4th day is the first thursday on Sep 2008
|
331
|
+
date = [2008, 9, day]
|
332
|
+
if day == 4
|
333
|
+
r.should recur_on(date)
|
334
|
+
else
|
335
|
+
r.should_not recur_on(date)
|
336
|
+
end
|
337
|
+
}
|
338
|
+
end
|
339
|
+
|
340
|
+
it "should recur every second thursday of a month" do
|
341
|
+
r = Recurrence.new(:epoch, :every_second => :thursday, :of => :month)
|
342
|
+
(1..30).each { |day|
|
343
|
+
# 11th day is second thursday on Sep 2008
|
344
|
+
date = [2008, 9, day]
|
345
|
+
if day == 11
|
346
|
+
r.should recur_on(date)
|
347
|
+
else
|
348
|
+
r.should_not recur_on(date)
|
349
|
+
end
|
350
|
+
}
|
351
|
+
end
|
352
|
+
|
353
|
+
it "should recur every last thursday of a month" do
|
354
|
+
r = Recurrence.new(:epoch, :every_last => :thursday, :of => :month)
|
355
|
+
(1..30).each { |day|
|
356
|
+
# 25th day is the last thursday on Sep 2008
|
357
|
+
date = [2008, 9, day]
|
358
|
+
if day == 25
|
359
|
+
r.should recur_on(date)
|
360
|
+
else
|
361
|
+
r.should_not recur_on(date)
|
362
|
+
end
|
363
|
+
}
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
it "should yield every second day" do
|
368
|
+
r = Recurrence.new(:epoch, :every_second => :day)
|
369
|
+
days = []
|
370
|
+
|
371
|
+
r.each {|t|
|
372
|
+
break if t.day > 5
|
373
|
+
days << t.day
|
374
|
+
}
|
375
|
+
days.should == [1, 3, 5]
|
376
|
+
end
|
377
|
+
|
378
|
+
describe 'iteration' do
|
379
|
+
it "should yield every week" do
|
380
|
+
r = Recurrence.new(:epoch, :every => :week)
|
381
|
+
weekdays = []
|
382
|
+
|
383
|
+
r.each {|t|
|
384
|
+
weekdays << t.wday
|
385
|
+
break if weekdays.length > 3
|
386
|
+
}
|
387
|
+
weekdays.should == [r.start_date.wday] * 4
|
388
|
+
end
|
389
|
+
|
390
|
+
it "should yield every given weekday" do
|
391
|
+
r = Recurrence.new([2008, 9, 1], :every => :sunday)
|
392
|
+
count = 0
|
393
|
+
|
394
|
+
r.each {|t|
|
395
|
+
RecurrenceBase::RecurrenceMixin::DAYS[t.wday].should == :sunday
|
396
|
+
count += 1
|
397
|
+
break if count == 10
|
398
|
+
}
|
399
|
+
count.should == 10
|
400
|
+
|
401
|
+
r = Recurrence.new([2008, 9, 1], :every => :wednesday)
|
402
|
+
count = 0
|
403
|
+
|
404
|
+
r.each {|t|
|
405
|
+
RecurrenceBase::RecurrenceMixin::DAYS[t.wday].should == :wednesday
|
406
|
+
count += 1
|
407
|
+
break if count == 10
|
408
|
+
}
|
409
|
+
count.should == 10
|
410
|
+
end
|
411
|
+
|
412
|
+
it "should yield every month, setting the date to last in month if overlapping" do
|
413
|
+
r = Recurrence.new('2008-01-31', :every => :month)
|
414
|
+
days_months = []
|
415
|
+
|
416
|
+
r.each {|t|
|
417
|
+
break if days_months.length > 3
|
418
|
+
days_months << [t.day, t.mon]
|
419
|
+
}
|
420
|
+
days_months.should == [[31, 1], [29, 2], [31, 3], [30,4]]
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
describe 'examples' do
|
425
|
+
it "should recur every other day, starting from epoch" do
|
426
|
+
r = Recurrence.new(:epoch, :every_second => :day)
|
427
|
+
r.start_date.should == Date.new(1970, 1, 1)
|
428
|
+
|
429
|
+
[1, 3, 5].each { |day| r.should recur_on([1970, 1, day]) }
|
430
|
+
[2, 4, 6].each { |day| r.should_not recur_on([1970, 1, day]) }
|
431
|
+
end
|
432
|
+
|
433
|
+
it "should recur every 10th day starting from epoch" do
|
434
|
+
r = Recurrence.new(:epoch, :every_nth => :day, :interval => 10)
|
435
|
+
|
436
|
+
[1, 11, 21].each { |day| r.should recur_on([1970, 1, day]) }
|
437
|
+
[2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 20].each { |day| r.should_not recur_on([1970, 1, day]) }
|
438
|
+
end
|
439
|
+
|
440
|
+
it "should recur only on the first wednesday of a month starting from today" do
|
441
|
+
date = Date.new(2008, 9, 15)
|
442
|
+
r = Recurrence.new(date, :every_first => :wednesday, :of => :month)
|
443
|
+
date = r.start_date
|
444
|
+
hits = []
|
445
|
+
40.times {
|
446
|
+
hits << date if r.recurs_on?(date)
|
447
|
+
date += 1
|
448
|
+
}
|
449
|
+
hits.map { |d| d.wday }.should == [3] # wednesday is at index 3
|
450
|
+
end
|
451
|
+
|
452
|
+
it "should recur only on every last thursday of a month, starting from today" do
|
453
|
+
r = Recurrence.new(:today, :every_last => :thursday, :of => :month)
|
454
|
+
hits = []
|
455
|
+
date = r.start_date
|
456
|
+
40.times {
|
457
|
+
hits << date if r.recurs_on?(date)
|
458
|
+
date += 1
|
459
|
+
}
|
460
|
+
hits.map { |d| d.wday }.should == [4]
|
461
|
+
end
|
462
|
+
|
463
|
+
it "should recur once a week starting from 1st day" do
|
464
|
+
r = Recurrence.new([2008, 10, 7], :every => :week)
|
465
|
+
[7, 14, 21].each { |day| r.should recur_on([2008, 10, day]) }
|
466
|
+
end
|
467
|
+
|
468
|
+
it "should recur every wednesday starting from given date" do
|
469
|
+
r = Recurrence.new([2008, 10, 7], :every => :wednesday)
|
470
|
+
r.should recur_on([2008, 10, 8]) # 8th is wednesday
|
471
|
+
end
|
472
|
+
|
473
|
+
it "should recur every nth day of month" do
|
474
|
+
r = Recurrence.new("2008-09-04", :every => :month) # Recur on the 4th day of every month
|
475
|
+
[9, 10, 11].each { |mon|
|
476
|
+
r.should_not recur_on([2008, mon, 3])
|
477
|
+
r.should recur_on([2008, mon, 4])
|
478
|
+
r.should_not recur_on([2008, mon, 5])
|
479
|
+
}
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: EdvardM-recurrence
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.14
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Edvard Majakari
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-01 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: edvard.majakari@adalia.fi
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
has_rdoc: "true"
|
27
|
+
homepage:
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
|
31
|
+
require_paths:
|
32
|
+
- lib
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: "0"
|
38
|
+
version:
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
requirements: []
|
46
|
+
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 1.2.0
|
49
|
+
signing_key:
|
50
|
+
specification_version: 2
|
51
|
+
summary: Library for periodically recurring things
|
52
|
+
test_files:
|
53
|
+
- spec/recurrence_spec.rb
|