Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2446ce0
Added class DateRange to Hotel, wrote and passed tests for initialize…
saintmedusa Mar 3, 2020
3aa96d6
In DateRage and date_range_tests: Added methods include?, num_nights …
saintmedusa Mar 4, 2020
b444395
Changed string argument > Date.parse case in date_range constructor t…
saintmedusa Mar 4, 2020
5d85ff3
Created class Reservation and its init, with tests in reservation_tes…
saintmedusa Mar 4, 2020
2dad181
Expanded error checking for invalid dates in constructor
saintmedusa Mar 4, 2020
d30f7d9
fixed error in DateRange left in last commit
saintmedusa Mar 5, 2020
07a200f
Front desk scaffolding and init, with basic tests
saintmedusa Mar 5, 2020
e0bd4f0
forgot to save front_desk.rb before last commit, lol
saintmedusa Mar 5, 2020
b730bc2
Added new class Room, with methods #available? and #add. Wrote tests …
saintmedusa Mar 5, 2020
a09d065
Added method #reserve_room(start_date, end_date) to FrontDesk, with p…
saintmedusa Mar 5, 2020
093c309
Successfully implemented Room#get_reservations(start_date, end_date)
saintmedusa Mar 6, 2020
6aa96a4
Changed Room#available? param to date_range instead of reservation (f…
saintmedusa Mar 6, 2020
c22e16d
added FrontDesk#get_reservations(date) with passing tests
saintmedusa Mar 6, 2020
0169121
Added two tests for FrontDesk#reserve_room - raises argument error wh…
saintmedusa Mar 6, 2020
6e549b9
Added files test/block_test.rb and lib/block.rb, basic formatting to …
saintmedusa Mar 6, 2020
0ebed56
Added constructor and method scafolding to Block, added optional para…
saintmedusa Mar 7, 2020
feaf784
Further fleshed out Block constructor and completed Block#reserve(roo…
saintmedusa Mar 7, 2020
be30060
added test: block overlap, and refactored Block@available_rooms - rem…
saintmedusa Mar 7, 2020
f0fe0af
Added Room@room_rate. Refactored Room#add and FrontDesk#reserve_room …
saintmedusa Mar 7, 2020
37b5c9e
Formatting, removing shadow variables, addressing instance variable a…
saintmedusa Mar 7, 2020
e7c6b57
final formatting and added file refactor.txt
saintmedusa Mar 9, 2020
d2a9a6e
using range to create rooms
saintmedusa Mar 15, 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.
47 changes: 47 additions & 0 deletions lib/block.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module Hotel
class Block < DateRange
attr_reader :reservations, :rate
def initialize(start_date, end_date, rooms, rate)
if rooms.length > 5
raise ArgumentError.new("Blocks can only be made for 5 rooms or less.")
end
super(start_date, end_date)
range = DateRange.new(start_date, end_date)
if rooms.any? { |room| !(room.available?(range))}
raise ArgumentError.new("One or more of the rooms is not available at given date range.")
end
@rate = rate
@reservations = []
@available_rooms = rooms
@available_rooms.each do |room|
room.add(self)
end
end

def reserve(room)
if !(@available_rooms.include?(room))
raise ArgumentError.new("Room #{room.id} is not in this Block.")
end
if @available_rooms.all?{|r| r == nil}
raise ArgumentError.new("All rooms in block are already reserved.")
end
new_res = Reservation.new(start_date, end_date, room.id, rate)
self.reservations << new_res

# finds the block in room's reservations, turns it into a reservation
i = room.reservations.find_index {|reservation|
reservation.nights == self.nights
}
room.reservations[i] = new_res
j = @available_rooms.find_index {|r|
r == room
}
@available_rooms[j] = nil
end

def available_rooms
return @available_rooms.find_all {|room| room != nil}
end

end
end
49 changes: 49 additions & 0 deletions lib/date_range.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require 'date'
module Hotel
class InvalidDateError < StandardError
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nice use of a custom exception.


end
class DateRange
attr_reader :start_date, :end_date, :nights

def initialize(start_date, end_date)
if !(start_date.instance_of?(Date) || end_date.instance_of?(Date))
raise InvalidDateError.new("End and start dates must be instances of Date.")
else
@start_date = start_date
@end_date = end_date
end
if @end_date - @start_date <= 0
raise InvalidDateError.new("End date must be after start date.")
end
@nights = Array.new((@end_date - @start_date).to_i)
@nights[0] = @start_date
index = 1

while @nights.last == nil
@nights[index] = @start_date + index
index += 1
end

end

def overlap?(other)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I like your design choice to have Reservation and Block inherit from DateRange. I think I understand your logic here. Front_desk will invoke overlap? on instances of reservation with date_range as the argument, yea? Given that you're using the method in a child class (reservation), but other is a DateRange, you may consider adding a comment to explain this use case to increase readability. Also, correct me if I'm mis-understanding your logic.

other.nights.each do |night|
if self.include? night
return true
end
end
return false
end


def include?(date)
return nights.include? date
end

def num_nights
return nights.length
end

end
end
56 changes: 56 additions & 0 deletions lib/front_desk.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
module Hotel
class FrontDesk
attr_reader :rooms
def initialize
@rooms = []
# Refactor: custom range - rooms. Rooms include Comparable, and implement succ and <=>
# See range doc
(1..20).each do |n|
@rooms << Room.new(n)
end
end

def reserve_room(start_date, end_date)
date_range = Hotel::DateRange.new(start_date, end_date)
room = find_room(date_range)
return room.add(date_range)
end

def get_avail_rooms(start_date, end_date)
date_range = Hotel::DateRange.new(start_date, end_date)
avail_rooms = rooms.find_all { |room|
room.available?(date_range)
}
return avail_rooms
end

def get_reservations(date)
reservations_at_date = []
rooms.each do |room|
room.reservations.each do |reservation|
if reservation.include?(date) && reservation.class != Block
reservations_at_date << reservation
end
end
end
return reservations_at_date
end

private
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nice use of a private helper method.

def find_room(date_range)
room = rooms.find {|r|
r.reservations.length == 0
}
if room == nil
room = rooms.find {|r|
r.available?(date_range)
}
end
if room == nil
raise ArgumentError.new("No rooms are availble in that date range.")
end
return room
end

end
end
11 changes: 11 additions & 0 deletions lib/reservation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require_relative 'date_range'
module Hotel
class Reservation < DateRange
attr_reader :cost, :room
def initialize(start_date, end_date, room, rate= 200)
super(start_date, end_date)
@room = room
@cost = self.num_nights * rate
end
end
end
46 changes: 46 additions & 0 deletions lib/room.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module Hotel
class Room
attr_reader :id, :reservations, :room_rate

def initialize(id, room_rate=200)
@id = id
@reservations = []
@room_rate = room_rate
end

# is available for a specific reservation or a general date range
def available?(date_range)
if reservations.length == 0
return true
end
if reservations.any? {|r| r.overlap?(date_range)}
return false
else
return true
end
end

def add(date_range)
if date_range.class != Reservation && date_range.class != Block
reservation = Reservation.new(date_range.start_date, date_range.end_date, self.id, room_rate)
else
reservation = date_range
end
if self.available?(reservation)
@reservations << reservation
else
raise ArgumentError.new("Room #{self.id} isn't available for that reservation.")
end
return reservation
end

def get_reservations(start_date, end_date)
range = DateRange.new(start_date, end_date)
resv_within = reservations.find_all {|reservation|
reservation.nights.all? {|night| range.include?(night)}
}
return resv_within
end

end
end
4 changes: 4 additions & 0 deletions refactor.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
* Create consistent convention for when to use date_range or start_date, end_date as parameters
* Create RoomNotAvailableError Class
* Map out everywhere that Room#availble? is used - there is redundancy here.
* Figure out why block_test.rb is not included in coverage file
Binary file added test/.DS_Store
Binary file not shown.
109 changes: 109 additions & 0 deletions test/block_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
require_relative "test_helper"

describe Hotel::Block do
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

These tests are really comprehensive. Nice work!

before do
@fd = Hotel::FrontDesk.new
@rooms = @fd.rooms.slice(0,5)
@start = Date.new(2020, 01, 01)
@end = Date.new(2020, 01, 07)
@rate = 153
end

describe "constructor" do
describe "has all the expected state" do
it "rooms" do
block = Hotel::Block.new(@start, @end, @rooms, @rate)
expect(block.available_rooms).must_be_kind_of Array
avail_rooms = block.available_rooms
avail_rooms.each_with_index do |room, i|
expect(room).must_equal @rooms[i]
end
end
it "reservations" do
block = Hotel::Block.new(@start, @end, @rooms, @rate)
expect(block.reservations).must_be_kind_of Array
end
end
it "raises error if a room in rooms is not available" do
@rooms[4].add(Hotel::Reservation.new(@start, @end, 5, 150))
expect{Hotel::Block.new(@start, @end, @rooms, @rate)}.must_raise ArgumentError
end
it "raises an error if rooms is > 5" do
@rooms << Hotel::Room.new(6)
expect{Hotel::Block.new(@start, @end, @rooms, @rate)}.must_raise ArgumentError
end
it "reflects changes in rooms included in block" do
block = Hotel::Block.new(@start, @end, @rooms, @rate)
@rooms.each do |room|
expect(room.reservations.include?(block)).must_equal true
end
end

end

describe "reserve(room)" do
it "raises error if attempting to reserve a room not in block" do
block = Hotel::Block.new(@start, @end, @rooms, @rate)
expect{block.reserve(Hotel::Room.new(20))}.must_raise ArgumentError
end

it "reflects changes in class state: reservations" do
block = Hotel::Block.new(@start, @end, @rooms, @rate)
@rooms.each do |room|
block.reserve(room)
end
block.reservations.each_with_index do |reservation, i|
expect(reservation.room).must_equal i + 1
end
end

it "reserved room no longer has the block in their reservations, but a reservation instead" do
block = Hotel::Block.new(@start, @end, @rooms, @rate)
@rooms.each do |room|
block.reserve(room)
expect(room.reservations.any?(Hotel::Block)).must_equal false
end

end
it "won't let another block be formed on the same rooms with overlapping range" do
Hotel::Block.new(@start, @end, @rooms, @rate)
start2 = Date.new(2020, 01, 03)
end2 = Date.new(2020, 01, 15)
expect{Hotel::Block.new(start2, end2, @rooms, @rate)}.must_raise ArgumentError
end
it "won't erase another block in making room's block>reservation change" do
block = Hotel::Block.new(@start, @end, @rooms, @rate)
start2 = Date.new(2020, 02, 01)
end2 = Date.new(2020, 02, 28)
block2 = Hotel::Block.new(start2, end2, @rooms, @rate)
@rooms.each do |room|
block.reserve(room)
expect(room.reservations.find{|r| r.class == Hotel::Block}).must_equal block2
end
end
it "removes room from available_rooms" do
block = Hotel::Block.new(@start, @end, @rooms, @rate)
@rooms.each_with_index do |room, i|
block.reserve(room)
expect(block.available_rooms.any?{|r| r == room }).must_equal false
end
end
it "effectively adds discounted rate to reservation" do
block = Hotel::Block.new(@start, @end, @rooms, @rate)
@rooms.each_with_index do |room, i|
block.reserve(room)
end
block.reservations.each do |r|
expect(r.cost % 153 == 0).must_equal true
end
end
it "raises error if all rooms are booked" do
block = Hotel::Block.new(@start, @end, @rooms, @rate)
@rooms.each_with_index do |room, i|
block.reserve(room)
end
expect{block.reserve(@rooms[0])}.must_raise ArgumentError
end
end

end
Loading