acts_as_bookable 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +43 -0
  6. data/Appraisals +21 -0
  7. data/Gemfile +21 -0
  8. data/Gemfile.lock +168 -0
  9. data/Guardfile +5 -0
  10. data/MIT-LICENSE +20 -0
  11. data/README.md +473 -0
  12. data/Rakefile +19 -0
  13. data/acts_as_bookable.gemspec +41 -0
  14. data/app/assets/images/acts_as_bookable/.keep +0 -0
  15. data/app/assets/javascripts/acts_as_bookable/application.js +13 -0
  16. data/app/assets/stylesheets/acts_as_bookable/application.css +15 -0
  17. data/app/controllers/acts_as_bookable/application_controller.rb +4 -0
  18. data/app/helpers/acts_as_bookable/application_helper.rb +4 -0
  19. data/app/views/layouts/acts_as_bookable/application.html.erb +14 -0
  20. data/bin/rails +12 -0
  21. data/config/locales/en.yml +12 -0
  22. data/config/routes.rb +2 -0
  23. data/db/migrate/20160217085200_create_acts_as_bookable_bookings.rb +14 -0
  24. data/gemfiles/activerecord_3.2.gemfile +16 -0
  25. data/gemfiles/activerecord_4.0.gemfile +16 -0
  26. data/gemfiles/activerecord_4.1.gemfile +16 -0
  27. data/gemfiles/activerecord_4.2.gemfile +17 -0
  28. data/gemfiles/activerecord_5.0.gemfile +17 -0
  29. data/lib/acts_as_bookable/bookable/core.rb +285 -0
  30. data/lib/acts_as_bookable/bookable.rb +56 -0
  31. data/lib/acts_as_bookable/booker.rb +70 -0
  32. data/lib/acts_as_bookable/booking.rb +54 -0
  33. data/lib/acts_as_bookable/db_utils.rb +39 -0
  34. data/lib/acts_as_bookable/engine.rb +5 -0
  35. data/lib/acts_as_bookable/t.rb +11 -0
  36. data/lib/acts_as_bookable/time_utils.rb +135 -0
  37. data/lib/acts_as_bookable/version.rb +3 -0
  38. data/lib/acts_as_bookable.rb +42 -0
  39. data/lib/tasks/acts_as_bookable_tasks.rake +4 -0
  40. data/spec/acts_as_bookable/acts_as_bookable_spec.rb +52 -0
  41. data/spec/acts_as_bookable/acts_as_booker_spec.rb +57 -0
  42. data/spec/acts_as_bookable/bookable/core_spec.rb +593 -0
  43. data/spec/acts_as_bookable/bookable_spec.rb +124 -0
  44. data/spec/acts_as_bookable/booker_spec.rb +140 -0
  45. data/spec/acts_as_bookable/booking_spec.rb +241 -0
  46. data/spec/acts_as_bookable/schedule_spec.rb +137 -0
  47. data/spec/acts_as_bookable/time_utils_spec.rb +525 -0
  48. data/spec/factories/bookable.rb +7 -0
  49. data/spec/factories/booker.rb +5 -0
  50. data/spec/factories/room.rb +11 -0
  51. data/spec/internal/app/models/Bookable.rb +3 -0
  52. data/spec/internal/app/models/Booker.rb +3 -0
  53. data/spec/internal/app/models/Event.rb +3 -0
  54. data/spec/internal/app/models/Generic.rb +2 -0
  55. data/spec/internal/app/models/NotBooker.rb +2 -0
  56. data/spec/internal/app/models/Room.rb +3 -0
  57. data/spec/internal/app/models/Show.rb +3 -0
  58. data/spec/internal/app/models/Unbookable.rb +2 -0
  59. data/spec/internal/config/database.yml.sample +17 -0
  60. data/spec/internal/db/schema.rb +51 -0
  61. data/spec/spec_helper.rb +26 -0
  62. data/spec/support/0-helpers.rb +32 -0
  63. data/spec/support/1-database.rb +42 -0
  64. data/spec/support/2-database_cleaner.rb +21 -0
  65. data/spec/support/3-factory_girl.rb +12 -0
  66. metadata +296 -0
@@ -0,0 +1,525 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ActsAsBookable::TimeUtils' do
4
+
5
+ describe '#time_in_interval?' do
6
+ before :each do
7
+ @interval_start = Time.now
8
+ @interval_end = Time.now + 1.hour
9
+ end
10
+
11
+ describe 'returns true' do
12
+ it 'when time is the interval_start' do
13
+ time = @interval_start
14
+ expect(ActsAsBookable::TimeUtils.time_in_interval?(time,@interval_start,@interval_end)).to eq true
15
+ end
16
+
17
+ it 'when time is bewteen interval_start and interval_end' do
18
+ time = @interval_start + 5.minutes
19
+ expect(ActsAsBookable::TimeUtils.time_in_interval?(time,@interval_start,@interval_end)).to eq true
20
+ end
21
+
22
+ it 'when time is very close to interval end' do
23
+ time = @interval_end - 1.second
24
+ expect(ActsAsBookable::TimeUtils.time_in_interval?(time,@interval_start,@interval_end)).to eq true
25
+ end
26
+
27
+ end
28
+
29
+ describe 'returns false' do
30
+ it 'when time is before interval_start' do
31
+ time = @interval_start - 1.second
32
+ expect(ActsAsBookable::TimeUtils.time_in_interval?(time,@interval_start,@interval_end)).to eq false
33
+ end
34
+
35
+ it 'when time is after interval_end' do
36
+ time = @interval_end + 1.second
37
+ expect(ActsAsBookable::TimeUtils.time_in_interval?(time,@interval_start,@interval_end)).to eq false
38
+ end
39
+
40
+ it 'when time is interval_end' do
41
+ time = @interval_end
42
+ expect(ActsAsBookable::TimeUtils.time_in_interval?(time,@interval_start,@interval_end)).to eq false
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '#interval_in_schedule?' do
48
+ before :each do
49
+ @day0 = '2016-01-05'.to_date
50
+ @schedule = IceCube::Schedule.new(@day0,duration: 1.day)
51
+ @schedule.add_recurrence_rule IceCube::Rule.monthly.day_of_month(1,3,5,7)
52
+ end
53
+
54
+ describe 'returns true' do
55
+ it 'when range starts and ends in the middle of an occurrence' do
56
+ time_start = @day0 + 1.hour
57
+ time_end = @day0 + 3.hours
58
+ expect(ActsAsBookable::TimeUtils.interval_in_schedule?(@schedule,time_start,time_end)).to eq true
59
+ end
60
+
61
+ it 'when range starts and ends in the middle of another occurrence' do
62
+ time_start = @day0 + 2.days + 1.hour
63
+ time_end = @day0 + 2.days + 3.hours
64
+ expect(ActsAsBookable::TimeUtils.interval_in_schedule?(@schedule,time_start,time_end)).to eq true
65
+ end
66
+
67
+ it 'when range starts at the beginning of an occurrence and ends at the end of the same occurence' do
68
+ time_start = @day0
69
+ time_end = @day0 + 1.day - 1.second
70
+ expect(ActsAsBookable::TimeUtils.interval_in_schedule?(@schedule,time_start,time_end)).to eq true
71
+ end
72
+ end
73
+
74
+ describe 'retuns false' do
75
+ it 'when range starts and ends outside any occurrence' do
76
+ time_start = '2016-01-15'.to_date
77
+ time_end = time_start + 1.day
78
+ expect(ActsAsBookable::TimeUtils.interval_in_schedule?(@schedule,time_start,time_end)).to eq false
79
+ end
80
+
81
+ it 'when range starts and ends outside any occurrence but contains an occurrence' do
82
+ time_start = @day0 - 1.hour
83
+ time_end = @day0 + 1.day + 1.hour
84
+ expect(ActsAsBookable::TimeUtils.interval_in_schedule?(@schedule,time_start,time_end)).to eq false
85
+ end
86
+
87
+ it 'when range starts within an occurrence but ends outside it' do
88
+ time_start = @day0 + 1.hour
89
+ time_end = @day0 + 1.day + 1.hour
90
+ expect(ActsAsBookable::TimeUtils.interval_in_schedule?(@schedule,time_start,time_end)).to eq false
91
+ end
92
+
93
+ it 'when range starts outside any occurrence but ends within an occurrence' do
94
+ time_start = @day0 - 1.hour
95
+ time_end = @day0 + 1.hour
96
+ expect(ActsAsBookable::TimeUtils.interval_in_schedule?(@schedule,time_start,time_end)).to eq false
97
+ end
98
+
99
+ it 'when range starts within an occurrence and ends within a different occurrence' do
100
+ time_start = @day0 + 1.hour
101
+ time_end = @day0 + 2.days + 1.hour
102
+ expect(ActsAsBookable::TimeUtils.interval_in_schedule?(@schedule,time_start,time_end)).to eq false
103
+ end
104
+
105
+ it 'when range starts within an occurrence and ends just after the end of the same occurrence' do
106
+ time_start = @day0 + 1.hour
107
+ time_end = @day0 + 1.day
108
+ expect(ActsAsBookable::TimeUtils.interval_in_schedule?(@schedule,time_start,time_end)).to eq false
109
+ end
110
+ end
111
+ end
112
+
113
+ describe '#time_in_schedule?' do
114
+ before :each do
115
+ @day0 = '2016-01-05'.to_date
116
+ @schedule = IceCube::Schedule.new(@day0,duration: 1.day)
117
+ @schedule.add_recurrence_rule IceCube::Rule.monthly.day_of_month(1,3,5,7)
118
+ end
119
+
120
+ describe 'returns true' do
121
+ it 'when time is at the beginning of an occurrence' do
122
+ time = @day0
123
+ expect(ActsAsBookable::TimeUtils.time_in_schedule?(@schedule,time)).to eq true
124
+ end
125
+
126
+ it 'when time is in the middle of an occurrence' do
127
+ time = @day0 + 5.hours
128
+ expect(ActsAsBookable::TimeUtils.time_in_schedule?(@schedule,time)).to eq true
129
+ end
130
+
131
+ it 'when time is at the end of an occurrence' do
132
+ time = @day0 + 1.day - 1.second
133
+ expect(ActsAsBookable::TimeUtils.time_in_schedule?(@schedule, time)).to eq true
134
+ end
135
+ end
136
+
137
+ describe 'retuns false' do
138
+ it 'when time is outside an occurrence' do
139
+ time = '2016-01-15'.to_date
140
+ expect(ActsAsBookable::TimeUtils.time_in_schedule?(@schedule, time)).to eq false
141
+ end
142
+
143
+ it 'when time is close to the end of an occurrence, but outside it' do
144
+ time = @day0 + 1.day
145
+ expect(ActsAsBookable::TimeUtils.time_in_schedule?(@schedule, time)).to eq false
146
+ end
147
+
148
+ it 'when time is close to the beginning of an occurrence, but outside it' do
149
+ time = @day0 + 2.days - 1.second
150
+ end
151
+ end
152
+ end
153
+
154
+ describe '#subintervals' do
155
+ before :each do
156
+ @time = Time.now
157
+ end
158
+
159
+ it 'returns ArgumentError if called without an array' do
160
+ expect{ ActsAsBookable::TimeUtils.subintervals(1) }.to raise_error ArgumentError
161
+ end
162
+
163
+ it 'returns ArgumentError if an interval has no time_start or time_end' do
164
+ intervals = [
165
+ {time_start: @time, time_end: @time + 1.hour},
166
+ {time_start: @time}
167
+ ]
168
+ expect{ ActsAsBookable::TimeUtils.subintervals(1) }.to raise_error ArgumentError
169
+ intervals = [
170
+ {time_start: @time, time_end: @time + 1.hour},
171
+ {time_end: @time}
172
+ ]
173
+ expect{ ActsAsBookable::TimeUtils.subintervals(1) }.to raise_error ArgumentError
174
+ end
175
+
176
+ it 'returns ArgumentError if time_start or time_end is not a Time or Date' do
177
+ intervals = [
178
+ {time_start: @time, time_end: 1}
179
+ ]
180
+ expect{ ActsAsBookable::TimeUtils.subintervals(1) }.to raise_error ArgumentError
181
+ intervals = [
182
+ {time_start: 2, time_end: @time + 1.hour}
183
+ ]
184
+ expect{ ActsAsBookable::TimeUtils.subintervals(1) }.to raise_error ArgumentError
185
+ end
186
+
187
+ it 'returns empty array if input is an empty array' do
188
+ expect(ActsAsBookable::TimeUtils.subintervals([])).to eq []
189
+ end
190
+
191
+ # |----|
192
+ # =>
193
+ # |----|
194
+ it 'returns a copy of the same interval if input is a single interval' do
195
+ intervals = [
196
+ {time_start: @time, time_end: @time + 1.hour}
197
+ ]
198
+ subintervals = ActsAsBookable::TimeUtils.subintervals(intervals)
199
+ expect(subintervals.length).to eq 1
200
+ expect(subintervals[0][:time_start]).to eq intervals[0][:time_start]
201
+ expect(subintervals[0][:time_end]).to eq intervals[0][:time_end]
202
+ end
203
+
204
+ # |----| |----| |----|
205
+ # =>
206
+ # |----| |----| |----|
207
+ it 'returns a copy of the same intervals if they are all separated' do
208
+ intervals = [
209
+ {time_start: @time, time_end: @time + 1.hour},
210
+ {time_start: @time + 2.hours, time_end: @time + 3.hours},
211
+ {time_start: @time + 4.hours, time_end: @time + 5.hours}
212
+ ]
213
+ subintervals = ActsAsBookable::TimeUtils.subintervals(intervals)
214
+ expect(subintervals.length).to eq 3
215
+ (0..2).each do |i|
216
+ expect(subintervals[i][:time_start]).to eq intervals[i][:time_start]
217
+ expect(subintervals[i][:time_end]).to eq intervals[i][:time_end]
218
+ end
219
+ end
220
+
221
+ # |----|
222
+ # |----|
223
+ # |----|
224
+ # =>
225
+ # |----|
226
+ # |----|
227
+ # |----|
228
+ it 'returns the sub-intervals sorted' do
229
+ time0 = @time
230
+ time1 = @time + 1.hour
231
+ time2 = @time + 2.hours
232
+ time3 = @time + 3.hours
233
+ time4 = @time + 4.hours
234
+ time5 = @time + 5.hours
235
+ time6 = @time + 6.hours
236
+
237
+ intervals = [
238
+ {time_start: time4, time_end: time5},
239
+ {time_start: time2, time_end: time3},
240
+ {time_start: time0, time_end: time1}
241
+ ]
242
+ subintervals = ActsAsBookable::TimeUtils.subintervals(intervals)
243
+ expect(subintervals.length).to eq 3
244
+ expect(subintervals[0][:time_start]).to eq time0
245
+ expect(subintervals[0][:time_end]).to eq time1
246
+ expect(subintervals[1][:time_start]).to eq time2
247
+ expect(subintervals[1][:time_end]).to eq time3
248
+ expect(subintervals[2][:time_start]).to eq time4
249
+ expect(subintervals[2][:time_end]).to eq time5
250
+ end
251
+
252
+ # |----|
253
+ # |----|
254
+ # |----|
255
+ # =>
256
+ # |----|
257
+ it 'merges intervals if they have same time_start and time_end' do
258
+ intervals = [
259
+ {time_start: @time, time_end: @time + 1.hour},
260
+ {time_start: @time, time_end: @time + 1.hour},
261
+ {time_start: @time, time_end: @time + 1.hour}
262
+ ]
263
+ subintervals = ActsAsBookable::TimeUtils.subintervals(intervals)
264
+ expect(subintervals.length).to eq 1
265
+ expect(subintervals[0][:time_start]).to eq intervals[0][:time_start]
266
+ expect(subintervals[0][:time_end]).to eq intervals[0][:time_end]
267
+ end
268
+
269
+ # |---|
270
+ # |------|
271
+ # =>
272
+ # |---|
273
+ # |--|
274
+ it 'returns two intervals if input is 2 intervals with same time_start and different time_end' do
275
+ time0 = @time
276
+ time1 = @time + 1.hour
277
+ time2 = @time + 2.hours
278
+ intervals = [
279
+ {time_start: time0, time_end: time1},
280
+ {time_start: time0, time_end: time2}
281
+ ]
282
+ subintervals = ActsAsBookable::TimeUtils.subintervals(intervals)
283
+ expect(subintervals.length).to eq 2
284
+ expect(subintervals[0][:time_start]).to eq time0
285
+ expect(subintervals[0][:time_end]).to eq time1
286
+ expect(subintervals[1][:time_start]).to eq time1
287
+ expect(subintervals[1][:time_end]).to eq time2
288
+ end
289
+
290
+ # |------|
291
+ # |---|
292
+ # =>
293
+ # |--|
294
+ # |---|
295
+ it 'returns two intervals if input is 2 intervals with same time_end and different time_start' do
296
+ time0 = @time
297
+ time1 = @time + 1.hour
298
+ time2 = @time + 2.hours
299
+ intervals = [
300
+ {time_start: time0, time_end: time2},
301
+ {time_start: time1, time_end: time2}
302
+ ]
303
+ subintervals = ActsAsBookable::TimeUtils.subintervals(intervals)
304
+ expect(subintervals.length).to eq 2
305
+ expect(subintervals[0][:time_start]).to eq time0
306
+ expect(subintervals[0][:time_end]).to eq time1
307
+ expect(subintervals[1][:time_start]).to eq time1
308
+ expect(subintervals[1][:time_end]).to eq time2
309
+ end
310
+
311
+ # |---------|
312
+ # |---|
313
+ # =>
314
+ # |--|
315
+ # |---|
316
+ # |--|
317
+ it 'returns three intervals if one includes another' do
318
+ time0 = @time
319
+ time1 = @time + 1.hour
320
+ time2 = @time + 2.hours
321
+ time3 = @time + 3.hours
322
+ intervals = [
323
+ {time_start: time0, time_end: time3},
324
+ {time_start: time1, time_end: time2}
325
+ ]
326
+ subintervals = ActsAsBookable::TimeUtils.subintervals(intervals)
327
+ expect(subintervals.length).to eq 3
328
+ expect(subintervals[0][:time_start]).to eq time0
329
+ expect(subintervals[0][:time_end]).to eq time1
330
+ expect(subintervals[1][:time_start]).to eq time1
331
+ expect(subintervals[1][:time_end]).to eq time2
332
+ expect(subintervals[2][:time_start]).to eq time2
333
+ expect(subintervals[2][:time_end]).to eq time3
334
+ end
335
+
336
+ # |---2---|
337
+ # |------4------|
338
+ # |----3------|
339
+ # |----1----|
340
+ # |----8----|
341
+ # =>
342
+ # |-5-|
343
+ # |-9-|
344
+ # |-7-|
345
+ # |--4--|
346
+ # |----9----|
347
+ it 'correctly merges interval attributes' do
348
+ time0 = @time
349
+ time1 = @time + 1.hour
350
+ time2 = @time + 2.hours
351
+ time3 = @time + 3.hours
352
+ time4 = @time + 4.hours
353
+ time5 = @time + 5.hours
354
+ time6 = @time + 6.hours
355
+ intervals = [
356
+ {time_start: time0, time_end: time2, attr: 2},
357
+ {time_start: time1, time_end: time4, attr: 4},
358
+ {time_start: time0, time_end: time3, attr: 3},
359
+ {time_start: time5, time_end: time6, attr: 1},
360
+ {time_start: time5, time_end: time6, attr: 8}
361
+ ]
362
+ subintervals = ActsAsBookable::TimeUtils.subintervals(intervals) do |a,b,op|
363
+ if op == :open
364
+ res = {attr: a[:attr] + b[:attr]}
365
+ end
366
+ if op == :close
367
+ res = {attr: a[:attr] - b[:attr]}
368
+ end
369
+ res
370
+ end
371
+ expect(subintervals.length).to eq 5
372
+ expect(subintervals[0][:time_start]).to eq time0
373
+ expect(subintervals[0][:time_end]).to eq time1
374
+ expect(subintervals[0][:attr]).to eq 5
375
+ expect(subintervals[1][:time_start]).to eq time1
376
+ expect(subintervals[1][:time_end]).to eq time2
377
+ expect(subintervals[1][:attr]).to eq 9
378
+ expect(subintervals[2][:time_start]).to eq time2
379
+ expect(subintervals[2][:time_end]).to eq time3
380
+ expect(subintervals[2][:attr]).to eq 7
381
+ expect(subintervals[3][:time_start]).to eq time3
382
+ expect(subintervals[3][:time_end]).to eq time4
383
+ expect(subintervals[3][:attr]).to eq 4
384
+ expect(subintervals[4][:time_start]).to eq time5
385
+ expect(subintervals[4][:time_end]).to eq time6
386
+ expect(subintervals[4][:attr]).to eq 9
387
+ end
388
+
389
+ # |---2---|
390
+ # |------4------|
391
+ # |----3------|
392
+ # |----1----|
393
+ # |----8----|
394
+ # =>
395
+ # |-5-|
396
+ # |-9-|
397
+ # |-7-|
398
+ # |--4--|
399
+ # |----9----|
400
+ it 'correctly merges interval attributes handling dates and times' do
401
+ time0 = Date.today
402
+ time1 = time0 + 1
403
+ time2 = time0 + 2
404
+ time3 = time0 + 3
405
+ time4 = time0 + 4.days + 1.hours
406
+ time5 = time0 + 5.days + 1.hours
407
+ time6 = time0 + 6.days + 1.hours
408
+ intervals = [
409
+ {time_start: time0, time_end: time2, attr: 2},
410
+ {time_start: time1, time_end: time4, attr: 4},
411
+ {time_start: time0, time_end: time3, attr: 3},
412
+ {time_start: time5, time_end: time6, attr: 1},
413
+ {time_start: time5, time_end: time6, attr: 8}
414
+ ]
415
+ subintervals = ActsAsBookable::TimeUtils.subintervals(intervals) do |a,b,op|
416
+ if op == :open
417
+ res = {attr: a[:attr] + b[:attr]}
418
+ end
419
+ if op == :close
420
+ res = {attr: a[:attr] - b[:attr]}
421
+ end
422
+ res
423
+ end
424
+ expect(subintervals.length).to eq 5
425
+ expect(subintervals[0][:time_start]).to eq time0
426
+ expect(subintervals[0][:time_end]).to eq time1
427
+ expect(subintervals[0][:attr]).to eq 5
428
+ expect(subintervals[1][:time_start]).to eq time1
429
+ expect(subintervals[1][:time_end]).to eq time2
430
+ expect(subintervals[1][:attr]).to eq 9
431
+ expect(subintervals[2][:time_start]).to eq time2
432
+ expect(subintervals[2][:time_end]).to eq time3
433
+ expect(subintervals[2][:attr]).to eq 7
434
+ expect(subintervals[3][:time_start]).to eq time3
435
+ expect(subintervals[3][:time_end]).to eq time4
436
+ expect(subintervals[3][:attr]).to eq 4
437
+ expect(subintervals[4][:time_start]).to eq time5
438
+ expect(subintervals[4][:time_end]).to eq time6
439
+ expect(subintervals[4][:attr]).to eq 9
440
+ end
441
+
442
+ # |---2---|
443
+ # |---4---|
444
+ # |---3---|
445
+ # |---5---|
446
+ # |---1---|
447
+ # |---1---|
448
+ # =>
449
+ # |---6---|
450
+ # |---10---|
451
+ it 'merges 3 intervals partially matching' do
452
+ time0 = @time
453
+ time1 = @time + 1.hour
454
+ time2 = @time + 2.hours
455
+ intervals = [
456
+ {time_start: time0, time_end: time1, attr: 2},
457
+ {time_start: time1, time_end: time2, attr: 4},
458
+ {time_start: time0, time_end: time1, attr: 3},
459
+ {time_start: time1, time_end: time2, attr: 5},
460
+ {time_start: time0, time_end: time1, attr: 1},
461
+ {time_start: time1, time_end: time2, attr: 1}
462
+ ]
463
+ subintervals = ActsAsBookable::TimeUtils.subintervals(intervals) do |a,b,op|
464
+ if op == :open
465
+ res = {attr: a[:attr] + b[:attr]}
466
+ end
467
+ if op == :close
468
+ res = {attr: a[:attr] - b[:attr]}
469
+ end
470
+ res
471
+ end
472
+ expect(subintervals.length).to eq 2
473
+ expect(subintervals[0][:time_start]).to eq time0
474
+ expect(subintervals[0][:time_end]).to eq time1
475
+ expect(subintervals[0][:attr]).to eq 6
476
+ expect(subintervals[1][:time_start]).to eq time1
477
+ expect(subintervals[1][:time_end]).to eq time2
478
+ expect(subintervals[1][:attr]).to eq 10
479
+ end
480
+
481
+ # |---2----|
482
+ # |----4---|
483
+ # |---3----|
484
+ # |----5---|
485
+ # |---1----|
486
+ # |----1---|
487
+ # =>
488
+ # |-6-|
489
+ # |-16-|
490
+ # |-10-|
491
+ it 'merges and split 3 intervals partially matching' do
492
+ time0 = @time
493
+ time1 = @time + 1.hour
494
+ time2 = @time + 2.hours
495
+ time3 = @time + 3.hours
496
+ intervals = [
497
+ {time_start: time0, time_end: time2, attr: 2},
498
+ {time_start: time1, time_end: time3, attr: 4},
499
+ {time_start: time0, time_end: time2, attr: 3},
500
+ {time_start: time1, time_end: time3, attr: 5},
501
+ {time_start: time0, time_end: time2, attr: 1},
502
+ {time_start: time1, time_end: time3, attr: 1}
503
+ ]
504
+ subintervals = ActsAsBookable::TimeUtils.subintervals(intervals) do |a,b,op|
505
+ if op == :open
506
+ res = {attr: a[:attr] + b[:attr]}
507
+ end
508
+ if op == :close
509
+ res = {attr: a[:attr] - b[:attr]}
510
+ end
511
+ res
512
+ end
513
+ expect(subintervals.length).to eq 3
514
+ expect(subintervals[0][:time_start]).to eq time0
515
+ expect(subintervals[0][:time_end]).to eq time1
516
+ expect(subintervals[0][:attr]).to eq 6
517
+ expect(subintervals[1][:time_start]).to eq time1
518
+ expect(subintervals[1][:time_end]).to eq time2
519
+ expect(subintervals[1][:attr]).to eq 16
520
+ expect(subintervals[2][:time_start]).to eq time2
521
+ expect(subintervals[2][:time_end]).to eq time3
522
+ expect(subintervals[2][:attr]).to eq 10
523
+ end
524
+ end
525
+ end
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :bookable, class: 'Bookable' do
3
+ name 'Bookable name'
4
+ capacity 4
5
+ schedule IceCube::Schedule.new
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :booker, class: 'Booker' do
3
+ name 'Booker name'
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ FactoryGirl.define do
2
+ factory :room, class: 'Room' do
3
+ name 'Room name'
4
+ capacity 4
5
+ schedule {
6
+ schedule = IceCube::Schedule.new(Date.today, duration: 1.day)
7
+ schedule.add_recurrence_rule IceCube::Rule.daily
8
+ schedule
9
+ }
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ class Bookable < ActiveRecord::Base
2
+ acts_as_bookable
3
+ end
@@ -0,0 +1,3 @@
1
+ class Booker < ActiveRecord::Base
2
+ acts_as_booker
3
+ end
@@ -0,0 +1,3 @@
1
+ class Event < ActiveRecord::Base
2
+ acts_as_bookable preset: :event
3
+ end
@@ -0,0 +1,2 @@
1
+ class Generic < ActiveRecord::Base
2
+ end
@@ -0,0 +1,2 @@
1
+ class NotBooker < ActiveRecord::Base
2
+ end
@@ -0,0 +1,3 @@
1
+ class Room < ActiveRecord::Base
2
+ acts_as_bookable preset: :room
3
+ end
@@ -0,0 +1,3 @@
1
+ class Show < ActiveRecord::Base
2
+ acts_as_bookable preset: :show
3
+ end
@@ -0,0 +1,2 @@
1
+ class Unbookable < ActiveRecord::Base
2
+ end
@@ -0,0 +1,17 @@
1
+ sqlite3:
2
+ adapter: sqlite3
3
+ database: ':memory:'
4
+
5
+ mysql:
6
+ adapter: mysql2
7
+ host: localhost
8
+ username: root
9
+ database: acts_as_bookable
10
+ charset: utf8
11
+
12
+ postgresql:
13
+ adapter: postgresql
14
+ hostname: localhost
15
+ username: postgres
16
+ database: acts_as_bookable
17
+ encoding: utf8
@@ -0,0 +1,51 @@
1
+ ActiveRecord::Schema.define version: 0 do
2
+ create_table :acts_as_bookable_bookings, force: true do |t|
3
+ t.references :bookable, polymorphic: true
4
+ t.references :booker, polymorphic: true
5
+ t.column :amount, :integer
6
+ t.column :schedule, :text
7
+ t.column :time_start, :datetime
8
+ t.column :time_end, :datetime
9
+ t.column :time, :datetime
10
+ t.datetime :created_at
11
+ end
12
+
13
+ create_table :bookables, force: true do |t|
14
+ t.column :name, :string
15
+ t.column :schedule, :text
16
+ t.column :capacity, :integer
17
+ end
18
+
19
+ create_table :rooms, force: true do |t|
20
+ t.column :name, :string
21
+ t.column :schedule, :text
22
+ t.column :capacity, :integer
23
+ end
24
+
25
+ create_table :events, force: true do |t|
26
+ t.column :name, :string
27
+ t.column :capacity, :integer
28
+ end
29
+
30
+ create_table :shows, force: true do |t|
31
+ t.column :name, :string
32
+ t.column :schedule, :text
33
+ t.column :capacity, :integer
34
+ end
35
+
36
+ create_table :unbookables, force: true do |t|
37
+ t.column :name, :string
38
+ end
39
+
40
+ create_table :not_bookers, force: true do |t|
41
+ t.column :name, :string
42
+ end
43
+
44
+ create_table :generics, force: true do |t|
45
+ t.column :name, :string
46
+ end
47
+
48
+ create_table :bookers, force: true do |t|
49
+ t.column :name, :string
50
+ end
51
+ end
@@ -0,0 +1,26 @@
1
+ begin
2
+ require 'pry-nav'
3
+ rescue LoadError
4
+ end
5
+ $LOAD_PATH << '.' unless $LOAD_PATH.include?('.')
6
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
7
+ require 'logger'
8
+
9
+ require File.expand_path('../../lib/acts_as_bookable', __FILE__)
10
+ I18n.enforce_available_locales = true
11
+ require 'rails'
12
+ require 'barrier'
13
+ require 'database_cleaner'
14
+ require 'factory_girl_rails'
15
+ require 'awesome_print'
16
+
17
+ ENGINE_RAILS_ROOT=File.join(File.dirname(__FILE__), '../')
18
+ Dir[File.join(ENGINE_RAILS_ROOT, "spec/factories/**/*.rb")].each {|f| require f }
19
+
20
+ Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
21
+
22
+ I18n.load_path << File.expand_path("../../config/locales/en.yml", __FILE__)
23
+
24
+ RSpec.configure do |config|
25
+ config.raise_errors_for_deprecations!
26
+ end