Skip to content
Open
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
0cb10a8
Verify Setup for Hotel project
tofuandeve Sep 3, 2019
8687b6b
Add tests for DateRange class
tofuandeve Sep 4, 2019
445808c
Implement DateRange class
tofuandeve Sep 4, 2019
c8068b1
Add HotelSystem class to Hotel module
tofuandeve Sep 4, 2019
c5d74d1
Add test for Reservation class
tofuandeve Sep 4, 2019
8f2873a
Implement Reservation class
tofuandeve Sep 4, 2019
534f647
Add @cost as a instance variable to Reservation class and update test…
tofuandeve Sep 4, 2019
143997a
Add .gitignore to Hotel project
tofuandeve Sep 4, 2019
995c898
Implement constructor and readers and add tests for HotelSystem class
tofuandeve Sep 4, 2019
84c293a
Add SimpleCov to test_helper.rb
tofuandeve Sep 4, 2019
d906e6e
Implement make_reservation and reservation_ids methods for HotelSyste…
tofuandeve Sep 5, 2019
a5d964b
Fix naming for HotelSystem class
tofuandeve Sep 5, 2019
ad5ce90
Add create_unique_id to simplify make_reservation for HotelSystem class
tofuandeve Sep 5, 2019
33a7bf1
Implement find_reservation_by_date for HotelSystem and add tests
tofuandeve Sep 5, 2019
c625670
Implement get_reservation_total_cost method for HotelSystem class and…
tofuandeve Sep 5, 2019
193e1ad
Implement .overlap? method for DateRange class and add tests
tofuandeve Sep 5, 2019
e942693
Add tests for find_available_rooms method and update tests for make_r…
tofuandeve Sep 5, 2019
108868e
Add find_available_rooms method and update make_reservation method fo…
tofuandeve Sep 5, 2019
713ef49
Fix naming warning for get_reservation_total_cost method for HotelSys…
tofuandeve Sep 5, 2019
933482f
Refactor HotelSystem class, update make_reservation method and tests
tofuandeve Sep 5, 2019
e0ee9ba
Implement HotelBlock class and add test
tofuandeve Sep 5, 2019
247d181
Implement create_hotel_block for HotelSystem class and add tests
tofuandeve Sep 6, 2019
9417e81
Update tests for Reservation class
tofuandeve Sep 6, 2019
cdef348
Implement available_rooms_by_hotel_block method for HotelSystem class…
tofuandeve Sep 6, 2019
3dd3948
Implement reserve_room by room number for HotelSystem class and add t…
tofuandeve Sep 6, 2019
6e88015
Update Hotel project to use keyword arguments
tofuandeve Sep 6, 2019
46e5feb
Refactor Hotel project: remove all unnecessary variables out of Hotel…
tofuandeve Sep 6, 2019
7f90d6d
Fix date data for test files for Hotel project
tofuandeve Sep 8, 2019
bed1710
Update tests: remove hardcode data
tofuandeve Sep 9, 2019
b1c89c0
Update test for hotel_block_test.rb
tofuandeve Sep 9, 2019
b9dd275
Update minor naming for hotel_system.rb and hotel_block.rb
tofuandeve Sep 9, 2019
3304f14
Fix bug for find_available_rooms when hotel does not have 0 reservati…
tofuandeve Sep 9, 2019
8c666d6
Update indentation for hotel project
tofuandeve Sep 9, 2019
6c8317c
Add refactors.txt for hotel project
tofuandeve Sep 9, 2019
faaaa69
Create CLI for HotelSystem
tofuandeve Sep 29, 2019
450c973
Update unit tests to be compatible with Minitest 6
tofuandeve Oct 1, 2019
9e6b6a3
Update HotelSystem#make_reservation to raise appropriate exceptions
tofuandeve Oct 1, 2019
650e780
Update Reservation class to take in room number as argument
tofuandeve Oct 1, 2019
c463113
Add CLI for user to interact with HotelSystem
tofuandeve Oct 1, 2019
11119ac
Fix naming issue for hotel_system_test.rb
tofuandeve Oct 1, 2019
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ build-iPhoneSimulator/

# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc
coverage
.DS_Store
23 changes: 23 additions & 0 deletions lib/date_range.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require 'date'

module Hotel
class DateRange
attr_reader :start_date, :end_date

def initialize(input_start_date, input_end_date)
@start_date = input_start_date
@end_date = input_end_date
current_time = Date.today()

if (@start_date < current_time) ||
Copy link

Choose a reason for hiding this comment

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

Nice touch!

(@end_date < current_time) ||
(@end_date <= @start_date)
raise ArgumentError.new("Invalid date input: Check-in: #{input_start_date}, check_out: #{input_end_date}")
end
end

def overlap?(date_range)
return @start_date < date_range.end_date && @end_date > date_range.start_date
end
end
end
19 changes: 19 additions & 0 deletions lib/hotel_block.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Hotel
class HotelBlock
MAX_NUMBER_OF_ROOMS = 5
@@current_id = 0
attr_reader :id, :rooms, :discount_rate, :date_range

def initialize(rooms:, date_range:, discount_rate:)
@@current_id += 1
@id = @@current_id
@rooms = rooms.dup
@date_range = date_range
@discount_rate = discount_rate

if rooms.length <= 0 || rooms.length > MAX_NUMBER_OF_ROOMS
raise ArgumentError.new("Can only add up to #{MAX_NUMBER_OF_ROOMS} rooms to a block!")
end
end
end
end
137 changes: 137 additions & 0 deletions lib/hotel_system.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
module Hotel
class HotelSystem
RATE = 200.00
NUMBER_OF_ROOMS = 20
DISCOUNT = 0.20

attr_reader :hotel_blocks, :rooms

def initialize(input_number_of_rooms = NUMBER_OF_ROOMS)
@room_reservation_data = Hash.new
input_number_of_rooms.times do |index|
@room_reservation_data[(index + 1)] = Array.new
end
@rooms = @room_reservation_data.keys
@hotel_blocks = Array.new
end

def number_of_rooms
return NUMBER_OF_ROOMS
end

def reservations
return @room_reservation_data.values.flatten
end

def make_reservation(start_date, end_date)
date_range = DateRange.new(start_date, end_date)
available_rooms = find_available_rooms(date_range)

if available_rooms.empty?
raise ArgumentError.new("No rooms available in this date range: #{start_date} - #{end_date}!")
end

reservation = create_reservation(date_range, RATE)
@room_reservation_data[available_rooms.first] << reservation
end

def find_reservation_by_date(date)
output = reservations.select do |reservation|
(reservation.date_range.start_date <= date) &&
(date < reservation.date_range.end_date)
end
return output
end

def get_reservation_total_cost(reservation_id)
output_reservation = reservations.find { |reservation| reservation.id == reservation_id }
if !output_reservation
return nil
end
return output_reservation.cost
end

def find_available_rooms(date_range)
raise ArgumentError.new('Date range cannot be nil') if !date_range

blocked_rooms = find_overlapping_rooms_in_hotel_blocks(date_range)
available_rooms = @rooms.select do |number|
!has_overlapping(@room_reservation_data[number], date_range) &&
!blocked_rooms.include?(number)
Copy link

Choose a reason for hiding this comment

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

This select is clever!

end
return available_rooms
end

def create_hotel_block(rooms:, date_range:, discount: DISCOUNT)
if rooms == nil ||
rooms.uniq != rooms ||
rooms.any? { |room| [email protected]?(room)}

raise ArgumentError.new("Rooms cannot be duplicate or nil")
end

available_rooms = find_available_rooms(date_range)
unavailable_room = rooms.find { |room| !available_rooms.include?(room) }
if unavailable_room
raise ArgumentError.new(
"Room number #{unavailable_room} is not available on this date range!"
)
end

hotel_block = create_block(rooms: rooms, date_range: date_range, discount: discount)
@hotel_blocks << hotel_block
end

def available_rooms_in_block(block_id)
hotel_block = @hotel_blocks.find do |block|
block.id == block_id
end

raise ArgumentError.new("Block #{block_id} doesn't exist") if !hotel_block
return hotel_block.rooms
end

def reserve_room(room_number)
hotel_block_index = find_block_index(room_number)
if !hotel_block_index
raise ArgumentError.new("Room #{room_number} doesn't belong to any block")
end

block = @hotel_blocks[hotel_block_index]

# add make new reservation for the input room
reservation = create_reservation(block.date_range, RATE * (1 - block.discount_rate))
@room_reservation_data[room_number] << reservation

# remove room out of block's room list
@hotel_blocks[hotel_block_index].rooms.delete(room_number)
end

private
def has_overlapping(reservations, date_range)
return reservations.any? {|reservation| reservation.date_range.overlap?(date_range) }
end

def find_overlapping_rooms_in_hotel_blocks(date_range)
blocked_rooms = Array.new
@hotel_blocks.each do |block|
if block.date_range.overlap?(date_range)
blocked_rooms += block.rooms
end
end
return blocked_rooms
end

def find_block_index(room_number)
return @hotel_blocks.find_index { |block| block.rooms.include?(room_number)}
end

def create_reservation(date_range, rate)
return Reservation.new(date_range: date_range, rate: rate)
end

def create_block(rooms:, date_range:, discount:)
return HotelBlock.new(rooms: rooms, date_range: date_range, discount_rate: discount)
end
end
end
14 changes: 14 additions & 0 deletions lib/reservation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Hotel
class Reservation
@@current_id = 0
attr_reader :id, :date_range, :rate, :cost

def initialize(date_range:, rate:)
@@current_id += 1
@date_range = date_range
@rate = rate
@id = @@current_id
@cost = (date_range.start_date - date_range.end_date).abs * rate
end
end
end
10 changes: 10 additions & 0 deletions refactors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
1. Naming:
- Replacing start_date with checkin_date, end_date with checkout_date.
- Find a better name for @room_reservation_data

2. Implementation
- Refactor HotelSystem class to reduce dependency on other classes (DateRange, HotelBlock, Reservation)
- Should HotelBlock be removed?
- Should there be a Rate class? or Room class where rate will be passed in to constructor as argument?
- Implement read_data() and write_data() methods for @room_reservation_data and @hotel_blocks
- Create main.rb to interact with HotelSystem
65 changes: 65 additions & 0 deletions test/date_range_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
require_relative 'test_helper'

describe Hotel::DateRange do
before do
@current_date = Date.today()
@duration = 10

@start_date = @current_date + 30
@end_date = @start_date + @duration
@date_range = Hotel::DateRange.new(@start_date, @end_date)
end
describe "Constructor" do
it "can construct a DateRange object" do
expect (@date_range).must_be_instance_of Hotel::DateRange
end

it "raises ArgumentError for invalid start date and end date" do
invalid_start_date = @end_date + 10
invalid_end_date = @start_date - 10
invalid_past_date = @current_date - 10

expect {Hotel::DateRange.new(invalid_start_date, @end_date)}.must_raise ArgumentError
expect {Hotel::DateRange.new(@start_date, invalid_end_date)}.must_raise ArgumentError
expect {Hotel::DateRange.new(invalid_past_date, @end_date)}.must_raise ArgumentError
end
end

describe "overlap? method" do
it "returns true if 2 date ranges overlap" do
start_date1 = @start_date - 1
end_date1 = @end_date - 1
date1 = Hotel::DateRange.new(start_date1, end_date1)

start_date2 = @start_date + 1
end_date2 = @end_date - 1
date2 = Hotel::DateRange.new(start_date2, end_date2)

start_date3 = @start_date + 1
end_date3 = @end_date + 1
date3 = Hotel::DateRange.new(start_date3, end_date3)

expect (@date_range.overlap?(date1)).must_equal true
expect (@date_range.overlap?(date2)).must_equal true
expect (@date_range.overlap?(date3)).must_equal true
end

it "returns false if 2 date ranges don't overlap" do
start_date1 = @start_date - 10
end_date1 = start_date1 + 5
date1 = Hotel::DateRange.new(start_date1, end_date1)

start_date2 = @end_date + 5
end_date2 = start_date2 + 5
date2 = Hotel::DateRange.new(start_date2, end_date2)

start_date3 = @start_date + 15
end_date3 = start_date3 + 5
date3 = Hotel::DateRange.new(start_date3, end_date3)

expect (@date_range.overlap?(date1)).must_equal false
expect (@date_range.overlap?(date2)).must_equal false
expect (@date_range.overlap?(date3)).must_equal false
end
end
end
30 changes: 30 additions & 0 deletions test/hotel_block_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
require_relative 'test_helper'

describe Hotel::HotelBlock do
before do
current_date = Date.today()
duration = 10

start_date = current_date + 30
end_date = start_date + duration
@date_range = Hotel::DateRange.new(start_date, end_date)
@discount_rate = 0.2
end
describe "Constructor" do
it "can create a HotelBlock object for valid input" do
rooms = [2, 3, 4]
hotel_block = Hotel::HotelBlock.new(
rooms: rooms, date_range: @date_range, discount_rate: @discount_rate
)

expect (hotel_block).must_be_instance_of Hotel::HotelBlock
end

it "raises ArgumentError if list of rooms has more than 5 rooms" do
rooms = [2, 3, 4, 5, 6, 7]
expect{Hotel::HotelBlock.new(
rooms: rooms, date_range: @date_range, discount_rate: @discount_rate
)}.must_raise ArgumentError
end
end
end
Loading