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
data/README.md ADDED
@@ -0,0 +1,473 @@
1
+ # ActsAsBookable
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/acts_as_bookable.svg)](http://badge.fury.io/rb/acts_as_bookable)
4
+ [![Build Status](https://secure.travis-ci.org/tandusrl/acts_as_bookable.png)](http://travis-ci.org/tandusrl/acts_as_bookable)
5
+ [![Code Climate](https://codeclimate.com/github/tandusrl/acts_as_bookable.png)](https://codeclimate.com/github/tandusrl/acts_as_bookable)
6
+ [![Inline docs](http://inch-ci.org/github/tandusrl/acts_as_bookable.png)](http://inch-ci.org/github/tandusrl/acts_as_bookable)
7
+
8
+ ActsAsBookable allows resources to be booked by users. It:
9
+
10
+ * Is a MVC solution based on Rails engines
11
+ * Is designed to cover many use cases (hotels bookings, restaurant reservations, shows...)
12
+ * Allows to define bookable availabilities with recurring times and exceptions (based on ice_cube)
13
+
14
+ ## Getting started
15
+
16
+ ### Installation
17
+
18
+ #### Include the gem
19
+
20
+ ActsAsBookable works with ActiveRecord 3.2 onwards. You can add it to your Gemfile with:
21
+
22
+ ```ruby
23
+ gem 'acts_as_bookable'
24
+ ```
25
+
26
+ run `bundle install` to install it.
27
+
28
+ #### Install and run migrations
29
+
30
+ ```bash
31
+ bundle exec rake acts_as_bookable_engine:install:migrations
32
+ bundle exec rake db:migrate
33
+ ```
34
+
35
+ ### Bookables, Bookers and Bookings
36
+
37
+ To set-up a **Bookable** model, use `acts_as_bookable`. A Bookable model is enabled to accept bookings.
38
+
39
+ ```ruby
40
+ class Room < ActiveRecord::Base
41
+ acts_as_bookable
42
+ end
43
+ ```
44
+
45
+ To set-up a **Booker** model, use `acts_as_booker`. Only Bookers can create bookings.
46
+
47
+ ```ruby
48
+ class User < ActiveRecord::Base
49
+ acts_as_booker
50
+ end
51
+ ```
52
+
53
+ From this time on, a User can book a Room with
54
+
55
+ ```ruby
56
+ @user.book! @room
57
+ ```
58
+
59
+ Or a Room can accept a booking from a User with
60
+
61
+ ```ruby
62
+ @room.be_booked! @user
63
+ ```
64
+
65
+ The functions above perform the same operation: they create and save a new **Booking** that has relations with the **Booker** and the **Bookable**.
66
+
67
+ Since only **Bookers** can book **Bookables**, you must configure both the models. You can even have two or more models configured as **Bookable**, as well as two or more models configured as **Booker**.
68
+
69
+ You can access bookings both from the Bookable and the Booker
70
+
71
+ ```ruby
72
+ @room.bookings # return all bookings created on this room
73
+ @user.bookings # return all bookings made by this user
74
+ ```
75
+
76
+ ## Configuring ActsAsBookable options
77
+
78
+ There are a number available options to make your models behave differently. They are all configurable in the Bookable model, passing a hash to `acts_as_bookable`
79
+
80
+ Available options (with values) are:
81
+
82
+ * `:time_type`: Specifies how the Bookable must be booked in terms of time. Allowed values are:
83
+ * `:none`
84
+ * `:fixed`
85
+ * `:range`
86
+ * `:capacity_type`: Specifies how the `amount` of a booking (e.g. number of people of a restaurant reservation) affects the future availability of the bookable. Allowed values are:
87
+ * `:none`
88
+ * `:open`
89
+ * `:closed`
90
+ * `:bookable_across_occurrences`: Allows or denies the possibility to book across different occurrences of the availability schedule of the bookable (further explanation below)
91
+
92
+ > WARNING - Some of the options above need migrations. They are explained in the sections below
93
+
94
+ ### No constraints
95
+
96
+ The model accepts booking without any constraint. This means every booker can create an infinite number of bookings on it and no capacity or time checks are performed.
97
+
98
+ Creating a booking on this model means booking it forever and without care for other existing bookings. In other words, the time and the number of bookings do not affect the availability of this bookable. (e.g. pre-ordering a product that will be released soon)
99
+
100
+ **Configuration**
101
+
102
+ ```ruby
103
+ class Product < ActiveRecord::Base
104
+ acts_as_bookable
105
+ end
106
+ ```
107
+
108
+ **Creating a new bookable**
109
+
110
+ ```ruby
111
+ # Creating a new bookable without constraints does not require any additional attribute
112
+ @product = Product.create!(...)
113
+ ```
114
+
115
+ **Booking**
116
+
117
+ ```ruby
118
+ # Booking a model without constraints does not require any additional option
119
+ @user.book! @product
120
+ ```
121
+
122
+ ### Time constraints
123
+
124
+ The option `time_type` may be used to set a constraint over the booking time.
125
+
126
+ #### No time constraints - `time_type: :none`
127
+
128
+ The model is bookable without time constraints.
129
+
130
+
131
+ ```ruby
132
+ class Product < ActiveRecord::Base
133
+ # As `time_type: :none` is a default, you can omit it. It's shown here for explanation purposes
134
+ acts_as_bookable time_type: :none
135
+ end
136
+ ```
137
+
138
+ #### Fixed time constraint - `time_type: :fixed`
139
+
140
+ > WARNING - **migration needed!** - with this option the model must have an attribute `schedule: :text`
141
+
142
+ The model accepts bookings that specify a fixed `:time`, and the availability is affected only for that time. (e.g. a show in a movie theater)
143
+
144
+ **Configuration**
145
+
146
+ ```ruby
147
+ class Show < ActiveRecord::Base
148
+ acts_as_bookable time_type: :fixed
149
+ end
150
+ ```
151
+
152
+ **Creating a new bookable**
153
+
154
+ Each instance of the model must define its availability in terms of time with an [IceCube Schedule](https://github.com/seejohnrun/ice_cube)
155
+
156
+ ```ruby
157
+ @show = Show.new(...)
158
+ @show.schedule = IceCube::Schedule.new
159
+ # This show is available every day at 6PM and 10PM
160
+ @show.schedule.add_recurrence_rule IceCube::Rule.daily.hour_of_day(18,22)
161
+ @show.save!
162
+ ```
163
+
164
+ **Booking**
165
+
166
+ ```ruby
167
+ time_ok = Date.today + 18.hours # Today at 6PM
168
+ time_wrong = Date.today + 19.hours # Today at 7PM
169
+ # Booking a model with `time_type: :fixed` requires a `:time` option
170
+ @user1.book! @show, time: time_ok # OK
171
+ @user2.book! @show, time: time_wrong # raise ActsAsBookable::AvailabilityError
172
+ ```
173
+
174
+ #### Time range constraint - `time_type: :range`
175
+
176
+ > WARNING - **migration needed!** - with this option the model must have an attribute `schedule: :text`
177
+
178
+ The model accepts bookings that specify a `:time_start` and a `:time_end`. After a booking is created, the bookable availability is affected only within that range. (e.g. a meeting room)
179
+
180
+ **Configuration**
181
+
182
+ ```ruby
183
+ class MeetingRoom < ActiveRecord::Base
184
+ acts_as_bookable time_type: :range
185
+ end
186
+ ```
187
+
188
+ **Creating a new bookable**
189
+
190
+ Each instance of the model must define its availability in terms of time with an [IceCube Schedule](https://github.com/seejohnrun/ice_cube). Although it's not strictly required, it's strongly suggested to create a schedule with a `:duration`, unless you know exactly what you are doing.
191
+
192
+ ```ruby
193
+ @meeting_room = MeetingRoom.new(...)
194
+ # The schedule starts now and each occurrence is 10 hours long
195
+ @meeting_room.schedule = IceCube::Schedule.new(Time.now, duration: 10.hours)
196
+ # This meeting_room is available on Mondays starting from 8 AM
197
+ @meeting_room.schedule.add_recurrence_rule IceCube::Rule.weekly.day(:monday).hour_of_day(8)
198
+ @meeting_room.save!
199
+ ```
200
+
201
+ **Booking**
202
+
203
+ ```ruby
204
+ # Next Monday from 9AM to 11AM
205
+ from_ok = Date.today.next_week + 9.hours
206
+ to_ok = from_ok + 2.hours
207
+ # Next Tuesday from 9AM to 11AM
208
+ from_wrong = Date.today.next_week + 1.day + 9.hours
209
+ to_wrong = from_wrong + 2.hours
210
+
211
+ # Booking a model with `time_type: :range` requires `:time_start` and `:time_end`
212
+ @user1.book! @meeting_room, time_start: from_ok, time_end: to_ok # OK
213
+ @user2.book! @meeting_room, time_start: from_wrong, time_end: to_wrong # raise ActsAsBookable::AvailabilityError
214
+ ```
215
+
216
+ ### Bookability across occurrences
217
+
218
+ Combined with `time_type: :range`, the option `bookable_across_occurrences` allows for creating bookings that start in an occurrence of the schedule and end in another occurrence. By default, it's set to `false`.
219
+
220
+ Let's use two examples to better explain the difference
221
+
222
+ #### Not bookable across occurrences **`bookable_across_occurrences: false`**
223
+
224
+ The model accepts only bookings that start and end within the same occurrence (e.g. a meeting room)
225
+
226
+ **Configuration**
227
+
228
+ ```ruby
229
+ class MeetingRoom < ActiveRecord::Base
230
+ # bookable_across_occurrences is always combined with time_type: :range
231
+ # As `bookable_across_occurrences: false` is a default, you can omit it. It's shown here for explanation purposes
232
+ acts_as_bookable time_type: :range, bookable_across_occurrences: false
233
+ end
234
+ ```
235
+
236
+ **Creating a new bookable**
237
+
238
+ ```ruby
239
+ @meeting_room = MeetingRoom.new(...)
240
+ # The schedule starts now and each occurrence is 4 hours long
241
+ @meeting_room.schedule = IceCube::Schedule.new(Time.now, duration: 4.hours)
242
+ # This meeting_room is available everyday, from 9AM to 13AM and from 2PM to 6PM
243
+ @meeting_room.schedule.add_recurrence_rule IceCube::Rule.daily.hour_of_day(9,14)
244
+ @meeting_room.save!
245
+ ```
246
+
247
+ **Booking**
248
+
249
+ ```ruby
250
+ # Next Monday from 9AM to 11AM
251
+ from_ok = Date.today.next_week + 9.hours
252
+ to_ok = from_ok + 2.hours
253
+
254
+ # Next Monday from 11AM to 6PM
255
+ from_wrong = Date.today.next_week + 11.hours
256
+ to_wrong = Date.today.next_week + 18.hours
257
+
258
+ # OK - time_start and time_end belong to the same occurrence
259
+ @user1.book! @meeting_room, time_start: from_ok, time_end: to_ok
260
+
261
+ # raise ActsAsBookable::AvailabilityError - both time_start and time_end are inside the schedule, but they belong to different occurrences
262
+ @user2.book! @meeting_room, time_start: from_wrong, time_end: to_wrong
263
+ ```
264
+
265
+ #### Bookable across occurrences **`bookable_across_occurrences: true`**
266
+
267
+ The model may accept bookings that start and end in different occurrences (e.g. a hotel room)
268
+
269
+ **Configuration**
270
+
271
+ ```ruby
272
+ class Room < ActiveRecord::Base
273
+ # bookable_across_occurrences is always combined with time_type: :range
274
+ acts_as_bookable time_type: :range, bookable_across_occurrences: true
275
+ end
276
+ ```
277
+
278
+ **Creating a new bookable**
279
+
280
+ ```ruby
281
+ @room = Room.new(...)
282
+ # The schedule starts today and each occurrence is 1 day long
283
+ @room.schedule = IceCube::Schedule.new(Date.today, duration: 1.day)
284
+ # This room is available every week, on weekends
285
+ @room.schedule.add_recurrence_rule IceCube::Rule.weekly.day(:friday,:saturday,:sunday)
286
+ @room.save!
287
+ ```
288
+
289
+ **Booking**
290
+
291
+ ```ruby
292
+ # check-in Friday, check-out Sunday
293
+ check_in_ok = Date.today.next_week + 4.days
294
+ check_out_ok = check_in_ok + 2.days
295
+
296
+ # check-in Tuesday, check-out Sunday
297
+ check_in_wrong = Date.today.next_week + 4.days
298
+ check_out_wrong = check_in_wrong + 3.days
299
+
300
+ # OK - time_start and time_end belong to different occurrences
301
+ @user1.book! @room, time_start: check_in_ok, time_end: check_out_ok
302
+
303
+ # raise ActsAsBookable::AvailabilityError - while time_end belongs to an occurrence, time_begin doesn't belong to any occurrence of the schedule
304
+ @user2.book! @room, time_start: check_in_wrong, time_end: check_out_wrong
305
+ ```
306
+
307
+ ### Capacity constraints
308
+
309
+ The option `capacity_type` may be used to set a constraint over the `amount` attribute of the booking
310
+
311
+ #### No capacity constraints - `capacity_type: :none`
312
+
313
+ The model is bookable without capacity constraints.
314
+
315
+ ```ruby
316
+ class Product < ActiveRecord::Base
317
+ # As `capacity_type: :none` is a default, you can omit it. It's shown here for explanation purposes
318
+ acts_as_bookable capacity_type: :none
319
+ end
320
+ ```
321
+
322
+ #### Open capacity - `capacity_type: :open`
323
+
324
+ > WARNING - **migration needed!** - with this option the model must have an attribute `capacity: :integer`
325
+
326
+ The model is bookable until its `capacity` is reached. (e.g. an event)
327
+
328
+ **Configuration**
329
+
330
+ ```ruby
331
+ class Event < ActiveRecord::Base
332
+ acts_as_bookable capacity_type: :open
333
+ end
334
+ ```
335
+
336
+ **Creating a new bookable**
337
+
338
+ Each instance of the model must define its capacity.
339
+
340
+ ```ruby
341
+ @event = Event.new(...)
342
+ @event.capacity = 30 # This event accepts 30 people
343
+ @event.save!
344
+ ```
345
+
346
+ **Booking**
347
+
348
+ ```ruby
349
+ # Booking a model with `capacity_type: :open` requires `:amount`
350
+ @user1.book! @event, amount: 5 # booking the event for 5 people, OK
351
+ @user2.book! @event, amount: 20 # booking the event for other 20 people, OK
352
+ @user3.book! @event, amount: 10 # overbooking! raise ActsAsBookable::AvailabilityError
353
+ ```
354
+
355
+ #### Closed capacity - `capacity_type: :closed`
356
+
357
+ > WARNING - **migration needed!** - with this option the model must have an attribute `capacity: :integer`
358
+
359
+ Similar to open capacity, but after the model is booked, it's no more available, no matter if capacity has not been reached. (e.g. a private room)
360
+
361
+ **Configuration**
362
+
363
+ ```ruby
364
+ class PrivateRoom < ActiveRecord::Base
365
+ acts_as_bookable capacity_type: :closed
366
+ end
367
+ ```
368
+
369
+ **Creating a new bookable**
370
+
371
+ Each instance of the model must define its capacity.
372
+
373
+ ```ruby
374
+ @private_room = PrivateRoom.new(...)
375
+ @private_room.capacity = 30 # This private_room accepts 30 people
376
+ @private_room.save!
377
+ ```
378
+
379
+ **Booking**
380
+
381
+ ```ruby
382
+ # Booking a model with `capacity_type: :closed` requires `:amount`
383
+ @user1.book! @private_room, amount: 35 # overbooking! raise ActsAsBookable::AvailabilityError
384
+ @user2.book! @private_room, amount: 5 # booking for 5 people, OK
385
+ @user3.book! @private_room, amount: 5 # not available! Although the room can still hosts (potentially) 25 people, it has already been booked. raise ActsAsBookable::AvailabilityError
386
+
387
+ ```
388
+
389
+ ### Mixing options
390
+
391
+ All the options may be mixed together to achieve different goals.
392
+
393
+ Adding an option means adding a constraint to the effectiveness of a booking on a bookable.
394
+
395
+ ### Presets
396
+
397
+ Some combinations of common options are provided as built-in presets. They are activated using just the option `:preset`
398
+
399
+ As for now only these presets are provided, others are coming soon:
400
+
401
+ * `:room`
402
+
403
+ #### Room - `preset: :room`
404
+
405
+ > WARNING - **migration needed!** - with this option the model must have an attribute `capacity: :integer` and an attribute `schedule: :text`
406
+
407
+ An hotel room has the following costraints:
408
+
409
+ 1. It accepts bookings that specify a **range of time** (i.e. check-in and check-out)
410
+ 2. It has a **capacity** that cannot be exceeded
411
+ 3. After it has been booked, it becomes unavailable for the given range of time, even though its capacity has not been reached.
412
+ 4. Its availability is expressed in terms of opening days (a schedule of 1 day long occurrences), but a single booking may cover more than one day (e.g. a weekend)
413
+
414
+ **Configuration**:
415
+
416
+ ```ruby
417
+ class Room < ActiveRecord::Base
418
+ acts_as_bookable preset: :room
419
+ end
420
+ ```
421
+
422
+ Which is equivalent to
423
+
424
+ ```ruby
425
+ class Room < ActiveRecord::Base
426
+ acts_as_bookable time_type: :range,
427
+ capacity_type: :closed,
428
+ bookable_across_occurrences: true
429
+ end
430
+ ```
431
+
432
+
433
+ **Booking:**
434
+
435
+ ```ruby
436
+ # A @user books a @room for 2 people. Check-in is today and check-out is tomorrow.
437
+ @user.book! @room, time_start: Date.today, time_end: Date.tomorrow, amount: 2
438
+ ```
439
+
440
+ ## FYI
441
+
442
+ ### Hey... Why not just an initializer?
443
+
444
+ We decided not to provide an initializer to configure bookings because one of the goals of this gem is to allow for different kinds of booking inside the same application.
445
+
446
+ This is achieved delegating the responsability of deciding "how a booking should be created" to the Bookable itself. In this way, different configurations of `acts_as_bookable` inside a model bring to different ways of creating and managing bookings for ***that*** *(and only that)* model.
447
+
448
+ ### License
449
+
450
+ Copyright 2016 Tandù srl
451
+
452
+ Permission is hereby granted, free of charge, to any person obtaining
453
+ a copy of this software and associated documentation files (the
454
+ "Software"), to deal in the Software without restriction, including
455
+ without limitation the rights to use, copy, modify, merge, publish,
456
+ distribute, sublicense, and/or sell copies of the Software, and to
457
+ permit persons to whom the Software is furnished to do so, subject to
458
+ the following conditions:
459
+
460
+ The above copyright notice and this permission notice shall be
461
+ included in all copies or substantial portions of the Software.
462
+
463
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
464
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
465
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
466
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
467
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
468
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
469
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
470
+
471
+ ### Acknowledgements
472
+
473
+ To speed-up the initialization process of this project, the structure of this repository was strongly influenced by [ActsAsTaggableOn](https://github.com/mbleigh/acts-as-taggable-on) by Michael Bleigh and Intridea Inc.
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ desc 'Default: run specs'
5
+ task default: :spec
6
+
7
+ desc 'Copy sample spec database.yml over if not exists'
8
+ task :copy_db_config do
9
+ cp 'spec/internal/config/database.yml.sample', 'spec/internal/config/database.yml'
10
+ end
11
+
12
+ task spec: [:copy_db_config]
13
+
14
+ require 'rspec/core/rake_task'
15
+ RSpec::Core::RakeTask.new do |t|
16
+ t.pattern = 'spec/**/*_spec.rb'
17
+ end
18
+
19
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,41 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ # Maintain your gem's version:
5
+ require "acts_as_bookable/version"
6
+
7
+ # Describe your gem and declare its dependencies:
8
+ Gem::Specification.new do |gem|
9
+ gem.name = "acts_as_bookable"
10
+ gem.version = ActsAsBookable::VERSION
11
+ gem.authors = ["Chosko"]
12
+ gem.email = ["ruben.caliandro@gmail.com"]
13
+ gem.homepage = "https://github.com/tandusrl/acts_as_bookable"
14
+ gem.summary = "The reservation engine for Rails applications that allows resources to be booked"
15
+ gem.description = "The reservation engine for Rails applications that allows resources to be booked"
16
+ gem.licenses = ["MIT"]
17
+ gem.platform = Gem::Platform::RUBY
18
+
19
+ gem.files = `git ls-files`.split($/)
20
+ gem.test_files = gem.files.grep(%r{^spec/})
21
+
22
+ gem.require_paths = ['lib']
23
+ gem.required_ruby_version = '>= 2.0.0'
24
+
25
+ if File.exist?('UPGRADING.md')
26
+ gem.post_install_message = File.read('UPGRADING.md')
27
+ end
28
+
29
+ gem.add_dependency 'ice_cube_chosko', '~> 0.1.0'
30
+ gem.add_runtime_dependency 'activerecord', ['>= 3.2', '< 5']
31
+
32
+ gem.add_development_dependency 'sqlite3'
33
+ gem.add_development_dependency 'mysql2', '~> 0.3.7'
34
+ gem.add_development_dependency 'pg'
35
+ gem.add_development_dependency 'rspec-rails'
36
+ gem.add_development_dependency 'rspec'
37
+ gem.add_development_dependency 'factory_girl_rails'
38
+ gem.add_development_dependency 'barrier'
39
+ gem.add_development_dependency 'database_cleaner'
40
+ gem.add_development_dependency 'awesome_print'
41
+ end
File without changes
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module ActsAsBookable
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ActsAsBookable
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>ActsAsBookable</title>
5
+ <%= stylesheet_link_tag "acts_as_bookable/application", media: "all" %>
6
+ <%= javascript_include_tag "acts_as_bookable/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
data/bin/rails ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
3
+
4
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
5
+ ENGINE_PATH = File.expand_path('../../lib/acts_as_bookable/engine', __FILE__)
6
+
7
+ # Set up gems listed in the Gemfile.
8
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
9
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
10
+
11
+ require 'rails/all'
12
+ require 'rails/engine/commands'
@@ -0,0 +1,12 @@
1
+ en:
2
+ acts_as_bookable:
3
+ errors:
4
+ messages:
5
+ booking:
6
+ bookable_must_be_bookable: "cannot book a %{model} as it\'s not bookable"
7
+ booker_must_be_booker: "a %{model} cannot book a resource, because %{model} is not a booker"
8
+ availability:
9
+ amount_gt_capacity: "amount cannot be greater than %{model} capacity"
10
+ already_booked: "the %{model} is fully booked"
11
+ unavailable_interval: "the %{model} is not available from %{time_start} to %{time_end}"
12
+ unavailable_time: "the %{model} is not available at %{time}"
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ ActsAsBookable::Engine.routes.draw do
2
+ end
@@ -0,0 +1,14 @@
1
+ class CreateActsAsBookableBookings < ActiveRecord::Migration
2
+ def change
3
+ create_table :acts_as_bookable_bookings, force: :cascade do |t|
4
+ t.references :bookable, polymorphic: true
5
+ t.references :booker, polymorphic: true
6
+ t.column :amount, :integer
7
+ t.column :schedule, :text
8
+ t.column :time_start, :datetime
9
+ t.column :time_end, :datetime
10
+ t.column :time, :datetime
11
+ t.datetime :created_at
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", :github => "rails/rails", :branch => "3-2-stable"
6
+
7
+ group :local_development do
8
+ gem "guard"
9
+ gem "guard-rspec"
10
+ gem "appraisal"
11
+ gem "rake"
12
+ gem "byebug", :platform => :mri_21
13
+ gem "pry-nav"
14
+ end
15
+
16
+ gemspec :path => "../"
@@ -0,0 +1,16 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", :github => "rails/rails", :branch => "4-0-stable"
6
+
7
+ group :local_development do
8
+ gem "guard"
9
+ gem "guard-rspec"
10
+ gem "appraisal"
11
+ gem "rake"
12
+ gem "byebug", :platform => :mri_21
13
+ gem "pry-nav"
14
+ end
15
+
16
+ gemspec :path => "../"