Conversation
HotelWhat We're Looking For
|
| class BlockReservation | ||
| attr_accessor :block_id, :reservation_id, :room, :start_date, :end_date, :price_per_night | ||
|
|
||
| def initialize(block_id:, reservation_id:, room:, start_date:, end_date:, price_per_night:) |
There was a problem hiding this comment.
The only difference between this and a regular reservation is that a block reservation has a block ID. One option that might simplify your design is to consolidate both in the Reservation class, and add in an optional block ID, which would be nil if this reservation isn't part of a block.
|
|
||
| def make_reservation(start_date, end_date) | ||
| reservation = Hotel::Reservation.new(reservation_id: generate_id, room: assign_available_room(start_date, end_date), start_date: start_date, end_date: end_date, price_per_night: 200) | ||
| @reservations << reservation |
There was a problem hiding this comment.
I love the way you've broken each of these bits of functionality into separate methods! However, it's a little difficult to read all on one line like this. You might split it across multiple lines:
reservation = Hotel::Reservation.new(
reservation_id: generate_id(),
room: assign_available_room(start_date, end_date),
start_date: start_date,
end_date: end_date,
price_per_night: 200
)I also like adding parentheses to the call to generate_id(), even though there are no arguments - this makes it a little clearer that this is a method call.
| def make_block(start_date, end_date, number_of_rooms) | ||
| if number_of_rooms > 5 | ||
| raise ArgumentError, "Cannot reserve more than 5 rooms" | ||
| end |
There was a problem hiding this comment.
What if the number of rooms is less than 1?
| @blocks << block | ||
|
|
||
| number_of_rooms.times do | ||
| block_reservation = Hotel::BlockReservation.new(block_id: id, reservation_id: nil, room: assign_available_room(start_date, end_date), start_date: start_date, end_date: end_date, price_per_night: 150) |
There was a problem hiding this comment.
Same comment about line lengths on lines 36 and 40.
| @reservations.each do |reservation| | ||
| if | ||
| reservation.start_date < end_date && start_date < reservation.end_date | ||
| booked_rooms << reservation.room |
There was a problem hiding this comment.
Here your BookingSystem is taking on some extra responsibility: determining whether a reservation overlaps a set of dates. I would argue that that is really the reservation's responsibility. You could write a method called something like Reservation#overlap?(start_date, end_date) that takes care of this logic.
That simplifies this code, and makes it easier to test the logic in isolation. You also repeat this code on line 72, which means that if the requirements change or you discover a bug, you'll have to change it in two places.
There was a problem hiding this comment.
This also an example of tight coupling, since BookingSystem needs to know about how a Reservation stores its dates.
There was a problem hiding this comment.
Why not call reservations_within_date here to get the list of booked_rooms?
| reservations_within_date = [] | ||
| @reservations.each do |reservation| | ||
| if | ||
| reservation.start_date < end_date && start_date < reservation.end_date |
There was a problem hiding this comment.
This and the above method could be streamlined a little using the select enumerable:
return @reservations.select do |reservation|
reservation.start_date < end_date && start_date < reservation.end_date
end|
|
||
| reservation3 = Hotel::Reservation.new(reservation_id: 3, room: @system.assign_available_room(Date.new(2018, 1, 6), Date.new(2018, 1, 9)), start_date: Date.new(2018, 1, 6), end_date: Date.new(2018, 1, 9), price_per_night: 200) | ||
| @system.reservations << reservation3 | ||
| expect(reservation3.room).must_equal 2 |
There was a problem hiding this comment.
Rather than creating a whole new reservation here, I would probably just call .assign_available_room and check the result directly:
room = @system.assign_available_room(Date.new(2018, 1, 6), Date.new(2018, 1, 9))
expect(room).must_equal 2| it "makes a reservation" do | ||
| @system.make_reservation(Date.new(2018,1,1), Date.new(2018,1,5)) | ||
| reservation = Hotel::Reservation.new(reservation_id: 1, room: 1, start_date: Date.new(2018, 1, 1), end_date: Date.new(2018, 1, 5), price_per_night: 200) | ||
| expect(@system.reservations.length).must_equal 1 |
There was a problem hiding this comment.
You have a lot of Date.new(...) in this file, which is a little difficult to read. Instead you might create a couple in a before block and put them in instance variables to use later:
@start_date = Date.new(2018, 1, 1)
@end_date = Date.new(2018, 1, 5)| it "raises argument error if no rooms are available" do | ||
|
|
||
| 20.times do | ||
| reservation = Hotel::Reservation.new(reservation_id: 1, room: @system.assign_available_room((Date.new(2018, 1, 1)), (Date.new(2018, 1, 8))), start_date: Date.new(2018, 1, 1), end_date: Date.new(2018, 1, 8), price_per_night: 200) |
There was a problem hiding this comment.
I like this test case! However, it should probably be in the describe block for make_reservation, since that's what it's testing.
| describe "search reservation dates" do | ||
| before do | ||
|
|
||
| reservation1 = Hotel::Reservation.new(reservation_id: 1, room: 1, start_date: Date.new(2018, 1, 1), end_date: Date.new(2018, 1, 8), price_per_night: 200) |
There was a problem hiding this comment.
There are several other interesting edge cases around date overlaps that you're missing here. I see you've got the list copy-pasted below, so I'm guessing it was just a matter of time.
Putting the overlap logic into its own method on Reservation would make these tests much easier to write.
Hotel
Congratulations! You're submitting your assignment!
Comprehension Questions