Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
d8c93e9
initial commit with class and test files
seaweeddol Mar 2, 2020
71c9caf
require lib files
seaweeddol Mar 2, 2020
0ceda41
create HotelManager class with initialize method
seaweeddol Mar 2, 2020
be9f6d6
add tests for HotelManager list_rooms method
seaweeddol Mar 2, 2020
27b51b5
add simple list_rooms method to HotelManager class
seaweeddol Mar 2, 2020
798e577
update list_rooms no rooms test to check for empty array instead of nil
seaweeddol Mar 2, 2020
f1ddfa1
update list_rooms method to return rooms without conditional
seaweeddol Mar 2, 2020
9df7fce
create Room class and add initialize method
seaweeddol Mar 2, 2020
26a9550
add tests for DateRange class: initialize and total_nights methods
seaweeddol Mar 3, 2020
eae3b18
create DateRange class with initialize and total_nights method
seaweeddol Mar 3, 2020
61c9760
add tests for DateRange validate_date method
seaweeddol Mar 3, 2020
755861d
create validate_date method for DateRange class
seaweeddol Mar 3, 2020
d92ed09
add test for creating Reservation class
seaweeddol Mar 3, 2020
9ec6a03
create Reservation class with initialize method
seaweeddol Mar 3, 2020
5e5fe70
add test to check if nights is calculated correctly in Reservation class
seaweeddol Mar 3, 2020
d4ea6fd
in Reservation, update nights to calculate number of nights
seaweeddol Mar 3, 2020
7ebca35
rewrite validate_date tests for DateRange class
seaweeddol Mar 3, 2020
f8324cb
update DateRange class to validate_date within the initializer
seaweeddol Mar 3, 2020
0fa22ae
update Reservation to take one argument
seaweeddol Mar 3, 2020
8ee037e
add reserve_room method to HotelManager
seaweeddol Mar 3, 2020
730c888
add tests for reserve_room method
seaweeddol Mar 3, 2020
4105abd
add date instance variables to Reservation
seaweeddol Mar 3, 2020
4c58c8d
add range variable to Reservation class
seaweeddol Mar 3, 2020
ab5c470
add tests for check_availability method in Room class
seaweeddol Mar 3, 2020
14c712f
add check_availability method to Room class
seaweeddol Mar 3, 2020
b4d5c7c
add tests for initialize_rooms method
seaweeddol Mar 3, 2020
531d217
add initialize_rooms method to HotelManager class
seaweeddol Mar 3, 2020
0d8ecde
add tests for find_room and list_reservations
seaweeddol Mar 4, 2020
89fcd73
add find_room and list_reservation methods to HotelManager class
seaweeddol Mar 4, 2020
56e666b
update variable name 'daterange' to 'date_range'
seaweeddol Mar 4, 2020
42d626d
update list_reservations to list_reservations_by_room
seaweeddol Mar 4, 2020
a3a6dd7
add logic and test to check_availability method for when first day of…
seaweeddol Mar 4, 2020
d345f85
add list_reservations_by_date method to HotelManager
seaweeddol Mar 4, 2020
bce125a
refactor check_availability method
seaweeddol Mar 4, 2020
df07947
add overlap? method to DateRange
seaweeddol Mar 4, 2020
f5f42f5
change composition of Reservation to have a DateRange
seaweeddol Mar 4, 2020
91e1c51
fix list_reservations_by_room to return correct reservations
seaweeddol Mar 4, 2020
78cc449
add additional test for HotelManager: list_reservations_by_date
seaweeddol Mar 4, 2020
11fcfcf
add room_number to Reservation created by reserve_room method
seaweeddol Mar 4, 2020
fcb013d
add total_cost method to Room class
seaweeddol Mar 4, 2020
761bbe8
add total_cost writer and optional room_number to initializer
seaweeddol Mar 4, 2020
577bc02
add include? method to DateRange
seaweeddol Mar 4, 2020
4376d09
Revert "add include? method to DateRange"
seaweeddol Mar 4, 2020
4328403
move calculate_cost from Room to HotelManager
seaweeddol Mar 4, 2020
f9299c4
refactor class methods
seaweeddol Mar 5, 2020
e9fc699
push new Reservation into correct Room number
seaweeddol Mar 5, 2020
ce23e8c
refactor tests for Wave 1
seaweeddol Mar 5, 2020
3d6486a
refactor list_reservations
seaweeddol Mar 5, 2020
3386b4c
add list_available_rooms method to HotelManager
seaweeddol Mar 6, 2020
28afae8
add list_reservations method to Room
seaweeddol Mar 6, 2020
7a49c9b
simplify test data
seaweeddol Mar 6, 2020
861ea42
create helper method find_reservations for list_reservations
seaweeddol Mar 6, 2020
0cb23f2
remove list_reservations from Room
seaweeddol Mar 6, 2020
3912efa
remove list_reservations from HotelManager
seaweeddol Mar 6, 2020
8fa06b7
move calculate_cost method from HotelManager to Reservation
seaweeddol Mar 7, 2020
2ed69e3
add cost reader
seaweeddol Mar 7, 2020
6c20c08
add test to verify Reservation receives cost
seaweeddol Mar 7, 2020
be9f83d
initialize HotelBlock class
seaweeddol Mar 8, 2020
b06b044
remove unnecessary require_relatives
seaweeddol Mar 8, 2020
59b25a1
add check_availability method to HotelBlock
seaweeddol Mar 8, 2020
ca2be75
add reserve_block method to HotelManager
seaweeddol Mar 8, 2020
46952a9
add HotelBlock to blocks
seaweeddol Mar 9, 2020
5564f70
use existing method list_available_rooms to check availability of roo…
seaweeddol Mar 9, 2020
ace8f03
add HotelBlock readers to Reservation
seaweeddol Mar 9, 2020
0d9ab3d
add check_block_availability and add_block_rooms methods to HotelManager
seaweeddol Mar 9, 2020
255e74f
add calculate_discounted_rate method to HotelBlock
seaweeddol Mar 9, 2020
178deff
update create_block_reservation to use information from find_block
seaweeddol Mar 9, 2020
5442afb
add check_availability and find_reservations to HotelBlock
seaweeddol Mar 9, 2020
578031d
change create_block_reservation to reserve_block_room, update existin…
seaweeddol Mar 9, 2020
556e2bf
add :available writer to Reservation
seaweeddol Mar 9, 2020
68c81de
submit refactors.txt
seaweeddol Mar 9, 2020
d6daf7f
remove comment
seaweeddol Mar 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
6 changes: 3 additions & 3 deletions Guardfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
guard :minitest, bundler: false, autorun: false, rubygems: false do
# with Minitest::Spec
guard :minitest, bundler: false, autorun: true, rubygems: false do
# With Minitest Reporters
watch(%r{^test/(.*)_test\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
watch(%r{^test/test_helper\.rb$}) { 'test' }
end
end
41 changes: 41 additions & 0 deletions lib/date_range.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require 'date'

module Hotel
class DateRange
attr_reader :start_date, :end_date, :range

def initialize(start_date, end_date)
@start_date = start_date
@end_date = end_date
validate_date()

@range = (start_date..end_date).to_a
end

def total_nights
return @end_date - @start_date
end

def validate_date()
unless (@start_date.is_a? Date) && (@end_date.is_a? Date)
raise ArgumentError.new("Invalid date provided: must be instance of Date")
end

if @start_date < Date.today
raise ArgumentError.new("Invalid date provided: start_date must be prior to today's date")
elsif @end_date < @start_date
raise ArgumentError.new("Invalid date provided: end_date must be prior to start_date")
end
end

def overlap?(date_range)
# if check-out date of one matches check-in date of the other, dates do not overlap
return false if (@range[-1] == date_range.range[0]) || (@range[0] == date_range.range[-1])

# if any dates are in both ranges, dates overlap
return (@range & date_range.range).any? ? true : false
end

end

end
40 changes: 40 additions & 0 deletions lib/hotel_block.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module Hotel
class HotelBlock
attr_reader :date_range, :rooms, :discount_rate, :id

def initialize(date_range, rooms, discount_rate, id)
@date_range = date_range
@rooms = rooms
raise ArgumentError.new("Max of 5 rooms can be reserved in a block") if rooms.length > 5
@discount_rate = discount_rate
calculate_discounted_rate()
@id = id
end

def calculate_discounted_rate()
if @discount_rate > 1
@discount_rate *= 0.01
end
@rooms.each do |room|
room.cost -= (room.cost * @discount_rate)
end
end

def check_availability
available_rooms = []
find_reservations.each do |reservation|
available_rooms << reservation.room_number if reservation.available == true
end
return available_rooms
end

def find_reservations
reservations = []
@rooms.each do |room|
reservations << room.reservations.find { |reservation| reservation.hotel_block == @id }
end
return reservations
end

end
end
132 changes: 132 additions & 0 deletions lib/hotel_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
require_relative "hotel_block"

module Hotel
class HotelManager
attr_reader :rooms, :blocks, :total_reservations

def initialize
@rooms = []
@blocks = []
@total_reservations = 0
end

def initialize_rooms(num)
if num.class != Integer
raise ArgumentError.new("Integer value must be provided. Value provided: '#{num}'")
else
num.times do |i|
room = Hotel::Room.new((i + 1), 200)
@rooms << room
end
end
end

def list_all_rooms
return @rooms
end

def reserve_room(date_range, room = nil)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use case of the optional parameter! Makes total sense

picked_room = ""
if !room
available_rooms = list_available_rooms(date_range)
raise ArgumentError.new("No rooms available") if available_rooms == []
picked_room = available_rooms[0]
else
picked_room = find_room(room)
end

@total_reservations += 1
reservation = Reservation.new(date_range, @total_reservations, picked_room.number, picked_room.cost)

find_room(reservation.room_number).reservations << reservation
Comment on lines +39 to +41
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A very small design thing to consider in the future:

Since your HotelManager class manages number of total reservations, it makes sense that @total_reservations += 1 logic lives here. But since Room manages reservations, too, it might be interesting to see the above lines take more of an approach to:

  1. Find the right room in HotelManager, THEN
  2. Tell the right room to create and add a reservation.

I would personally achieve this by doing the find_room method first, and then creating an instance method in Room to create the Reservation object instance and shovel it into its reservations array. This is a thought for a future refactoring!

return reservation
end

def reserve_block(date_range, rooms, discount_rate)
check_availability = check_block_availability(date_range, rooms)

add_block_rooms(date_range, check_availability, discount_rate)

block = Hotel::HotelBlock.new(date_range, check_availability, discount_rate, @blocks.length + 1)
@blocks << block

return block
end

def add_block_rooms(date_range, rooms, discount_rate)
rooms.each do |room|
@total_reservations += 1
reservation = Hotel::Reservation.new(date_range, @total_reservations, room.number, room.cost * (1 + discount_rate), @blocks.length + 1, true)
room.reservations << reservation
end
end

# check whether a given block has any rooms available
def check_block_availability(date_range, rooms)
available_rooms = list_available_rooms(date_range)

raise ArgumentError.new("Not all rooms have availability") if !(rooms - available_rooms).empty?

return rooms
end

# reserve a specific room from a hotel block
def reserve_block_room(room, block)
found_block = find_block(block)
found_room = find_room(room)
found_reservation = found_room.reservations.find { |reservation| reservation.hotel_block == block}
found_reservation.available == false
return found_reservation
end

def find_block(id)
found_block = @blocks.find { |block| block.id == id }
return found_block
end

def find_room(id)
found_room = @rooms.find { |room| room.number == id }
return found_room
end

def list_reservations_by_room(room, date_range)
reservation_list = []
found_room = find_room(room)

found_room.reservations.each do |reservation|
if reservation.date_range.overlap?(date_range) == true
reservation_list << reservation
end
end

return reservation_list
end

def list_reservations_by_date(date)
reservation_list = []

@rooms.each do |room|
room.reservations.each do |reservation|
if reservation.date_range.range.include?(date)
reservation_list << reservation
end
end
end

return reservation_list
end

def list_available_rooms(date_range)
available_rooms = []

@rooms.length.times do |i|
room = find_room(i + 1)
available = room.check_availability(date_range)
available_rooms << room if available
end

return available_rooms
end

end
end
23 changes: 23 additions & 0 deletions lib/reservation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Hotel
class Reservation
attr_reader :date_range, :id, :room_number, :nights, :cost, :hotel_block

attr_accessor :total_cost, :available

def initialize(date_range, id = 0, room_number = 0, cost = 0, hotel_block = nil, available = nil)
@date_range = date_range
@id = id
@cost = cost
@nights = date_range.total_nights
@total_cost = calculate_cost()
@room_number = room_number
@hotel_block = hotel_block || false
@available = available || false
end

def calculate_cost()
return @cost * @nights
end

end
end
22 changes: 22 additions & 0 deletions lib/room.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module Hotel
class Room
attr_reader :reservations, :number, :cost
attr_writer :cost

def initialize(number, cost, reservations = [])
@number = number
@cost = cost
@reservations = []
end

def check_availability(date_range)
return true if @reservations.empty?
@reservations.each do |reservation|
# return false if dates overlap, else continue
reservation.date_range.overlap?(date_range) ? (return false) : next
end
return true
end

end
end
29 changes: 29 additions & 0 deletions refactors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
- Structure
- think about holding array of Reservations in HotelManager instead of array of Rooms Would need to rewrite methods but this would probably reduce amount of loops being used

- HotelManager
- move line 77 into a find_reservations method
- line 28 reserve_room: move room picker into its own method
- line 56 - add_block_rooms method name is not clear. Rename this to say what this method does (add block reservations to rooms)
- see if these can be moved into HotelBlock class
- add_block_room
- check_block_availability
- reserve_block_room
- list_reservations_by_room & list_reservations_by_date have a similar loop: look into making this into a reusable method
- and/or, look into combining these methods (list_reservations)room = nil, date_range = nil, date = nil)

- HotelBlock
- store reservations instead of rooms to reduce layers
- can get rid of find_reservations method by doing this

- Reservation
- Room also holds cost - remove cost & keep only total_cost in Reservation
- Change @room_number to @room and hold instance of room
- move nights to DateRange and call from there

- DateRange
- hold nights in DateRange and remove from Reservation, and call from DateRange

- Room
- remove reservations from Room if moved into HotelManager
- check_availability would need to be moved into HotelManager as well
71 changes: 71 additions & 0 deletions test/date_range_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
require_relative "test_helper"

describe "DateRange" do
before do
@date_range = Hotel::DateRange.new(Date.new(2020,5,3), Date.new(2020,5,5))
end

describe "initialize" do
it "creates an instance of DateRange" do
expect(@date_range).must_be_kind_of Hotel::DateRange
expect(@date_range).must_respond_to :start_date
expect(@date_range).must_respond_to :end_date
expect(@date_range).must_respond_to :range
end
end

describe "total_nights" do
it "should return correct total of nights for given dates" do
expect(@date_range.total_nights).must_equal 2
end
end

describe "validate_date" do
it "should return instance of DateRange if start_date and end_date are Date instances" do
expect(@date_range).must_be_kind_of Hotel::DateRange
end

it "should raise ArgumentError if one or both of start_date and end_date are not Date instances" do
date1 = Date.new(2020,5,3)
date2 = "October 24"

expect{ Hotel::DateRange.new(date1, date2) }.must_raise ArgumentError
end

it "should raise ArgumentError if start_date is before today" do
date1 = Date.new(2020,2,3)
date2 = Date.new(2020,5,5)

expect{ Hotel::DateRange.new(date1, date2) }.must_raise ArgumentError
end

it "should raise ArgumentError if end_date is before start_date" do
date1 = Date.new(2020,5,3)
date2 = Date.new(2020,5,1)

expect{ Hotel::DateRange.new(date1, date2) }.must_raise ArgumentError
end
end

describe "overlap?" do
it "should return true if dates overlap" do
date_range = Hotel::DateRange.new(Date.new(2020,5,4), Date.new(2020,5,6))
expect(@date_range.overlap?(date_range)).must_equal true
end

it "should return false if dates do not overlap" do
date_range = Hotel::DateRange.new(Date.new(2020,5,7), Date.new(2020,5,9))
expect(@date_range.overlap?(date_range)).must_equal false
end

it "returns false when check-out day of reservation is same as check-in day of new reservation" do
date_range = Hotel::DateRange.new(Date.new(2020,5,5), Date.new(2020,5,9))
expect(@date_range.overlap?(date_range)).must_equal false
end

it "returns false when check-in day of reservation is same as check-out day of new reservation" do
date_range = Hotel::DateRange.new(Date.new(2020,5,1), Date.new(2020,5,3))
expect(@date_range.overlap?(date_range)).must_equal false
end
end
end
Loading