cyclical 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.
@@ -0,0 +1,218 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe MonthlyRule do
6
+ describe "simple rule" do
7
+ before do
8
+ @rule = MonthlyRule.new
9
+ end
10
+
11
+ it "should return one day as step" do
12
+ @rule.step.should == 1.month
13
+ end
14
+
15
+ it "should give next date" do
16
+ base = Time.local(2010, 1, 1, 9, 30, 21)
17
+
18
+ @rule.next(Time.local(2010, 1, 1), base).should == Time.local(2010, 1, 1, 9, 30, 21)
19
+ @rule.next(Time.local(2010, 1, 1, 9, 30, 21), base).should == Time.local(2010, 2, 1, 9, 30, 21)
20
+ @rule.next(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 2, 1, 9, 30, 21)
21
+
22
+ # align forward should include base time
23
+ @rule.next(base, base).should == base + 1.month
24
+ end
25
+
26
+ it "should give previous date" do
27
+ base = Time.local(2010, 1, 1, 9, 30, 21)
28
+
29
+ @rule.previous(Time.local(2010, 1, 1), base).should == Time.local(2009, 12, 1, 9, 30, 21)
30
+ @rule.previous(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 1, 1, 9, 30, 21)
31
+
32
+ # align back should exclude base time
33
+ @rule.previous(base, base).should == Time.local(2009, 12, 1, 9, 30, 21)
34
+ end
35
+
36
+ it "should match dates" do
37
+ @rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2010, 1, 1, 9, 30)).should be_true
38
+
39
+ @rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2010, 1, 1, 9, 29)).should_not be_true
40
+ @rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2010, 1, 8, 9, 30)).should_not be_true
41
+ end
42
+ end
43
+
44
+ describe "finite rules" do
45
+ before do
46
+ @rule = MonthlyRule.new
47
+ end
48
+
49
+ it "should accept count and allow chaining" do
50
+ @rule.count(10).should be_a(MonthlyRule)
51
+ @rule.count.should == 10
52
+ end
53
+
54
+ it "should accept stop time" do
55
+ @rule.stop(Time.utc(2020, 1, 1)).should be_a(MonthlyRule)
56
+ @rule.stop.should == Time.utc(2020, 1, 1)
57
+ end
58
+
59
+ it "should report rule finiteness" do
60
+ MonthlyRule.new.count(5).should be_finite
61
+ MonthlyRule.new.stop(Time.utc(2020, 1, 1)).should be_finite
62
+
63
+ MonthlyRule.new.should_not be_finite
64
+ end
65
+ end
66
+
67
+ describe "rule with interval" do
68
+ before do
69
+ @every_other_month_rule = MonthlyRule.new(2)
70
+ @every_ten_months_rule = MonthlyRule.new(10)
71
+ end
72
+
73
+ it "should return corect step" do
74
+ @every_other_month_rule.step.should == 2.months
75
+ @every_ten_months_rule.step.should == 10.months
76
+ end
77
+
78
+ it "should find next date" do
79
+ base = Time.local(2010, 1, 1, 9, 30, 21)
80
+
81
+ @every_other_month_rule.next(Time.local(2010, 1, 1), base).should == Time.local(2010, 1, 1, 9, 30, 21)
82
+ @every_ten_months_rule.next(Time.local(2010, 1, 1), base).should == Time.local(2010, 1, 1, 9, 30, 21)
83
+
84
+ @every_other_month_rule.next(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 3, 1, 9, 30, 21)
85
+ @every_ten_months_rule.next(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 11, 1, 9, 30, 21)
86
+
87
+ # align forward should include base time
88
+ @every_other_month_rule.next(base, base).should == base + 2.months
89
+ @every_ten_months_rule.next(base, base).should == base + 10.months
90
+ end
91
+
92
+ it "should find previous date" do
93
+ base = Time.local(2010, 1, 1, 9, 30, 21)
94
+
95
+ @every_other_month_rule.previous(Time.local(2010, 1, 1), base).should == Time.local(2009, 11, 1, 9, 30, 21)
96
+ @every_ten_months_rule.previous(Time.local(2010, 1, 1), base).should == Time.local(2009, 3, 1, 9, 30, 21)
97
+
98
+ @every_other_month_rule.previous(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 1, 1, 9, 30, 21)
99
+ @every_ten_months_rule.previous(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 1, 1, 9, 30, 21)
100
+
101
+ # align back should exclude base time
102
+ @every_other_month_rule.previous(base, base).should == Time.local(2009, 11, 1, 9, 30, 21)
103
+ @every_ten_months_rule.previous(base, base).should == Time.local(2009, 3, 1, 9, 30, 21)
104
+ end
105
+
106
+ it "should match dates" do
107
+ # same month, same datetime
108
+ @every_ten_months_rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2010, 1, 1, 9, 30)).should be_true
109
+ @every_ten_months_rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2010, 1, 1, 9, 30)).should be_true
110
+
111
+ # right month, same dattime
112
+ @every_other_month_rule.match?(Time.local(2010, 3, 1, 9, 30), Time.local(2010, 1, 1, 9, 30)).should be_true
113
+ @every_other_month_rule.match?(Time.local(2010, 11, 1, 9, 30), Time.local(2010, 1, 1, 9, 30)).should be_true
114
+
115
+ # wrong month, same datetime
116
+ @every_ten_months_rule.match?(Time.local(2010, 2, 1, 9, 30), Time.local(2010, 1, 1, 9, 30)).should_not be_true
117
+ @every_ten_months_rule.match?(Time.local(2010, 8, 1, 9, 30), Time.local(2010, 1, 1, 9, 30)).should_not be_true
118
+
119
+ # right month, different datetime
120
+ @every_other_month_rule.match?(Time.local(2010, 3, 8, 9, 20), Time.local(2010, 1, 1, 9, 30)).should_not be_true
121
+ @every_other_month_rule.match?(Time.local(2010, 11, 21, 9, 35), Time.local(2010, 1, 1, 9, 30)).should_not be_true
122
+ end
123
+ end
124
+
125
+ describe "rule with filters" do
126
+ before do
127
+ @base = Time.utc(2000, 1, 1, 9, 30, 21)
128
+ @rule = Rule.monthly.months(1, 2).weekdays(1,3)
129
+ end
130
+
131
+ it "should find next date" do
132
+ @rule.next(Time.utc(2000, 1, 1), @base).should == Time.utc(2000, 1, 3, 9, 30, 21)
133
+ @rule.next(Time.utc(2000, 1, 3, 10), @base).should == Time.utc(2000, 1, 5, 9, 30, 21)
134
+
135
+ @rule.next(Time.utc(2000, 2, 2), @base).should == Time.utc(2000, 2, 2, 9, 30, 21)
136
+ @rule.next(Time.utc(2000, 2, 2, 10), @base).should == Time.utc(2000, 2, 7, 9, 30, 21)
137
+ @rule.next(Time.utc(2000, 2, 29), @base).should == Time.utc(2001, 1, 1, 9, 30, 21)
138
+ @rule.next(Time.utc(2000, 3, 1), @base).should == Time.utc(2001, 1, 1, 9, 30, 21)
139
+ end
140
+
141
+ it "should find previous date" do
142
+ @rule.previous(Time.utc(2000, 1, 1), @base).should == Time.utc(1999, 2, 24, 9, 30, 21)
143
+ @rule.previous(Time.utc(2000, 1, 3, 10), @base).should == Time.utc(2000, 1, 3, 9, 30, 21)
144
+
145
+ @rule.previous(Time.utc(2000, 2, 2), @base).should == Time.utc(2000, 1, 31, 9, 30, 21)
146
+ @rule.previous(Time.utc(2000, 2, 2, 10), @base).should == Time.utc(2000, 2, 2, 9, 30, 21)
147
+ @rule.previous(Time.utc(2000, 3, 3), @base).should == Time.utc(2000, 2, 28, 9, 30, 21)
148
+ @rule.previous(Time.utc(2000, 3, 1), @base).should == Time.utc(2000, 2, 28, 9, 30, 21)
149
+ end
150
+
151
+ it "should match dates" do
152
+ # weekdays match
153
+ @rule.match?(Time.utc(2000, 1, 3, 9, 30, 21), @base).should be_true
154
+ @rule.match?(Time.utc(2000, 1, 5, 9, 30, 21), @base).should be_true
155
+
156
+ @rule.match?(Time.utc(2000, 1, 4, 9, 30, 21), @base).should_not be_true
157
+ @rule.match?(Time.utc(2000, 1, 6, 9, 30, 21), @base).should_not be_true
158
+
159
+ # months match
160
+ @rule.match?(Time.utc(2000, 2, 23, 9, 30, 21), @base).should be_true
161
+ @rule.match?(Time.utc(2000, 2, 2, 9, 30, 21), @base).should be_true
162
+
163
+ @rule.match?(Time.utc(2000, 3, 3, 9, 30, 21), @base).should_not be_true
164
+ @rule.match?(Time.utc(2000, 3, 4, 9, 30, 21), @base).should_not be_true
165
+
166
+ # wrong time
167
+ @rule.match?(Time.utc(2000, 1, 3, 9, 30, 28), @base).should_not be_true
168
+ @rule.match?(Time.utc(2000, 1, 3, 9, 12, 29), @base).should_not be_true
169
+ @rule.match?(Time.utc(2000, 1, 3, 10, 30, 29), @base).should_not be_true
170
+ end
171
+ end
172
+
173
+ describe "serialization" do
174
+ it "should do a simple hash roundtrip" do
175
+ h = Rule.monthly(5).to_hash
176
+ restore = Rule.from_hash(h)
177
+
178
+ restore.class.should == MonthlyRule
179
+ restore.interval.should == 5
180
+ restore.step.should == 5.months
181
+ end
182
+
183
+ it "should do a hash roundtrip with count" do
184
+ h = Rule.monthly.count(10).to_hash
185
+ restore = Rule.from_hash(h)
186
+
187
+ restore.count.should == 10
188
+ end
189
+
190
+ it "should do a hash roundtrip with stop" do
191
+ h = Rule.monthly.stop(Time.local(2020, 10, 10)).to_hash
192
+ restore = Rule.from_hash(h)
193
+
194
+ restore.stop.should == Time.local(2020, 10, 10)
195
+ end
196
+
197
+ it "should do a hash roundtrip with weekdays filter" do
198
+ h = Rule.monthly.weekdays(:mon, :tuesday).to_hash
199
+ restore = Rule.from_hash(h)
200
+
201
+ restore.filters(:weekdays).weekdays.should == [1, 2]
202
+ end
203
+
204
+ it "should do a hash roundtrip with ordered weekdays filter" do
205
+ h = Rule.monthly.weekdays(:mon => 1, :tuesday => [2, -3]).to_hash
206
+ restore = Rule.from_hash(h)
207
+
208
+ restore.filters(:weekdays).ordered_weekdays.should == {:mo => [1], :tu => [-3, 2]}
209
+ end
210
+
211
+ it "should do a hash roundtrip with monthdays filter" do
212
+ h = Rule.monthly.monthdays(1, 3, 7, -10).to_hash
213
+ restore = Rule.from_hash(h)
214
+
215
+ restore.filters(:monthdays).monthdays.should == [-10, 1, 3, 7]
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,150 @@
1
+ require 'spec_helper'
2
+
3
+ describe WeeklyRule do
4
+ describe "simple rule" do
5
+ before do
6
+ @rule = WeeklyRule.new
7
+ end
8
+
9
+ it "should return one week as step" do
10
+ @rule.step.should == 1.week
11
+ end
12
+
13
+ it "should find next date" do
14
+ base = Time.local(2010, 1, 1, 9, 30, 21)
15
+
16
+ @rule.next(Time.local(2010, 1, 1), base).should == Time.local(2010, 1, 1, 9, 30, 21)
17
+ @rule.next(Time.local(2010, 1, 1, 9, 30, 21), base).should == Time.local(2010, 1, 8, 9, 30, 21)
18
+ @rule.next(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 1, 8, 9, 30, 21)
19
+
20
+ # align forward should include base time
21
+ @rule.next(base, base).should == base + 1.week
22
+ end
23
+
24
+ it "should find previous date" do
25
+ base = Time.local(2010, 1, 1, 9, 30, 21)
26
+
27
+ @rule.previous(Time.local(2010, 1, 1), base).should == Time.local(2009, 12, 25, 9, 30, 21)
28
+ @rule.previous(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 1, 1, 9, 30, 21)
29
+
30
+ # align back should exclude base time
31
+ @rule.previous(base, base).should == Time.local(2009, 12, 25, 9, 30, 21)
32
+ end
33
+
34
+ it "should match dates" do
35
+ @rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2010, 1, 8, 9, 30)).should be_true
36
+ @rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2010, 1, 15, 9, 30)).should be_true
37
+
38
+ @rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2010, 1, 8, 9, 29)).should_not be_true
39
+ @rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2010, 1, 8, 10, 30)).should_not be_true
40
+ end
41
+ end
42
+
43
+ describe "finite rules" do
44
+ before do
45
+ @rule = WeeklyRule.new
46
+ end
47
+
48
+ it "should accept count and allow chaining" do
49
+ @rule.count(10).should be_a(WeeklyRule)
50
+ @rule.count.should == 10
51
+ end
52
+
53
+ it "should accept stop time" do
54
+ @rule.stop(Time.utc(2020, 1, 1)).should be_a(WeeklyRule)
55
+ @rule.stop.should == Time.utc(2020, 1, 1)
56
+ end
57
+
58
+ it "should report rule finiteness" do
59
+ WeeklyRule.new.count(5).should be_finite
60
+ WeeklyRule.new.stop(Time.utc(2020, 1, 1)).should be_finite
61
+
62
+ WeeklyRule.new.should_not be_finite
63
+ end
64
+ end
65
+
66
+ describe "rule with interval" do
67
+ before do
68
+ @every_other_week_rule = WeeklyRule.new(2)
69
+ @every_ten_weeks_rule = WeeklyRule.new(10)
70
+ end
71
+
72
+ it "should return corect step" do
73
+ @every_other_week_rule.step.should == 2.weeks
74
+ @every_ten_weeks_rule.step.should == 10.weeks
75
+ end
76
+
77
+ it "should find next date" do
78
+ base = Time.local(2010, 1, 1, 9, 30, 21)
79
+
80
+ @every_other_week_rule.next(Time.local(2010, 1, 1), base).should == Time.local(2010, 1, 1, 9, 30, 21)
81
+ @every_ten_weeks_rule.next(Time.local(2010, 1, 1), base).should == Time.local(2010, 1, 1, 9, 30, 21)
82
+
83
+ @every_other_week_rule.next(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 1, 15, 9, 30, 21)
84
+ @every_ten_weeks_rule.next(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 3, 12, 9, 30, 21)
85
+
86
+ # align forward should include base time
87
+ @every_other_week_rule.next(base, base).should == base + 2.weeks
88
+ @every_ten_weeks_rule.next(base, base).should == base + 10.weeks
89
+ end
90
+
91
+ it "should align dates back" do
92
+ base = Time.local(2010, 1, 1, 9, 30, 21)
93
+
94
+ @every_other_week_rule.previous(Time.local(2010, 1, 1), base).should == Time.local(2009, 12, 18, 9, 30, 21)
95
+ @every_ten_weeks_rule.previous(Time.local(2010, 1, 1), base).localtime.should == Time.local(2009, 10, 23, 9, 30, 21)
96
+
97
+ @every_other_week_rule.previous(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 1, 1, 9, 30, 21)
98
+ @every_ten_weeks_rule.previous(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 1, 1, 9, 30, 21)
99
+
100
+ # align forward should include base time
101
+ @every_other_week_rule.previous(base, base).should == base - 2.weeks
102
+ @every_ten_weeks_rule.previous(base, base).should == base - 10.weeks
103
+ end
104
+
105
+ it "should check date alignment" do
106
+ base = Time.local(2010, 1, 1, 9, 30)
107
+
108
+ @every_other_week_rule.match?(Time.local(2010, 1, 1, 9, 30), base).should be_true
109
+ @every_other_week_rule.match?(Time.local(2010, 1, 15, 9, 30), base).should be_true
110
+
111
+ @every_ten_weeks_rule.match?(Time.local(2010, 1, 1, 9, 30), base).should be_true
112
+ @every_ten_weeks_rule.match?(Time.local(2010, 3, 12, 9, 30), base).should be_true
113
+
114
+ @every_other_week_rule.match?(Time.local(2010, 1, 2, 9, 30), base).should_not be_true
115
+ @every_ten_weeks_rule.match?(Time.local(2010, 1, 5, 9, 30), base).should_not be_true
116
+ end
117
+ end
118
+
119
+ describe "serialization" do
120
+ it "should do a simple hash roundtrip" do
121
+ h = Rule.weekly(5).to_hash
122
+ restore = Rule.from_hash(h)
123
+
124
+ restore.class.should == WeeklyRule
125
+ restore.interval.should == 5
126
+ restore.step.should == 5.weeks
127
+ end
128
+
129
+ it "should do a hash roundtrip with count" do
130
+ h = Rule.weekly.count(10).to_hash
131
+ restore = Rule.from_hash(h)
132
+
133
+ restore.count.should == 10
134
+ end
135
+
136
+ it "should do a hash roundtrip with stop" do
137
+ h = Rule.weekly.stop(Time.local(2020, 10, 10)).to_hash
138
+ restore = Rule.from_hash(h)
139
+
140
+ restore.stop.should == Time.local(2020, 10, 10)
141
+ end
142
+
143
+ it "should do a hash roundtrip with weekdays filter" do
144
+ h = Rule.weekly.weekdays(:mon, :tuesday).to_hash
145
+ restore = Rule.from_hash(h)
146
+
147
+ restore.filters(:weekdays).weekdays.should == [1, 2]
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,232 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe YearlyRule do
5
+ describe "simple rule" do
6
+ before do
7
+ @rule = YearlyRule.new
8
+ end
9
+
10
+ it "should return one day as step" do
11
+ @rule.step.should == 1.year
12
+ end
13
+
14
+ it "should give next date" do
15
+ base = Time.local(2010, 1, 1, 9, 30, 21)
16
+
17
+ @rule.next(Time.local(2010, 1, 1), base).should == Time.local(2010, 1, 1, 9, 30, 21)
18
+ @rule.next(Time.local(2010, 1, 1, 9, 30, 21), base).should == Time.local(2011, 1, 1, 9, 30, 21)
19
+ @rule.next(Time.local(2010, 1, 1, 10), base).should == Time.local(2011, 1, 1, 9, 30, 21)
20
+
21
+ # align forward should include base time
22
+ @rule.next(base, base).should == base + 1.year
23
+ end
24
+
25
+ it "should give previous date" do
26
+ base = Time.local(2010, 1, 1, 9, 30, 21)
27
+
28
+ @rule.previous(Time.local(2010, 1, 1), base).should == Time.local(2009, 1, 1, 9, 30, 21)
29
+ @rule.previous(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 1, 1, 9, 30, 21)
30
+
31
+ # align back should exclude base time
32
+ @rule.previous(base, base).should == Time.local(2009, 1, 1, 9, 30, 21)
33
+ end
34
+
35
+ it "should match dates" do
36
+ @rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2011, 1, 1, 9, 30)).should be_true
37
+
38
+ @rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2011, 1, 1, 9, 29)).should_not be_true
39
+ @rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2011, 1, 2, 9, 30)).should_not be_true
40
+ @rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2011, 2, 1, 9, 30)).should_not be_true
41
+ end
42
+ end
43
+
44
+ describe "finite rules" do
45
+ before do
46
+ @rule = YearlyRule.new
47
+ end
48
+
49
+ it "should accept count and allow chaining" do
50
+ @rule.count(10).should be_a(YearlyRule)
51
+ @rule.count.should == 10
52
+ end
53
+
54
+ it "should accept stop time" do
55
+ @rule.stop(Time.utc(2020, 1, 1)).should be_a(YearlyRule)
56
+ @rule.stop.should == Time.utc(2020, 1, 1)
57
+ end
58
+
59
+ it "should report rule finiteness" do
60
+ YearlyRule.new.count(5).should be_finite
61
+ YearlyRule.new.stop(Time.utc(2020, 1, 1)).should be_finite
62
+
63
+ YearlyRule.new.should_not be_finite
64
+ end
65
+ end
66
+
67
+ describe "rule with interval" do
68
+ before do
69
+ @every_other_year_rule = YearlyRule.new(2)
70
+ @every_ten_years_rule = YearlyRule.new(10)
71
+ end
72
+
73
+ it "should return corect step" do
74
+ @every_other_year_rule.step.should == 2.years
75
+ @every_ten_years_rule.step.should == 10.years
76
+ end
77
+
78
+ it "should find next date" do
79
+ base = Time.local(2010, 1, 1, 9, 30, 21)
80
+
81
+ @every_other_year_rule.next(Time.local(2010, 1, 1), base).should == Time.local(2010, 1, 1, 9, 30, 21)
82
+ @every_ten_years_rule.next(Time.local(2010, 1, 1), base).should == Time.local(2010, 1, 1, 9, 30, 21)
83
+
84
+ @every_other_year_rule.next(Time.local(2010, 1, 1, 10), base).should == Time.local(2012, 1, 1, 9, 30, 21)
85
+ @every_ten_years_rule.next(Time.local(2010, 1, 1, 10), base).should == Time.local(2020, 1, 1, 9, 30, 21)
86
+
87
+ # align forward should include base time
88
+ @every_other_year_rule.next(base, base).should == base + 2.years
89
+ @every_ten_years_rule.next(base, base).should == base + 10.years
90
+ end
91
+
92
+ it "should find previous date" do
93
+ base = Time.local(2010, 1, 1, 9, 30, 21)
94
+
95
+ @every_other_year_rule.previous(Time.local(2010, 1, 1), base).should == Time.local(2008, 1, 1, 9, 30, 21)
96
+ @every_ten_years_rule.previous(Time.local(2010, 1, 1), base).should == Time.local(2000, 1, 1, 9, 30, 21)
97
+
98
+ @every_other_year_rule.previous(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 1, 1, 9, 30, 21)
99
+ @every_ten_years_rule.previous(Time.local(2010, 1, 1, 10), base).should == Time.local(2010, 1, 1, 9, 30, 21)
100
+
101
+ # align back should exclude base time
102
+ @every_other_year_rule.previous(base, base).should == Time.local(2008, 1, 1, 9, 30, 21)
103
+ @every_ten_years_rule.previous(base, base).should == Time.local(2000, 1, 1, 9, 30, 21)
104
+ end
105
+
106
+ it "should match dates" do
107
+ # same year, same datetime
108
+ @every_ten_years_rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2010, 1, 1, 9, 30)).should be_true
109
+ @every_ten_years_rule.match?(Time.local(2010, 1, 1, 9, 30), Time.local(2010, 1, 1, 9, 30)).should be_true
110
+
111
+ # right year, same dattime
112
+ @every_other_year_rule.match?(Time.local(2012, 1, 12, 9, 30), Time.local(2010, 1, 12, 9, 30)).should be_true
113
+ @every_other_year_rule.match?(Time.local(2020, 1, 12, 9, 30), Time.local(2010, 1, 12, 9, 30)).should be_true
114
+
115
+ # wrong year, same datetime
116
+ @every_ten_years_rule.match?(Time.local(2011, 1, 1, 9, 30), Time.local(2010, 1, 1, 9, 30)).should_not be_true
117
+ @every_ten_years_rule.match?(Time.local(2015, 1, 1, 9, 30), Time.local(2010, 1, 1, 9, 30)).should_not be_true
118
+
119
+ # right year, different datetime
120
+ @every_other_year_rule.match?(Time.local(2012, 3, 8, 9, 20), Time.local(2010, 1, 12, 9, 30)).should_not be_true
121
+ @every_other_year_rule.match?(Time.local(2020, 6, 21, 9, 35), Time.local(2010, 1, 12, 9, 30)).should_not be_true
122
+ end
123
+ end
124
+
125
+ describe "rule with filters" do
126
+ before do
127
+ @base = Time.utc(2000, 1, 1, 9, 30, 21)
128
+ @rule = Rule.yearly.months(1, 2).weekdays(1,3)
129
+ end
130
+
131
+ it "should find next date" do
132
+ @rule.next(Time.utc(2000, 1, 1), @base).should == Time.utc(2000, 1, 3, 9, 30, 21)
133
+ @rule.next(Time.utc(2000, 1, 3, 10), @base).should == Time.utc(2000, 1, 5, 9, 30, 21)
134
+
135
+ @rule.next(Time.utc(2000, 2, 2), @base).should == Time.utc(2000, 2, 2, 9, 30, 21)
136
+ @rule.next(Time.utc(2000, 2, 2, 10), @base).should == Time.utc(2000, 2, 7, 9, 30, 21)
137
+ @rule.next(Time.utc(2000, 2, 29), @base).should == Time.utc(2001, 1, 1, 9, 30, 21)
138
+ @rule.next(Time.utc(2000, 3, 1), @base).should == Time.utc(2001, 1, 1, 9, 30, 21)
139
+ end
140
+
141
+ it "should find previous date" do
142
+ @rule.previous(Time.utc(2000, 1, 1), @base).should == Time.utc(1999, 2, 24, 9, 30, 21)
143
+ @rule.previous(Time.utc(2000, 1, 3, 10), @base).should == Time.utc(2000, 1, 3, 9, 30, 21)
144
+
145
+ @rule.previous(Time.utc(2000, 2, 2), @base).should == Time.utc(2000, 1, 31, 9, 30, 21)
146
+ @rule.previous(Time.utc(2000, 2, 2, 10), @base).should == Time.utc(2000, 2, 2, 9, 30, 21)
147
+ @rule.previous(Time.utc(2000, 3, 3), @base).should == Time.utc(2000, 2, 28, 9, 30, 21)
148
+ @rule.previous(Time.utc(2000, 3, 1), @base).should == Time.utc(2000, 2, 28, 9, 30, 21)
149
+ end
150
+
151
+ it "should match dates" do
152
+ # weekdays match
153
+ @rule.match?(Time.utc(2000, 1, 3, 9, 30, 21), @base).should be_true
154
+ @rule.match?(Time.utc(2000, 1, 5, 9, 30, 21), @base).should be_true
155
+
156
+ @rule.match?(Time.utc(2000, 1, 4, 9, 30, 21), @base).should_not be_true
157
+ @rule.match?(Time.utc(2000, 1, 6, 9, 30, 21), @base).should_not be_true
158
+
159
+ # months match
160
+ @rule.match?(Time.utc(2000, 2, 23, 9, 30, 21), @base).should be_true
161
+ @rule.match?(Time.utc(2000, 2, 2, 9, 30, 21), @base).should be_true
162
+
163
+ @rule.match?(Time.utc(2000, 3, 3, 9, 30, 21), @base).should_not be_true
164
+ @rule.match?(Time.utc(2000, 3, 4, 9, 30, 21), @base).should_not be_true
165
+
166
+ # wrong time
167
+ @rule.match?(Time.utc(2000, 1, 3, 9, 30, 28), @base).should_not be_true
168
+ @rule.match?(Time.utc(2000, 1, 3, 9, 12, 29), @base).should_not be_true
169
+ @rule.match?(Time.utc(2000, 1, 3, 10, 30, 29), @base).should_not be_true
170
+ end
171
+ end
172
+
173
+ describe "serialization" do
174
+ it "should do a hash roundtrip" do
175
+ h = Rule.yearly(5).to_hash
176
+ restore = Rule.from_hash(h)
177
+
178
+ restore.class.should == YearlyRule
179
+ restore.interval.should == 5
180
+ restore.step.should == 5.years
181
+ end
182
+
183
+ it "should do a hash roundtrip with count" do
184
+ h = Rule.yearly.count(10).to_hash
185
+ restore = Rule.from_hash(h)
186
+
187
+ restore.count.should == 10
188
+ end
189
+
190
+ it "should do a hash roundtrip with stop" do
191
+ h = Rule.yearly.stop(Time.local(2020, 10, 10)).to_hash
192
+ restore = Rule.from_hash(h)
193
+
194
+ restore.stop.should == Time.local(2020, 10, 10)
195
+ end
196
+
197
+ it "should do a hash roundtrip with weekdays filter" do
198
+ h = Rule.yearly.weekdays(:mon, :tuesday).to_hash
199
+ restore = Rule.from_hash(h)
200
+
201
+ restore.filters(:weekdays).weekdays.should == [1, 2]
202
+ end
203
+
204
+ it "should do a hash roundtrip with ordered weekdays filter" do
205
+ h = Rule.yearly.weekdays(:mon => 1, :tuesday => [2, -3]).to_hash
206
+ restore = Rule.from_hash(h)
207
+
208
+ restore.filters(:weekdays).ordered_weekdays.should == {:mo => [1], :tu => [-3, 2]}
209
+ end
210
+
211
+ it "should do a hash roundtrip with monthdays filter" do
212
+ h = Rule.yearly.monthdays(1, 3, 7, -10).to_hash
213
+ restore = Rule.from_hash(h)
214
+
215
+ restore.filters(:monthdays).monthdays.should == [-10, 1, 3, 7]
216
+ end
217
+
218
+ it "should do a hash roundtrip with months filter" do
219
+ h = Rule.yearly.months(1, 3, 12, -5).to_hash
220
+ restore = Rule.from_hash(h)
221
+
222
+ restore.filters(:months).months.should == [-5, 1, 3, 12]
223
+ end
224
+
225
+ it "should do a hash roundtrip with yeardays filter" do
226
+ h = Rule.yearly.yeardays(1, 30, 120, -50).to_hash
227
+ restore = Rule.from_hash(h)
228
+
229
+ restore.filters(:yeardays).yeardays.should == [-50, 1, 30, 120]
230
+ end
231
+ end
232
+ end