forked from AdaGold/hotel
-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pipes - Kate Evans-Spitzer - Hotel #48
Open
Guribot
wants to merge
132
commits into
Ada-C8:master
Choose a base branch
from
Guribot:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
132 commits
Select commit
Hold shift + click to select a range
bdc1eab
add rakefile
Guribot 0f80e82
create files for classes & specs
Guribot 5b5b85b
comments basic method/variable names
Guribot 936ce00
add files to spec_helper require list
Guribot ddbe4ed
add initialize method
Guribot 6cdb1ff
initialize
Guribot 387c256
add #all_rooms
Guribot b150d60
add #initialize
Guribot 6c38487
pseudocode remaining methods
Guribot 43d7f68
add room_num parameter to initialize method
Guribot 0f42fca
pseudocode #includes_dates? method
Guribot eeae8f8
test for @total_cost
Guribot 69d7740
parses checkin & checkout into dates array
Guribot 96ea3df
fixed broken it block
Guribot 25c2edc
implement ::validate method
Guribot 77c88ac
implement ::range_to method
Guribot 3e6c923
implement ::range_with method
Guribot 8e8afd8
add room_num parameter to initialize
Guribot e64ba26
implement #initialize and @dates
Guribot c8d8597
skip future tests
Guribot 2382fa0
implement @id and #create_id
Guribot ce2065b
add Hotel ROOM_COST constant of 200, pass as parameter to Room.new
Guribot facc88f
move comments
Guribot 46be315
unskip test
Guribot 41b1d0f
implement #room method
Guribot 5b016f4
implement @total_cost and #get_cost
Guribot 8edfa6c
Hotel module requires classes
Guribot 6bc2383
remove to_do comment
Guribot 1b55142
passes Room into Reservation.initialize instead of room number
Guribot 09e964c
implement #make_reservation
Guribot e2ff5fd
moved Wave 1 TODO comment from hotel to reservation spec
Guribot 67306ab
implement #find_available_rooms
Guribot c79af96
require date
Guribot d37bc74
implement #view_reservations method
Guribot 6a51556
create class AlreadyBookedError
Guribot 48475b0
add Wave 2 comments
Guribot 7805a12
implement #includes_dates? method
Guribot e0e27b4
#view_avail method checks reservations
Guribot 3058ab5
renamed already_booked_error to no_room_error
Guribot 51d3893
implement NoRoomError, tests for availability
Guribot db06bfd
#all_rooms returns list of Rooms, not numbers
Guribot b2d1a36
rubocop style guide tweaks
Guribot ba9c895
#make_reservation returns reservation, pseudocode for #make_block
Guribot 2864b1b
add #initialize for Block class, implement basic #make_block method
Guribot e4d8791
Hotel.create_block will not take booked room
Guribot 1de2b4b
dry out #make_reservation tests
Guribot 492cfc0
added 'block = false' argument to #make_reservation, #find_available_…
Guribot 53439e8
add leading B or R to block & reservation IDs
Guribot 67f6684
pseudocode and skeleton tests for adding block functionality to #find…
Guribot e9b1155
fix date issue in @id and #create_id
Guribot ed39e6a
moved Reservation.includes_dates? functionality into DateRange.overlap?
Guribot ca39406
add reader methods for dates
Guribot 33dce75
#find_available_rooms raises RangeError if passed incongruent dates &…
Guribot c40839c
add block functionality to #make_reservation
Guribot 8eba6cf
add #includes_dates?
Guribot eac2592
renamed no_room_error to exceptions
Guribot 4951fdd
streamlined #block and #room
Guribot f04af7e
add TODO
Guribot 0532edf
refactored #range_to and #range_with to be more DRY
Guribot 573dff1
change RangeError to InvalidDatesError
Guribot e45f56c
rubocop style guide tweaks
Guribot f70d6e0
add TODO: implement block discount
Guribot 626f97a
rubocop style guide tweaks
Guribot 9ffeef1
added comparability for rooms by room number - not sure if this will …
Guribot 8b134cc
much-needed refactor for #find_available_rooms
Guribot 4c87057
removed unnecessary code (Hotel to Reservation, etc)
Guribot 4622f6f
formatting
Guribot 14fcd5d
fix broken @block assignment
Guribot f34830b
implement #block_availability? method
Guribot 41bdcc2
removed room comparability, wasnt necessary
Guribot 543d4b2
removed unnecessary private methods
Guribot 328ed62
removed unnecessary hotel parameter
Guribot d5fdd64
comment format
Guribot 84a61ce
validate input in initialize, remove useless #all_rooms method
Guribot e70a665
add validate_order method
Guribot 8cc9530
validate input for #find_available_rooms, reorder methods
Guribot c3ea60f
removed unnecessary Reservation ID
Guribot c89fc53
add InvalidBlockError to #find_available_rooms
Guribot 20c543e
#validate_order will raise exception if given invalid input
Guribot 0021d77
changed InvalidDatesError to ArgumentError to align with Date class
Guribot 37ce94c
edge testing for #find_available_rooms
Guribot 113069b
rename InvalidBlockError to NoBlockError
Guribot 3876d77
edge tests for #make_reservation'
Guribot 94abb1e
reformat comments / add TODO
Guribot ba9026a
edge testing for reservations
Guribot 8af2eb4
add InvalidDiscountError
Guribot 2a690db
edge tests for #make_block
Guribot 3ae8819
renamed InvalidDatesError to DatesError and InvalidDiscountError to D…
Guribot 9c43bda
input validation for Block.discount_rate
Guribot 5adc193
add missing end
Guribot 3244b40
clarify error messages
Guribot 9b83883
add descriptions for exceptions defining their use scenarios
Guribot 03f59e9
input validation for #make_block num_rooms
Guribot 6b2cbdf
edge tests for #make_block
Guribot 77fd316
edge tests for #find_rooms_not_in_blocks and #block_availability?
Guribot 795c446
add #include_all? method
Guribot dce26c5
add #include_all_dates? method
Guribot 586ddbe
add date confirmation for #make_reservation in block
Guribot 9198637
remove TODO
Guribot dbd91fb
#initialize validates instead of parses date input - can take Date or…
Guribot d8425e4
--amend
Guribot 20a1113
remembered why @reservation has to take hotel parameter
Guribot c93eaab
add reader method for @discount_rate and convert output into Float
Guribot 563f649
#make_reservation passes hotel as argument
Guribot dce178c
implement block discount in #get_total
Guribot 1758ca8
remove unused #create_id method
Guribot 218b77e
moved Reservation date validation from Hotel to Reservation.initialize
Guribot 15a5121
removed comments
Guribot fe28cff
block discount can be 0% or 100%
Guribot 7279cbd
discount can be float, discounts to 0%
Guribot 399d924
discount defaults to 0
Guribot 4cdd9c7
discount defaults to 0
Guribot 1aed359
edge tests for #get_total
Guribot b525ab6
renamed Room.cost to Room.rate
Guribot d6964ce
did not need Block.includes_dates? method - replaced all with Block.i…
Guribot 860bc5e
edge tests for #initialize
Guribot fda8015
tentatively removing unused #range_with
Guribot 07fb17f
edge tests for #includes_dates?
Guribot 0fc3390
edge tests for #get_discount_rate
Guribot 836a997
removed unnecessary methods to consolidate self.range_to
Guribot e299acf
edge tests for #range_to, #overlap? and #include_all?
Guribot be990e7
self.validate_order returns true if input is correct
Guribot 5a91bf4
edge tests for #validate_order
Guribot 00b65d8
edge tests for #validate
Guribot 450c168
add test for block dates logic
Guribot de2755e
add design.md to .gitignore
Guribot da4f5b5
ShoppingCart design activity
Guribot 7253647
remove unnecessary input validation in #initialize
Guribot 007a5d1
complete Revisiting Hotel portion
Guribot a84a19d
REFACTOR: moved DateRange.validate method to Date class
Guribot e65e5ea
REFACTOR: moved DateRange.validate method to Date class
Guribot 95cb711
revisiting hotel answer
Guribot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
require 'rake/testtask' | ||
|
||
Rake::TestTask.new do |t| | ||
t.libs = ['lib'] | ||
t.warning = true | ||
t.test_files = FileList['./specs/*_spec.rb'] | ||
end | ||
|
||
task default: :test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
### Activity | ||
##### What classes does each implementation include? Are the lists the same? | ||
|
||
Yes, they are the same. Both implementations have: | ||
* CartEntry | ||
* ShoppingCart | ||
* Order | ||
|
||
|
||
##### Write down a sentence to describe each class. | ||
|
||
Implementation A: | ||
* CartEntry | ||
* Contains basic pricing info entry | ||
* ShoppingCart | ||
* Contains CartEntry objects | ||
* Order | ||
* Contains and totals a ShoppingCart object | ||
|
||
Implementation B: | ||
* CartEntry | ||
* Manages all pricing info of a single entry | ||
* ShoppingCart | ||
* Contains and totals CartEntry objects | ||
* Order | ||
* Contains and totals ShoppingCart, accounting for sales tax | ||
|
||
##### How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper. | ||
* Order _has a_ ShoppingCart | ||
* ShoppingCart _has many_ CartEntries | ||
|
||
##### What data does each class store? How (if at all) does this differ between the two implementations? | ||
Implementation A: | ||
* CartEntry | ||
* Unit price | ||
* Unit quantity | ||
* ShoppingCart | ||
* List of CartEntries | ||
* Order | ||
* ShoppingCart | ||
* Total price of all CartEntries in ShoppingCart | ||
|
||
Implementation B: | ||
* CartEntry | ||
* Unit price | ||
* Unit quantity | ||
* Total entry price | ||
* ShoppingCart | ||
* List of CartEntries | ||
* Total of all CartEntry prices | ||
* Order | ||
* ShoppingCart | ||
* Total price of ShoppingCart with tax | ||
|
||
##### What methods does each class have? How (if at all) does this differ between the two implementations? | ||
Implementation A: | ||
* CartEntry | ||
* #unit_price | ||
* #quantity | ||
* ShoppingCart | ||
* #entries | ||
* Order | ||
* #cart | ||
* #total_price | ||
|
||
Implementation B: | ||
* CartEntry | ||
* #price | ||
* ShoppingCart | ||
* #price | ||
* Order | ||
* #total_price | ||
|
||
Implementation A uses attr_accessor methods to make all of the data contained within each class publicly accessible. Implementation B keeps this data private and uses a #price method on CartEntry and ShoppingCart classes to return only the necessary information (in this case, price). | ||
|
||
##### Consider the Order#totalprice method. In each implementation: | ||
|
||
##### Is logic to compute the price delegated to "lower level" classes like ShoppingCart and CartEntry, or is it retained in Order? | ||
|
||
Implementation A requires the Order#total_price method to dig through the ShoppingCart class and into the CartEntry class to directly access its variables, while Implementation B takes the returned value of ShoppingCart#price and performs its logic around that. | ||
|
||
##### Does totalprice directly manipulate the instance variables of other classes? | ||
|
||
Implementation A directly reads the instance variables of the ShoppingCart and CartEntry classes, though it does not modify them. Implementation B does not directly read or modify any other class' instance variables. | ||
|
||
##### If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify? | ||
|
||
Implementation B would be easier to modify, as this change would only affect the CartEntry class, which could be updated to modify price based on quantity. In Implementation A, this would require the Order#total_price method to perform this additional logic within the same method where it is already calculating the total _and_ applying sales tax. | ||
|
||
##### Which implementation better adheres to the single responsibility principle? | ||
|
||
Implementation B better adheres to this principle, as each class manages and encapsulates its relevant information. | ||
|
||
##### Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? | ||
|
||
### Revisiting Hotel | ||
Overall, I feel that I did a pretty good job of adhering to the single responsibility principle. The only thing that bothers me about my design is that the price of each room comes from a constant variable defined within the Hotel class, but since the current spec of the project is for all of the hotel's rooms to have a price of 200, I still think it makes the most sense for the time being. How I would refactor the code to account for varying room types would vary depending on how the rooms' prices were being determined, so there's nothing to change at the moment. | ||
|
||
The change I _did_ make was to remove the #validate method from the DateRange class. My thought process behind the change was that the method (which converts valid input into a Date object if it isn't already one) only interacts with one date, and therefore should be part of the Date class, not DateRange. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
module Hotel | ||
class Block | ||
attr_reader :rooms, :id, :start_date, :end_date, :dates, :discount_rate | ||
|
||
def initialize(start_date, end_date, rooms, discount_rate = 0) | ||
@start_date = Date.parse(start_date) | ||
@end_date = Date.parse(end_date) | ||
@dates = DateRange.range_to(@start_date, @end_date) | ||
@rooms = rooms | ||
@discount_rate = get_discount_rate(discount_rate) | ||
@id = create_id | ||
end | ||
|
||
def create_id | ||
format('B%.2d%.2d%.4d', @start_date.month, @start_date.day, rand(9999)) | ||
end | ||
|
||
def includes_dates?(checkfirst, checklast) | ||
DateRange.include_all?(checkfirst, checklast, @start_date, @end_date) | ||
end | ||
|
||
def get_discount_rate(input) | ||
raise(ArgumentError, "Discount must be number: was #{input.class}") unless (input.class == Integer) || (input.class == Float) | ||
raise(DiscountError, "Discount must be between 0-100%: was #{input}") unless 0 <= input && input <= 100 | ||
return (100.0 - input) / 100 | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
module DateRange | ||
require 'date' | ||
|
||
def self.range_to(start_date, end_date) | ||
start_date = Date.validate(start_date) | ||
end_date = Date.validate(end_date) | ||
validate_order(start_date, end_date) | ||
dates = [] | ||
while start_date < end_date | ||
dates << start_date | ||
start_date += 1 | ||
end | ||
dates | ||
end | ||
|
||
def self.overlap?(first_start, first_end, second_start, second_end) | ||
first_start = Date.validate(first_start) | ||
first_end = Date.validate(first_end) | ||
second_start = Date.validate(second_start) | ||
second_end = Date.validate(second_end) | ||
|
||
first_dates = DateRange.range_to(first_start, first_end) | ||
second_dates = DateRange.range_to(second_start, second_end) | ||
|
||
first_dates.each do |first_date| | ||
second_dates.each do |second_date| | ||
return true if first_date.strftime == second_date.strftime | ||
end | ||
end | ||
false | ||
end | ||
|
||
def self.include_all?(search_start, search_end, contain_start, contain_end) | ||
search_start = Date.validate(search_start) | ||
search_end = Date.validate(search_end) | ||
contain_start = Date.validate(contain_start) | ||
contain_end = Date.validate(contain_end) | ||
|
||
search_dates = DateRange.range_to(search_start, search_end) | ||
contain_dates = DateRange.range_to(contain_start, contain_end) | ||
|
||
search_dates.each do |search_date| | ||
return false unless contain_dates.include? search_date | ||
end | ||
true | ||
end | ||
|
||
def self.validate_order(first, second) | ||
first = Date.validate(first) | ||
second = Date.validate(second) | ||
unless first < second | ||
raise(DatesError, 'Start date must be at least 1 day before end date') | ||
end | ||
true | ||
end | ||
end | ||
|
||
class Date | ||
def self.validate(input) | ||
if input.class == Date | ||
return input | ||
elsif input.class == String | ||
return Date.parse(input) | ||
else | ||
raise(ArgumentError, "Input #{input.class} cannot be converted into Date") | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
class NoRoomError < StandardError | ||
# Raised when there are not enough available rooms for request | ||
end | ||
|
||
class DatesError < StandardError | ||
# Raised when dates are in wrong order, out of range, etc | ||
# NOT raised for invalid date input (use ArgumentError) | ||
end | ||
|
||
class NoBlockError < StandardError | ||
# Raised when provided block does not exist/cannot be found | ||
end | ||
|
||
class DiscountError < StandardError | ||
# Raised when discount is not number from 0-100 | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
require 'pry' | ||
|
||
module Hotel | ||
require_relative 'room' | ||
require_relative 'reservation' | ||
require_relative 'room' | ||
require_relative 'block' | ||
require_relative 'exceptions' | ||
|
||
class Hotel | ||
attr_reader :rooms, :reservations, :blocks | ||
ROOM_COST = 200 | ||
|
||
def initialize(num_rooms) | ||
@rooms = [] | ||
|
||
num_rooms.times do |i| | ||
@rooms << Room.new(i + 1, ROOM_COST) | ||
end | ||
@reservations = [] | ||
@blocks = [] | ||
end | ||
|
||
def make_reservation(checkin, checkout, block = false) | ||
room_num = find_available_rooms(checkin, checkout, block).first | ||
if room_num.nil? | ||
raise(NoRoomError, "No available rooms for dates #{checkin} - #{checkout}") | ||
end | ||
reservation = Reservation.new(room_num, checkin, checkout, self, block) | ||
@reservations << reservation | ||
reservation | ||
end | ||
|
||
def make_block(start_date, end_date, num_rooms, discount = 0) | ||
raise(ArgumentError,"Number of rooms must be Integer: is #{num_rooms.class}") unless num_rooms.class == Integer | ||
|
||
rooms = find_available_rooms(start_date, end_date)[0...num_rooms] | ||
|
||
raise(NoRoomError, "Not enough available rooms for amount #{num_rooms}") if rooms.length < num_rooms | ||
|
||
block = Block.new(start_date, end_date, rooms, discount) | ||
@blocks << block | ||
block | ||
end | ||
|
||
def view_reservations(date) | ||
date = Date.validate(date) | ||
reservations = [] | ||
@reservations.each do |reservation| | ||
reservations << reservation if reservation.dates.include?(date) | ||
end | ||
reservations | ||
end | ||
|
||
def find_available_rooms(checkin, checkout, block_id = false) | ||
DateRange.validate_order(checkin, checkout) | ||
if block_id | ||
unless block_exists?(block_id) | ||
raise(NoBlockError, "No such block: #{block_id}") | ||
end | ||
unless block(block_id).includes_dates?(checkin, checkout) | ||
raise(DatesError, "Dates (#{checkin}, #{checkout}) do not fall within provided block #{block(block_id).id}") | ||
end | ||
rooms = block(block_id).rooms | ||
else | ||
rooms = find_rooms_not_in_blocks(checkin, checkout) | ||
end | ||
|
||
@reservations.each do |reservation| | ||
rooms.delete(reservation.room) if (rooms.include? reservation.room) && reservation.includes_dates?(checkin, checkout) | ||
end | ||
rooms | ||
end | ||
|
||
def block_availability?(checkin, checkout, block_id) | ||
find_available_rooms(checkin, checkout, block_id) != [] | ||
end | ||
|
||
def room(num) | ||
@rooms.each { |room| return room if room.number == num } | ||
nil | ||
end | ||
|
||
def block(id) | ||
@blocks.each { |block| return block if block.id == id } | ||
nil | ||
end | ||
|
||
# private | ||
def find_rooms_not_in_blocks(start_date, end_date) | ||
rooms = @rooms.dup | ||
@blocks.each do |block| | ||
if block.includes_dates?(start_date, end_date) | ||
rooms.delete_if { |room| block.rooms.include? room } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good use of an instance method ( |
||
end | ||
end | ||
rooms | ||
end | ||
|
||
def block_exists?(block_id) | ||
block(block_id) != nil | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
require 'pry' | ||
|
||
module Hotel | ||
class Reservation | ||
require_relative 'date_range' | ||
attr_reader :total_cost, :dates, :checkin, :checkout, :id, :hotel, :room, :block | ||
|
||
def initialize(room, checkin, checkout, hotel, block = false) | ||
@room = room | ||
@checkin = Date.validate(checkin) | ||
@checkout = Date.validate(checkout) | ||
@dates = DateRange.range_to(@checkin, @checkout) | ||
if block | ||
@block = hotel.block(block) | ||
raise(DatesError) unless @block.includes_dates?(checkin, checkout) | ||
else | ||
@block = false | ||
end | ||
get_total | ||
end | ||
|
||
def get_total | ||
num_nights = @dates.length | ||
@total_cost = @room.rate * num_nights | ||
@total_cost *= @block.discount_rate if @block | ||
end | ||
|
||
def includes_dates?(checkfirst, checklast) | ||
DateRange.overlap?(checkfirst, checklast, @checkin, @checkout) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module Hotel | ||
class Room | ||
attr_reader :number, :rate | ||
|
||
def initialize(number, rate) | ||
@number = number | ||
@rate = rate | ||
end | ||
end | ||
end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like this method - it is well-implemented and very easy to read.
Minor note: you don't need the
(rooms.include? reservation.room)
. Attempting to delete an element from a list in which it doesn't appear will have no effect (not an error).