acts_as_event_owner 1.0.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/.gitignore +7 -0
- data/LICENSE +24 -0
- data/README.textile +205 -0
- data/Rakefile +28 -0
- data/acts_as_event_owner.gemspec +76 -0
- data/generators/acts_as_event_owner_migration/USAGE +6 -0
- data/generators/acts_as_event_owner_migration/acts_as_event_owner_migration_generator.rb +7 -0
- data/generators/acts_as_event_owner_migration/templates/acts_as_event_owner_migration.rb +38 -0
- data/lib/acts_as_event_owner/core.rb +38 -0
- data/lib/acts_as_event_owner/event_occurrence.rb +6 -0
- data/lib/acts_as_event_owner/event_specification.rb +152 -0
- data/lib/acts_as_event_owner/exception.rb +4 -0
- data/lib/acts_as_event_owner/railtie.rb +13 -0
- data/lib/acts_as_event_owner/version.rb +3 -0
- data/lib/acts_as_event_owner.rb +17 -0
- data/lib/generators/acts_as_event_owner/migration/migration_generator.rb +31 -0
- data/lib/generators/acts_as_event_owner/migration/templates/active_record/acts_as_event_owner_migration.rb +38 -0
- data/lib/generators/acts_as_event_owner_migration/USAGE +6 -0
- data/lib/generators/acts_as_event_owner_migration/acts_as_event_owner_migration_generator.rb +7 -0
- data/lib/generators/acts_as_event_owner_migration/templates/acts_as_event_owner_migration.rb +38 -0
- data/lib/tasks/acts_as_event_owner_tasks.rake +14 -0
- data/rails/init.rb +1 -0
- data/spec/acts_as_event_owner/core_spec.rb +62 -0
- data/spec/acts_as_event_owner/event_specification_spec.rb +365 -0
- data/spec/schema.rb +43 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/model_builders.rb +13 -0
- data/spec/support/user.rb +3 -0
- metadata +106 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
class ActsAsEventOwnerMigration < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :event_specifications do |t|
|
4
|
+
t.integer :owner_id
|
5
|
+
t.string :owner_type
|
6
|
+
t.string :description
|
7
|
+
t.datetime :start_at
|
8
|
+
t.datetime :end_at
|
9
|
+
t.string :repeat # daily, weekly, monthly, yearly
|
10
|
+
t.integer :frequency, :default => 1 # every 'n' days, weeks, months, or years
|
11
|
+
t.string :on # su, mo, tu, we, th, fr, sa, 1-31, jan-dec
|
12
|
+
t.string :on_the # first, second, third, fourth, last
|
13
|
+
t.string :target # su, mo, tu, we, th, fr, sa, day, wkday, wkend
|
14
|
+
t.datetime :until
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
|
18
|
+
add_index :event_specifications, [:owner_id, :owner_type]
|
19
|
+
|
20
|
+
create_table :event_occurrences do |t|
|
21
|
+
t.integer :owner_id
|
22
|
+
t.string :owner_type
|
23
|
+
t.integer :event_specification_id
|
24
|
+
t.datetime :start_at
|
25
|
+
t.datetime :end_at
|
26
|
+
t.string :description
|
27
|
+
t.timestamps
|
28
|
+
end
|
29
|
+
|
30
|
+
add_index :event_occurrences, [:owner_id, :owner_type]
|
31
|
+
add_index :event_occurrences, :event_specification_id
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.down
|
35
|
+
drop_table :event_specifications
|
36
|
+
drop_table :event_occurrences
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class ActsAsEventOwnerMigration < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :event_specifications do |t|
|
4
|
+
t.integer :owner_id
|
5
|
+
t.string :owner_type
|
6
|
+
t.string :description
|
7
|
+
t.datetime :start_at
|
8
|
+
t.datetime :end_at
|
9
|
+
t.string :repeat # daily, weekly, monthly, yearly
|
10
|
+
t.integer :frequency, :default => 1 # every 'n' days, weeks, months, or years
|
11
|
+
t.string :on # su, mo, tu, we, th, fr, sa, 1-31, jan-dec
|
12
|
+
t.string :on_the # first, second, third, fourth, last
|
13
|
+
t.string :target # su, mo, tu, we, th, fr, sa, day, wkday, wkend
|
14
|
+
t.datetime :until
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
|
18
|
+
add_index :event_specifications, [:owner_id, :owner_type]
|
19
|
+
|
20
|
+
create_table :event_occurrences do |t|
|
21
|
+
t.integer :owner_id
|
22
|
+
t.string :owner_type
|
23
|
+
t.integer :event_specification_id
|
24
|
+
t.datetime :start_at
|
25
|
+
t.datetime :end_at
|
26
|
+
t.string :description
|
27
|
+
t.timestamps
|
28
|
+
end
|
29
|
+
|
30
|
+
add_index :event_occurrences, [:owner_id, :owner_type]
|
31
|
+
add_index :event_occurrences, :event_specification_id
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.down
|
35
|
+
drop_table :event_specifications
|
36
|
+
drop_table :event_occurrences
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
namespace :acts_as_event_owner do
|
2
|
+
task :require_from do
|
3
|
+
raise "Set FROM to something understandable by Time.parse" if !ENV['FROM']
|
4
|
+
end
|
5
|
+
|
6
|
+
task :require_to do
|
7
|
+
raise "Set TO to something understandable by Time.parse" if !ENV['TO']
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Generate all events within a certain time window"
|
11
|
+
task :generate_events => [:environment, :require_from, :require_to] do
|
12
|
+
ActsAsEventOwner::EventSpecification.all(:conditions => "until IS NULL OR until >= '#{Time.now.utc.to_s(:db)}'").each {|spec| spec.generate_events(options)}
|
13
|
+
end
|
14
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'acts_as_event_owner'
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe ActsAsEventOwner::Core do
|
4
|
+
before(:each) do
|
5
|
+
clean_database!
|
6
|
+
@user = User.create :name => 'dude'
|
7
|
+
@now = Time.now.utc
|
8
|
+
@bod = Date.today.to_time.utc
|
9
|
+
end
|
10
|
+
|
11
|
+
it "adds associations to the host object" do
|
12
|
+
lambda {
|
13
|
+
@user.events
|
14
|
+
@user.event_specifications
|
15
|
+
}.should_not raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it "adds event specifications to the host object" do
|
19
|
+
lambda {
|
20
|
+
@user.event_specifications.create :description => 'walk the dog', :start_at => @now, :repeat => :daily, :frequency => 1
|
21
|
+
}.should change(EventSpecification, :count).by(1)
|
22
|
+
|
23
|
+
specs = @user.reload.event_specifications
|
24
|
+
specs.size.should == 1
|
25
|
+
end
|
26
|
+
|
27
|
+
it "adds events to the host object" do
|
28
|
+
@user.event_specifications.create :description => 'walk the dog', :start_at => @now, :repeat => :daily, :frequency => 1, :generate => false
|
29
|
+
@user.event_specifications.create :description => 'go to the gym', :start_at => @now, :repeat => :daily, :frequency => 2, :generate => false
|
30
|
+
|
31
|
+
lambda {
|
32
|
+
@user.events.generate :from => @bod, :to => @bod + 1.week
|
33
|
+
}.should change(EventOccurrence, :count).by(11)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "injects events into the association immediately" do
|
37
|
+
@user.event_specifications.create :description => 'walk the dog', :start_at => @now, :repeat => :daily, :frequency => 1, :generate => false
|
38
|
+
@user.events.should be_empty
|
39
|
+
@user.events.generate :from => @bod, :to => @bod + 1.week
|
40
|
+
@user.events.should be_present
|
41
|
+
@user.events.size.should == 7
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "events association" do
|
45
|
+
before(:each) do
|
46
|
+
@new_event = EventOccurrence.new
|
47
|
+
@new_event.should be_valid
|
48
|
+
end
|
49
|
+
|
50
|
+
it "raises an exception if #<< is called" do
|
51
|
+
lambda { @user.events << @new_event }.should raise_error(ActsAsEventOwner::Exception)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "raises an exception is #build is called" do
|
55
|
+
lambda { @user.events.build @new_event.attributes }.should raise_error(ActsAsEventOwner::Exception)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "raises an exception if #create is called" do
|
59
|
+
lambda { @user.events.create @new_event.attributes }.should raise_error(ActsAsEventOwner::Exception)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,365 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe ActsAsEventOwner::EventSpecification do
|
4
|
+
before(:each) do
|
5
|
+
clean_database!
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "defaults" do
|
9
|
+
it "defaults start_at to now" do
|
10
|
+
now = Time.now
|
11
|
+
Time.stub!(:now).and_return(now)
|
12
|
+
spec = new_event_specification
|
13
|
+
spec.should be_valid
|
14
|
+
spec.start_at.should == now
|
15
|
+
end
|
16
|
+
|
17
|
+
it "defaults duration to one hour" do
|
18
|
+
spec = new_event_specification
|
19
|
+
spec.should be_valid
|
20
|
+
spec.end_at.should == spec.start_at + 1.hour
|
21
|
+
end
|
22
|
+
|
23
|
+
it "defaults repeat until forever" do
|
24
|
+
spec = new_event_specification(:repeat => :daily)
|
25
|
+
spec.should be_valid
|
26
|
+
spec.until.should be_nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "validations" do
|
31
|
+
it "requires a valid repeat interval" do
|
32
|
+
spec = new_event_specification(:repeat => :bogus)
|
33
|
+
spec.should_not be_valid
|
34
|
+
spec.errors[:repeat].should be_present
|
35
|
+
end
|
36
|
+
|
37
|
+
it "requires a description" do
|
38
|
+
spec = new_event_specification(:description => nil)
|
39
|
+
spec.should_not be_valid
|
40
|
+
spec.errors[:description].should be_present
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "non-recurring events" do
|
45
|
+
it "passes validations" do
|
46
|
+
new_event_specification.should be_valid
|
47
|
+
end
|
48
|
+
|
49
|
+
it "does not generate an RRULE" do
|
50
|
+
new_event_specification.to_rrule.should be_nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "events recurring daily" do
|
55
|
+
it "passes validations" do
|
56
|
+
new_event_specification(:repeat => :daily).should be_valid
|
57
|
+
new_event_specification(:repeat => :daily, :frequency => 4).should be_valid
|
58
|
+
end
|
59
|
+
|
60
|
+
it "does not support invalid recurrence specifications" do
|
61
|
+
spec = new_event_specification(:repeat => :daily, :frequency => 'foo')
|
62
|
+
spec.should_not be_valid
|
63
|
+
spec.errors[:frequency].should be_present
|
64
|
+
|
65
|
+
spec = new_event_specification(:repeat => :daily, :on => [1, 2])
|
66
|
+
spec.should_not be_valid
|
67
|
+
spec.errors[:on].should be_present
|
68
|
+
|
69
|
+
spec = new_event_specification(:repeat => :daily, :on_the => :first)
|
70
|
+
spec.should_not be_valid
|
71
|
+
spec.errors[:on_the].should be_present
|
72
|
+
|
73
|
+
spec = new_event_specification(:repeat => :daily, :on_the => :first, :target => :wkday)
|
74
|
+
spec.should_not be_valid
|
75
|
+
spec.errors[:target].should be_present
|
76
|
+
end
|
77
|
+
|
78
|
+
it "defaults frequency to 1" do
|
79
|
+
new_event_specification(:repeat => :daily).frequency.should == 1
|
80
|
+
end
|
81
|
+
|
82
|
+
it "generates an RRULE" do
|
83
|
+
# every day
|
84
|
+
new_event_specification(:repeat => :daily).to_rrule.should == "FREQ=DAILY;INTERVAL=1"
|
85
|
+
# every four days
|
86
|
+
new_event_specification(:repeat => :daily, :frequency => 4).to_rrule.should == "FREQ=DAILY;INTERVAL=4"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "events recurring weekly" do
|
91
|
+
it "passes validations" do
|
92
|
+
new_event_specification(:repeat => :weekly).should be_valid
|
93
|
+
new_event_specification(:repeat => :weekly, :frequency => 2).should be_valid
|
94
|
+
new_event_specification(:repeat => :weekly, :on => [:mo, :we, :fr]).should be_valid
|
95
|
+
new_event_specification(:repeat => :weekly, :frequency => 2, :on => [:mo, :we, :fr]).should be_valid
|
96
|
+
new_event_specification(:repeat => :weekly, :frequency => 2, :on => [:mo, :we, :fr], :until => Time.parse("12/31/2010")).should be_valid
|
97
|
+
end
|
98
|
+
|
99
|
+
it "does not support invalid recurrence specifications" do
|
100
|
+
spec = new_event_specification(:repeat => :weekly, :frequency => 'foo')
|
101
|
+
spec.should_not be_valid
|
102
|
+
spec.errors[:frequency].should be_present
|
103
|
+
|
104
|
+
spec = new_event_specification(:repeat => :weekly, :on_the => :first, :target => :wkend)
|
105
|
+
spec.should_not be_valid
|
106
|
+
spec.errors[:on_the].should be_present
|
107
|
+
spec.errors[:target].should be_present
|
108
|
+
|
109
|
+
spec = new_event_specification(:repeat => :weekly, :on => '2')
|
110
|
+
spec.should_not be_valid
|
111
|
+
spec.errors[:on].should be_present
|
112
|
+
end
|
113
|
+
|
114
|
+
it "generates an RRULE" do
|
115
|
+
# every week
|
116
|
+
new_event_specification(:repeat => :weekly).to_rrule.should == "FREQ=WEEKLY;INTERVAL=1"
|
117
|
+
# every two weeks
|
118
|
+
new_event_specification(:repeat => :weekly, :frequency => 2).to_rrule.should == "FREQ=WEEKLY;INTERVAL=2"
|
119
|
+
# every monday, wednesday, and friday
|
120
|
+
new_event_specification(:repeat => :weekly, :on => [:mo, :we, :fr]).to_rrule.should == "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,WE,FR"
|
121
|
+
# every other monday, wednesday, and friday
|
122
|
+
new_event_specification(:repeat => :weekly, :frequency => 2, :on => [:mo, :we, :fr]).to_rrule.should == "FREQ=WEEKLY;INTERVAL=2;BYDAY=MO,WE,FR"
|
123
|
+
# every other monday, wednesday, and friday, until 12/31/2010
|
124
|
+
new_event_specification(:repeat => :weekly, :frequency => 2, :on => [:mo, :we, :fr], :until => Time.parse("12/31/2010")).to_rrule.should == "FREQ=WEEKLY;INTERVAL=2;BYDAY=MO,WE,FR;UNTIL=20101231T000000Z"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "events recurring monthly" do
|
129
|
+
it "passes validations" do
|
130
|
+
new_event_specification(:repeat => :monthly).should be_valid
|
131
|
+
new_event_specification(:repeat => :monthly, :frequency => 2).should be_valid
|
132
|
+
new_event_specification(:repeat => :monthly, :frequency => 2, :on => [1, 15, 20]).should be_valid
|
133
|
+
new_event_specification(:repeat => :monthly, :frequency => 2, :on_the => :third, :target => :wkday).should be_valid
|
134
|
+
new_event_specification(:repeat => :monthly, :frequency => 2, :on_the => :third, :target => [:mo, :we], :until => Time.parse("12/31/2010")).should be_valid
|
135
|
+
end
|
136
|
+
|
137
|
+
it "does not support invalid recurrence specification" do
|
138
|
+
spec = new_event_specification(:repeat => :monthly, :frequency => 'foo')
|
139
|
+
spec.should_not be_valid
|
140
|
+
spec.errors[:frequency].should be_present
|
141
|
+
|
142
|
+
spec = new_event_specification(:repeat => :monthly, :on => 2)
|
143
|
+
spec.should_not be_valid
|
144
|
+
spec.errors[:on].should be_present
|
145
|
+
|
146
|
+
spec = new_event_specification(:repeat => :monthly, :on => [2], :on_the => :first, :target => :wkday)
|
147
|
+
spec.should_not be_valid
|
148
|
+
spec.errors[:on].should be_present
|
149
|
+
|
150
|
+
spec = new_event_specification(:repeat => :monthly, :on_the => 2)
|
151
|
+
spec.should_not be_valid
|
152
|
+
spec.errors[:on_the].should be_present
|
153
|
+
|
154
|
+
spec = new_event_specification(:repeat => :monthly, :on_the => :first, :target => :we)
|
155
|
+
spec.should_not be_valid
|
156
|
+
spec.errors[:target].should be_present
|
157
|
+
|
158
|
+
spec = new_event_specification(:repeat => :monthly, :on_the => :first, :on => [2])
|
159
|
+
spec.should_not be_valid
|
160
|
+
spec.errors[:on].should be_present
|
161
|
+
end
|
162
|
+
|
163
|
+
it "generates an RRULE" do
|
164
|
+
# every month
|
165
|
+
new_event_specification(:repeat => :monthly).to_rrule.should == "FREQ=MONTHLY;INTERVAL=1"
|
166
|
+
# every two months
|
167
|
+
new_event_specification(:repeat => :monthly, :frequency => 2).to_rrule.should == "FREQ=MONTHLY;INTERVAL=2"
|
168
|
+
# every other month, on the 1st, 15th, and 20th
|
169
|
+
new_event_specification(:repeat => :monthly, :frequency => 2, :on => [1, 15, 20]).to_rrule.should == "FREQ=MONTHLY;INTERVAL=2;BYMONTHDAY=1,15,20"
|
170
|
+
# every other month, on the third weekday of the month
|
171
|
+
new_event_specification(:repeat => :monthly, :frequency => 2, :on_the => :third, :target => :wkday).to_rrule.should == "FREQ=MONTHLY;INTERVAL=2;BYSETPOS=3;BYDAY=MO,TU,WE,TH,FR"
|
172
|
+
# every other month, on the third monday and third wednesday, until 12/31/2010
|
173
|
+
new_event_specification(:repeat => :monthly, :frequency => 2, :on_the => :third, :target => [:mo, :we], :until => Time.parse("12/31/2010")).to_rrule.should == "FREQ=MONTHLY;INTERVAL=2;BYSETPOS=3;BYDAY=MO,WE;UNTIL=20101231T000000Z"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe "events recurring yearly" do
|
178
|
+
it "passes validations" do
|
179
|
+
new_event_specification(:repeat => :yearly, :on => [1,7]).should be_valid
|
180
|
+
new_event_specification(:repeat => :yearly, :frequency => 2, :on => [1,7]).should be_valid
|
181
|
+
new_event_specification(:repeat => :yearly, :on => [1,7], :on_the => :first, :target => :wkend).should be_valid
|
182
|
+
new_event_specification(:repeat => :yearly, :frequency => 2, :on => [1,7], :on_the => :first, :target => :wkday, :until => Time.parse("12/31/2010")).should be_valid
|
183
|
+
end
|
184
|
+
|
185
|
+
it "does not support invalid recurrence rules" do
|
186
|
+
spec = new_event_specification(:repeat => :yearly)
|
187
|
+
spec.should_not be_valid
|
188
|
+
spec.errors[:on].should be_present
|
189
|
+
|
190
|
+
spec = new_event_specification(:repeat => :yearly, :frequency => 3)
|
191
|
+
spec.should_not be_valid
|
192
|
+
spec.errors[:on].should be_present
|
193
|
+
|
194
|
+
spec = new_event_specification(:repeat => :yearly, :frequency => 'foo')
|
195
|
+
spec.should_not be_valid
|
196
|
+
spec.errors[:frequency].should be_present
|
197
|
+
|
198
|
+
spec = new_event_specification(:repeat => :yearly, :on => 2)
|
199
|
+
spec.should_not be_valid
|
200
|
+
spec.errors[:on].should be_present
|
201
|
+
|
202
|
+
spec = new_event_specification(:repeat => :yearly, :on => [2], :on_the => 'first')
|
203
|
+
spec.should_not be_valid
|
204
|
+
spec.errors[:on_the].should be_present
|
205
|
+
|
206
|
+
spec = new_event_specification(:repeat => :yearly, :on => [2], :on_the => :first, :target => 2)
|
207
|
+
spec.should_not be_valid
|
208
|
+
spec.errors[:target].should be_present
|
209
|
+
end
|
210
|
+
|
211
|
+
it "generates an RRULE" do
|
212
|
+
# every year in january and july
|
213
|
+
new_event_specification(:repeat => :yearly, :on => [1,7]).to_rrule.should == "FREQ=YEARLY;INTERVAL=1;BYMONTH=1,7"
|
214
|
+
# every other year, in january and july
|
215
|
+
new_event_specification(:repeat => :yearly, :frequency => 2, :on => [1,7]).to_rrule.should == "FREQ=YEARLY;INTERVAL=2;BYMONTH=1,7"
|
216
|
+
# every year, on the first weekend day in january and july
|
217
|
+
new_event_specification(:repeat => :yearly, :on => [1,7], :on_the => :first, :target => :wkend).to_rrule.should == "FREQ=YEARLY;INTERVAL=1;BYMONTH=1,7;BYSETPOS=1;BYDAY=SU,SA"
|
218
|
+
# every other year, on the first weekday in january and july, until 12/31/2010
|
219
|
+
new_event_specification(:repeat => :yearly, :frequency => 2, :on => [1,7], :on_the => :first, :target => :wkday, :until => Time.parse("12/31/2010")).to_rrule.should == "FREQ=YEARLY;INTERVAL=2;BYMONTH=1,7;BYSETPOS=1;BYDAY=MO,TU,WE,TH,FR;UNTIL=20101231T000000Z"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
describe "#generate_events" do
|
224
|
+
before(:each) do
|
225
|
+
@now = Time.now.utc
|
226
|
+
@bod = Date.today.to_time.utc
|
227
|
+
end
|
228
|
+
|
229
|
+
describe "non-recurring events" do
|
230
|
+
before(:each) do
|
231
|
+
@spec = create_event_specification :start_at => @now, :added_string => 'foo', :added_boolean => true, :added_datetime => Date.yesterday.to_time, :generate => false
|
232
|
+
end
|
233
|
+
|
234
|
+
it "generates a single event" do
|
235
|
+
lambda {
|
236
|
+
@spec.generate_events
|
237
|
+
}.should change(EventOccurrence, :count).by(1)
|
238
|
+
end
|
239
|
+
|
240
|
+
it "copies added columns from event_specifications to event_occurrences" do
|
241
|
+
@spec.generate_events
|
242
|
+
@spec.event_occurrences.first.added_string.should == @spec.added_string
|
243
|
+
@spec.event_occurrences.first.added_boolean.should == @spec.added_boolean
|
244
|
+
@spec.event_occurrences.first.added_datetime.should == @spec.added_datetime
|
245
|
+
end
|
246
|
+
|
247
|
+
it "allows attribute overrides" do
|
248
|
+
@spec.generate_events :attributes => { :description => 'something new', :added_string => 'something else new'}
|
249
|
+
@spec.event_occurrences.first.description.should == 'something new'
|
250
|
+
@spec.event_occurrences.first.added_string.should == 'something else new'
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe "recurring events" do
|
255
|
+
before(:each) do
|
256
|
+
@spec = create_event_specification :description => 'walk the dog', :start_at => @now, :repeat => :daily, :frequency => 1, :generate => false
|
257
|
+
end
|
258
|
+
|
259
|
+
it "generates recurring events according to the rrule" do
|
260
|
+
lambda {
|
261
|
+
@spec.generate_events :from => @bod, :to => @bod + 1.week
|
262
|
+
}.should change(EventOccurrence, :count).by(7)
|
263
|
+
end
|
264
|
+
|
265
|
+
it "does not generate events before the specified :from" do
|
266
|
+
lambda {
|
267
|
+
@spec.generate_events :from => @bod + 1.day, :to => @bod + 1.week
|
268
|
+
}.should change(EventOccurrence, :count).by(6)
|
269
|
+
end
|
270
|
+
|
271
|
+
it "does not generate events after the specified :to" do
|
272
|
+
lambda {
|
273
|
+
@spec.generate_events :from => @bod + 1.day, :to => @bod + 6.days
|
274
|
+
}.should change(EventOccurrence, :count).by(5)
|
275
|
+
end
|
276
|
+
|
277
|
+
it "does not generate more events than the specified :count" do
|
278
|
+
lambda {
|
279
|
+
@spec.generate_events :from => @bod, :to => @bod + 1.week, :count => 3
|
280
|
+
}.should change(EventOccurrence, :count).by(3)
|
281
|
+
end
|
282
|
+
|
283
|
+
it "returns the new events" do
|
284
|
+
events = @spec.generate_events :from => @bod, :to => @bod + 1.week
|
285
|
+
events.should be_present
|
286
|
+
events.first.class.should == EventOccurrence
|
287
|
+
end
|
288
|
+
|
289
|
+
it "returns but does not persist duplicate events" do
|
290
|
+
lambda {
|
291
|
+
@spec.generate_events :from => @bod, :to => @bod + 1.week
|
292
|
+
}.should change(EventOccurrence, :count).by(7)
|
293
|
+
|
294
|
+
lambda {
|
295
|
+
events = @spec.generate_events :from => @bod, :to => @bod + 1.week
|
296
|
+
events.should be_present
|
297
|
+
events.size.should == 7
|
298
|
+
}.should_not change(EventOccurrence, :count)
|
299
|
+
end
|
300
|
+
|
301
|
+
it "raises an exception if the event specification is invalid" do
|
302
|
+
spec = new_event_specification(:description => nil)
|
303
|
+
spec.should_not be_valid
|
304
|
+
lambda {
|
305
|
+
spec.generate_events :from => @bod
|
306
|
+
}.should raise_error(ActsAsEventOwner::Exception)
|
307
|
+
end
|
308
|
+
|
309
|
+
it "does not generate events for specifications that are past their end_at" do
|
310
|
+
@spec.update_attributes! :start_at => @now - 1.week, :until => @now - 2.days
|
311
|
+
lambda {
|
312
|
+
@spec.generate_events :from => @bod, :to => @bod + 1.week
|
313
|
+
}.should_not change(EventOccurrence, :count)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
describe "autogeneration" do
|
319
|
+
before(:each) do
|
320
|
+
@now = Time.now.utc
|
321
|
+
@bod = Date.today.to_time.utc
|
322
|
+
end
|
323
|
+
|
324
|
+
def create_daily_event(generate=nil)
|
325
|
+
create_event_specification :description => 'walk the dog', :start_at => @now, :repeat => :daily, :frequency => 2, :generate => generate
|
326
|
+
end
|
327
|
+
|
328
|
+
it "generates 30 days worth of events by default" do
|
329
|
+
lambda {
|
330
|
+
create_daily_event
|
331
|
+
}.should change(EventOccurrence, :count).by(15)
|
332
|
+
end
|
333
|
+
|
334
|
+
it "does not generate any events if the :generate attribute is set to false" do
|
335
|
+
lambda {
|
336
|
+
create_daily_event(false)
|
337
|
+
}.should_not change(EventOccurrence, :count)
|
338
|
+
end
|
339
|
+
|
340
|
+
it "generates events according the :generate attribute" do
|
341
|
+
lambda {
|
342
|
+
create_daily_event(:to => @now + 15.days)
|
343
|
+
}.should change(EventOccurrence, :count).by(8)
|
344
|
+
|
345
|
+
lambda {
|
346
|
+
create_daily_event(:count => 5)
|
347
|
+
}.should change(EventOccurrence, :count).by(5)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
describe "self.generate_events" do
|
352
|
+
before(:each) do
|
353
|
+
@now = Time.now.utc
|
354
|
+
@bod = Date.today.to_time.utc
|
355
|
+
@walking_the_dog = create_event_specification :description => 'walk the dog', :start_at => @now, :repeat => :daily, :frequency => 1, :generate => false
|
356
|
+
@taking_out_the_trash = create_event_specification :description => 'take out the trash', :start_at => @now, :repeat => :daily, :frequency => 3, :generate => false
|
357
|
+
end
|
358
|
+
|
359
|
+
it "generates events for all event specifications" do
|
360
|
+
lambda {
|
361
|
+
ActsAsEventOwner::EventSpecification.generate_events :from => @bod, :to => @bod + 1.week
|
362
|
+
}.should change(EventOccurrence, :count).by(10)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
data/spec/schema.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 1) do
|
2
|
+
create_table "event_occurrences", :force => true do |t|
|
3
|
+
t.integer "owner_id"
|
4
|
+
t.string "owner_type"
|
5
|
+
t.integer "event_specification_id"
|
6
|
+
t.datetime "start_at"
|
7
|
+
t.datetime "end_at"
|
8
|
+
t.string "description"
|
9
|
+
t.datetime "created_at"
|
10
|
+
t.datetime "updated_at"
|
11
|
+
t.string "added_string"
|
12
|
+
t.boolean "added_boolean"
|
13
|
+
t.datetime "added_datetime"
|
14
|
+
end
|
15
|
+
add_index "event_occurrences", ["event_specification_id"], :name => "index_event_occurrences_on_event_specification_id"
|
16
|
+
add_index "event_occurrences", ["owner_id", "owner_type"], :name => "index_event_occurrences_on_owner_id_and_owner_type"
|
17
|
+
|
18
|
+
create_table "event_specifications", :force => true do |t|
|
19
|
+
t.integer "owner_id"
|
20
|
+
t.string "owner_type"
|
21
|
+
t.string "description"
|
22
|
+
t.datetime "start_at"
|
23
|
+
t.datetime "end_at"
|
24
|
+
t.string "repeat"
|
25
|
+
t.integer "frequency", :default => 1
|
26
|
+
t.string "on"
|
27
|
+
t.string "on_the"
|
28
|
+
t.string "target"
|
29
|
+
t.datetime "until"
|
30
|
+
t.datetime "created_at"
|
31
|
+
t.datetime "updated_at"
|
32
|
+
t.string "added_string"
|
33
|
+
t.boolean "added_boolean"
|
34
|
+
t.datetime "added_datetime"
|
35
|
+
end
|
36
|
+
add_index "event_specifications", ["owner_id", "owner_type"], :name => "index_event_specifications_on_owner_id_and_owner_type"
|
37
|
+
|
38
|
+
create_table "users", :force => true do |t|
|
39
|
+
t.string "name"
|
40
|
+
t.datetime "created_at"
|
41
|
+
t.datetime "updated_at"
|
42
|
+
end
|
43
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_record'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
ActiveRecord::Base.establish_connection({
|
6
|
+
:adapter => 'sqlite3',
|
7
|
+
:database => ':memory:'
|
8
|
+
})
|
9
|
+
# ActiveRecord::Base.logger = Logger.new(STDOUT)
|
10
|
+
|
11
|
+
require File.expand_path('../../lib/acts_as_event_owner', __FILE__)
|
12
|
+
include ActsAsEventOwner
|
13
|
+
|
14
|
+
require 'support/model_builders'
|
15
|
+
require 'support/user'
|
16
|
+
|
17
|
+
ActiveRecord::Base.silence do
|
18
|
+
ActiveRecord::Migration.verbose = false
|
19
|
+
load(File.dirname(__FILE__) + '/schema.rb')
|
20
|
+
end
|
21
|
+
|
22
|
+
def clean_database!
|
23
|
+
[ActsAsEventOwner::EventSpecification, ActsAsEventOwner::EventOccurrence, User].each do |model|
|
24
|
+
ActiveRecord::Base.connection.execute "DELETE FROM #{model.table_name}"
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
def attributes_for_event_specification(overrides={})
|
2
|
+
{
|
3
|
+
:description => 'do something'
|
4
|
+
}.merge(overrides)
|
5
|
+
end
|
6
|
+
|
7
|
+
def new_event_specification(overrides={})
|
8
|
+
ActsAsEventOwner::EventSpecification.new(attributes_for_event_specification(overrides))
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_event_specification(overrides={})
|
12
|
+
ActsAsEventOwner::EventSpecification.create(attributes_for_event_specification(overrides))
|
13
|
+
end
|