-
Notifications
You must be signed in to change notification settings - Fork 46
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
Naheed - Hotel - Edges #43
base: master
Are you sure you want to change the base?
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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