Conversation
…d_reservation method
…e method in Main.rb. Got previous failing tests working and wrote a new test test that is bith failing and passing when guard is run multiple times. Need to fix.
…d to fix previous issue but could not.
…les. Made FrontDesk a Class again. Modiefied tests by instantiating FrontDesk in each describe block
…sponding tests as well. Added .round to total_cost
…eservation method to check for overlapping dates for room reservations and to raise error if dates overlap.
…lass. Created a class called BlockRoom for Wave 3. Class has been tested.
… in FrontDesk class
HotelWhat We're Looking For
Good work on this, Faiza-- your design overall ended up to be pretty good, and your tests were full However, I have a huge concern about some of your code style. You relied on nesting a lot of ifs/elsifs/elses inside of nested loops, and more loops! With a little thought about how to refactor, you can get rid of a lot of complexity. Similarly, parts of your logic felt strange: what is a Similarly, there were a lot of misses on some requirements because of how you implemented room blocks. Room Blocks are not a type of reservation-- even if it may seem like they are. A lot of my comments are on the following things:
I would love to see improvements on all of these areas, especially the each loops, in the near future Good work on pushing through this project-- your project could definitely grow and improve, but overall you have a submission that got through all the waves. |
| attr_accessor :room_booking_ref, :block_room_number, :check_in, :check_out | ||
|
|
||
| def initialize(room_booking_ref:, block_room_number:, check_in:, check_out:) | ||
| @room_booking_ref = room_booking_ref |
There was a problem hiding this comment.
What is this variable? Was there a requirement for it?
| module Hotel | ||
| class FrontDesk | ||
| # attr_reader :all_rooms, :reservations_record, :block_reservations_only, :reserved_rooms_in_blocks | ||
| attr_accessor :all_rooms, :reservations_record, :block_reservations_only, :reserved_rooms_in_blocks |
There was a problem hiding this comment.
Why did you choose to make this accessor instead of reader? Your tests still run the same way if you make it reader, so I would choose this over accessor
|
|
||
| def all_rooms_array | ||
| return @all_rooms | ||
| end |
There was a problem hiding this comment.
I don't think this method is wrong-- in fact, it is the perfect example of a "getter method"! However, since what you are returning is an instance variable (@all_rooms), there are ways to refactor this to be shorter and smaller. Think on it and let me know what questions you have :)
| check_out: new_check_out, | ||
| total_cost: @total_cost, | ||
| room_blocks: @room_blocks, | ||
| ) |
There was a problem hiding this comment.
Here, when you're calling Reservation.new, you are saying that the value that should go into the parameter total_cost should be whatever @total_cost is... but @total_cost doesn't have any value stored on it, ever! You never call @total_cost = ... ever in your code, so it will always be nil.
ame with @room_blocks. @room_blocks is the name of the variable that this instance of FrontDesk has stored, but this instance of FrontDesk will never change that value, so it's always nil. What value were you expecting to be on @room_blocks?
| if (@reservations_record.length == 0) | ||
| booking = reservation_template(new_booking_ref, new_number_of_rooms, new_first_room_number, new_check_in, new_check_out) | ||
| else | ||
| for i in (0...@reservations_record.length) |
There was a problem hiding this comment.
Why did you choose this for loop instead of an each loop? If you used an each loop, then to refer to each reservation, you can say
@reservations_record.each do |reservation|
old_first_room_no = reservation.first_room_number
endnote the difference: reservation, as opposed to @reservations_record[i], so it's a lot shorter and cleaner
| booking = reservation_template(new_booking_ref, new_number_of_rooms, new_first_room_number, new_check_in, new_check_out) | ||
| else | ||
| for i in (0...@reservations_record.length) | ||
| old_first_room_no = @reservations_record[i].first_room_number |
There was a problem hiding this comment.
What does old_first_room_no represent?
|
|
||
| if ((old_first_room_no >= new_first_room_number && old_first_room_no <= new_last_room_no) || | ||
| (old_last_room_no >= new_first_room_number && old_last_room_no <= new_last_room_no) || | ||
| ((old_first_room_no <= new_first_room_number) && (old_first_room_no <= new_last_room_no) && (old_last_room_no >= new_first_room_number) && (old_last_room_no >= new_last_room_no))) |
| booking = reservation_template(new_booking_ref, new_number_of_rooms, new_first_room_number, new_check_in, new_check_out) | ||
| end | ||
| end | ||
| end |
There was a problem hiding this comment.
Your variable names and your complex logic here are overwhelming and confusing, and difficult to read. This would be great pulled into helper methods.
| def get_reservations_by_date(date) | ||
| reservations_by_date_list = Array.new | ||
|
|
||
| for index in (0...@reservations_record.length) |
There was a problem hiding this comment.
For every time you do for i in (0...array.length), it is probably better and more clear to use an each loop
| reservations_at_date = get_reservations_by_date(date) | ||
|
|
||
| available_rooms = Array.new | ||
| for room_idx in (0...@all_rooms.length) |
| available_rooms = Array.new | ||
| for room_idx in (0...@all_rooms.length) | ||
| room_booked = false | ||
| for res_idx in (0...reservations_at_date.length) |
| for room_idx in (0...@all_rooms.length) | ||
| room_booked = false | ||
| for res_idx in (0...reservations_at_date.length) | ||
| for i in (0..@reservations_record[res_idx].room_blocks.length - 1) |
| end | ||
| end | ||
| end | ||
| if (room_booked == false) |
There was a problem hiding this comment.
For something this short, no need to put parens: if room_booked == false or even if !room_booked
| if (room_booked == false) | ||
| available_rooms << @all_rooms[room_idx] | ||
| end | ||
| end |
There was a problem hiding this comment.
This logic isn't clear-- it might be clearer if you iterated through your reservations first, instead of all rooms and then all reservations. However, ultimately, this code isn't readable because of the long variable names and the nested logic. Having a deep "V" nesting (there are 4 levels of nesting) is an indicator that things should be reworked, refactored, and pulled into helper methods.
|
|
||
| #### BLOCK METHODS #### | ||
| def add_block_reservations | ||
| for i in (0...@reservations_record.length) |
| @block_reservations_only << @reservations_record[i] | ||
| end | ||
| end | ||
| end |
There was a problem hiding this comment.
What is this method accomplishing? Why do we add to @block_reservations_only every reservation with multiple rooms?
| end | ||
|
|
||
| def make_reservation_in_block(block_room_booking_ref, block_room_number, block_check_in, block_check_out) | ||
| for i in (0...@block_reservations_only.length) |
|
|
||
| rooms_in_blocks = Array.new | ||
| available_rooms_in_block = Array.new | ||
| for i in (0...block_reservations_at_date.length) |
| rooms_in_blocks = Array.new | ||
| available_rooms_in_block = Array.new | ||
| for i in (0...block_reservations_at_date.length) | ||
| for j in (0...block_reservations_at_date[i].room_blocks.length) |
| def block_room_availability(date) | ||
| rooms_in_blocks = all_rooms_in_blocks(date) | ||
| rooms_available_in_blocks = Array.new | ||
| for i in (0...rooms_in_blocks.length) |
| rooms_in_blocks = all_rooms_in_blocks(date) | ||
| rooms_available_in_blocks = Array.new | ||
| for i in (0...rooms_in_blocks.length) | ||
| for j in (0...@reserved_rooms_in_blocks.length) |
| module Hotel | ||
| class Reservation | ||
| attr_reader :booking_ref | ||
| attr_accessor :booking_ref, :number_of_rooms, :first_room_number, :check_in, :check_out, :total_cost, :room_blocks |
There was a problem hiding this comment.
You probably should make all of these reader. Also, you don't need to double up-- booking_ref is in both reader and accessor and you should probably pick one
| DISCOUNTED_RATE = 160.00 | ||
|
|
||
| def initialize(booking_ref:, number_of_rooms:, first_room_number:, check_in:, check_out:, total_cost:, room_blocks:) | ||
| @booking_ref = booking_ref |
There was a problem hiding this comment.
What is a booking_ref? Is there a requirement for this?
| @booking_ref = booking_ref | ||
|
|
||
| if (number_of_rooms <= 5) | ||
| @number_of_rooms = number_of_rooms |
There was a problem hiding this comment.
There is no requirement that a reservation should have more than one room. Blocks should have different behavior: they are not a type of reservation
| raise ArgumentError, "A block can only have 5 rooms or less." | ||
| end # if | ||
|
|
||
| @first_room_number = first_room_number |
There was a problem hiding this comment.
What is a first_room_number? What does it represent?
| @total_cost = ((check_out - check_in) * number_of_rooms) * DISCOUNTED_RATE | ||
| end # if | ||
|
|
||
| @room_blocks = Array.new |
There was a problem hiding this comment.
Hm, I think that this isn't what the requirements were asking for...
|
|
||
| it "creates an instance of BlockRoom" do | ||
| expect(@block_room).must_be_kind_of Hotel::BlockRoom | ||
| end |
There was a problem hiding this comment.
Tests could be filled out a little more
| return Hotel::FrontDesk.new | ||
| end | ||
|
|
||
| describe "all arrays" do |
There was a problem hiding this comment.
Not the best name for this test! What if these values grow to not be arrays in the future? This is testing that the initial values are correct
| 1, | ||
| Date.new(2019, 3, 20), | ||
| Date.new(2019, 3, 24), | ||
| ) |
There was a problem hiding this comment.
Probably would make sense to use keyword arguments here, since you defined them as such in Reservation
| expect(by_date).must_be_kind_of Array | ||
| expect(by_date.length).must_equal 1 | ||
| expect(reservation_2.check_in).must_be :<, Date.new(2019, 4, 10) | ||
| expect(reservation_2.check_in).must_be :>, Date.new(2019, 4, 7) |
There was a problem hiding this comment.
You probably don't need to make assertions on reservation2 in this test, since you didn't alter it
| before do | ||
| @concierge = build_front_desk | ||
| end | ||
| it "will raise an ArgumentError if check_out date is before current date" do |
There was a problem hiding this comment.
The logic for this test ends up living in the Reservation class, and you even test it there -- no need to double test it here in this file, unless this code was doing something different
| Date.new(2019, 10, 8), | ||
| Date.new(2019, 10, 12) | ||
| ) | ||
| }.must_raise ArgumentError |
There was a problem hiding this comment.
It isn't clear from this test why this is relevant to the test (it looks like a regular, valid reservation)-- maybe there are ways to use variable names and error detail testing to make this clear
| Date.new(2019, 7, 5) | ||
| ) | ||
| }.must_raise ArgumentError | ||
| end |
There was a problem hiding this comment.
I would expect more edge cases than this!
| @concierge.add_block_reservations | ||
|
|
||
| expect(@concierge.block_reservations_only.length).must_equal 1 | ||
| end |
There was a problem hiding this comment.
What happens if you make two hotel blocks for the same date range?
| Date.new(2019, 7, 5), | ||
| Date.new(2019, 7, 6), | ||
| ) | ||
| }.must_raise ArgumentError |
There was a problem hiding this comment.
Why should this raise an error? If this is a different case, then you should write a different test for it
| check_out: Date.new(2019, 5, 24), | ||
| total_cost: @total_cost, | ||
| room_blocks: @room_blocks, | ||
| ) |
There was a problem hiding this comment.
Same as the comments that I had in your FrontDesk file... @total_cost will always be nil, no matter what, so you probably wouldn't want to say total_cost: @total_cost, but just total_cost: nil if that's what you're expecting
…ted two new helper methods to check for room and date overlaps
…ulate room cost, check block size, and populate the room_blocks array
Hotel
Congratulations! You're submitting your assignment!
Comprehension Questions