Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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.
36 changes: 36 additions & 0 deletions lib/date_range.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require 'date'

module Hotel
class DateRange
attr_reader :start_date, :end_date

def initialize(start_date, end_date)
@start_date = start_date
@end_date = end_date
raise ArgumentError.new("This is not a valid date range!") if @end_date < @start_date
end

def overlap?(other)
# check to see if the date range itself is overlapping with "other"?
# A reservation is allowed start on the same day that another reservation for the same room ends
if self.start_date.between?(other.start_date, other.end_date - 1) || other.start_date.between?(self.start_date, self.end_date - 1)
return true
else
return false
end
end

def include?(date)
# see if the date provided is in between the date range
if date.between?(self.start_date, self.end_date - 1)
return true
else
return false
end
end

def duration
return @end_date - @start_date
end
end
end
18 changes: 18 additions & 0 deletions lib/hotel_block.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require 'date'
require 'time'
require_relative 'reservation'
require_relative 'date_range'


module Hotel
class BlockReservation
attr_reader :date_range, :status
attr_accessor :room_num , :no_of_rooms, :block_reservations

def initialize(date_range, no_of_rooms)
@date_range = date_range
@no_of_rooms = no_of_rooms
@block_reservations = Array.new
end
end
end
162 changes: 162 additions & 0 deletions lib/hotel_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
require 'date'

require_relative 'reservation'
require_relative 'date_range'
require_relative 'hotel_block'

module Hotel
class HotelController
attr_reader :reservation_list
attr_accessor :room_list, :specific_date_reservation, :hotel_block_list

# Wave 1
# default number of room in the hotel is 20
def initialize(number_of_room = 20)
@reservation_list = Hash.new
@room_list = Array.new
@hotel_block_list = Hash.new

# added flexibilty to the number of room to have in the future
n = 1
number_of_room.times do
@room_list << "Room #{n}"
n += 1
end

end

# to get the list of rooms in the hotel
def get_room_list
return @room_list
end

def reserve_room(start_date, end_date, customer_name)
# start_date and end_date should be instances of class Date
# new data range and reservation created
# first available room assigned to the new reservation
raise ArgumentError.new("They are not the valid Date class for start_date and end_date") if (start_date.class != Date || end_date.class != Date)

Choose a reason for hiding this comment

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

Consider putting this exception raising functionality into the DateRange class.

resevation_duration = DateRange.new(start_date, end_date)
new_reservation = Reservation.new(resevation_duration, customer_name)
new_reservation.cost
reservation_id = @reservation_list.length + 1
if self.available_rooms(start_date, end_date)[0] == nil

Choose a reason for hiding this comment

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

Minor note: consider finding the available room before creating a new reservation and using this available room when instantiating the new reservation.

raise ArgumentError.new("Opps! There is no room availiable for this date range!")
else
new_reservation.room_num = self.available_rooms(start_date, end_date)[0]
end
@reservation_list[reservation_id] = new_reservation
end

def reservations(date)
specific_date_reservation = Array.new
@reservation_list.each_value do |reservation|
if reservation.date_range.include?(date)
specific_date_reservation << reservation
end
end

if specific_date_reservation.empty?
raise ArgumentError.new("There is no reservation on this day!")
else
return specific_date_reservation
end
end


def get_list_of_reservations(specific_room, start_date, end_date)
date_range_reservation_list = Array.new
check_date_range = Hotel::DateRange.new(start_date, end_date)
@reservation_list.each_value do |reservation|
if (reservation.date_range.overlap?(check_date_range) ) && (reservation.room_num == specific_room)
date_range_reservation_list << reservation
end
end
return date_range_reservation_list
end



def get_reservation_cost(reservation_id)
return self.reservation_list[reservation_id].cost
end

# Wave 2
def available_rooms(start_date, end_date)
# start_date and end_date should be instances of class Date
available_rooms_list = Array.new
occupied_rooms_list = Array.new
perferred_date_range = Hotel::DateRange.new(start_date, end_date)
@reservation_list.each_value do |reservation|
if reservation.date_range.overlap?(perferred_date_range)
occupied_rooms_list << reservation.room_num
end
end
if occupied_rooms_list.empty?
return @room_list
else
available_rooms_list = @room_list - occupied_rooms_list

Choose a reason for hiding this comment

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

Consider the fact that you don't necessarily need to check if occupied rooms are empty. @room_list - occupied_rooms_list will return the correct array whether or not occupied_rooms_list is empty. Reducing the number of tests makes your code faster and more concise.

if available_rooms_list.empty?
raise ArgumentError.new("There is no more room for you!")
else
return available_rooms_list
end
end
end

#Wave 3 Hotel Block
def create_hotel_block(start_date, end_date, number_of_rooms)
raise ArgumentError.new("They are not the valid Date class for start_date and end_date") if (start_date.class != Date || end_date.class != Date)
raise ArgumentError.new("There is not enough room!") if number_of_rooms > 5 || number_of_rooms > self.available_rooms(start_date, end_date).length
block_duration = DateRange.new(start_date, end_date)
new_hotel_block = BlockReservation.new(block_duration, number_of_rooms)
number_of_rooms.times do
block_room = self.reserve_room(block_duration.start_date, block_duration.end_date, "Hotel Block Reserve")
block_room.status = :open_hotel_block
new_hotel_block.block_reservations << block_room
end
hotel_block_id = hotel_block_list.length + 1
hotel_block_list[hotel_block_id] = new_hotel_block
return new_hotel_block
end

# check if a given block has any rooms available
# if there is available room - will return the list of rooms that are open
# else will raise argument

def check_hotel_block_list_availability(hotel_block_id)
raise ArgumentError.new("Not a valid Hotel Block ID!") if !(hotel_block_list.keys.include? hotel_block_id)
available_rooms_in_block = Array.new
hotel_block_list[hotel_block_id].block_reservations.each do |reservation|
if reservation.check_status
available_rooms_in_block << reservation.room_num
end
end

if available_rooms_in_block == []
raise ArgumentError.new("No room available in this hotel block anymore!")
else
return available_rooms_in_block
end
end

def reserve_room_hotel_block(hotel_block_id, customer_name, specific_room)
raise ArgumentError.new("Not a valid Hotel Block ID!") if !(hotel_block_list.keys.include? hotel_block_id)

error_status = true

hotel_block_list[hotel_block_id].block_reservations.each do |reservation|
# check if the specific room requested in within the hotel block and not booked by another guests
#if hotel_block_list[hotel_block_id].check_valid_room(specific_room) && reservation.check_status
if (reservation.check_valid_room(specific_room)) && (reservation.check_status)
booking_room = reservation
booking_room.customer_name = customer_name
booking_room.status = :reserved_hotel_block
error_status = false
end
end
if error_status
raise ArgumentError.new("This is not a reserved room for the hotel block guest! Or it is already reserved by another guest!")
end
end
end
end
41 changes: 41 additions & 0 deletions lib/reservation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require 'date'
require 'time'
require_relative 'reservation'
require_relative 'date_range'
require_relative 'hotel_block'

module Hotel
class Reservation
attr_reader :date_range
attr_accessor :room_num, :status, :customer_name

def initialize(date_range, customer_name)
@date_range = date_range
@room_num = nil
@customer_name = customer_name
@status = :comfirmed
@cost = nil
end

def cost
# offering discount to hotel block customers
if @customer_name == "Hotel Block Reserve"
@cost = ((@date_range.duration)* 150).to_f
elsif
# how many night times 200 per night
@cost = ((@date_range.duration)* 200).to_f
end
return @cost
end

# for hotel blocks - to check if request room is within the block
def check_valid_room(request_room)
return self.room_num == request_room
end

# for hotel blocks - to make sure it is still open for hotel block guests
def check_status
return self.status == :open_hotel_block
end
end
end
7 changes: 7 additions & 0 deletions refactors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
To refactor:
- I think some of my methods are too complicated and too much dependency within methods.
I would love to spend some time to clean that up
- try to follow the single responsibility
- Dry it up!
- would like to add more stuff in each class so it would be small methods
- maybe I should have a room class?
33 changes: 33 additions & 0 deletions test/date_range_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
require_relative 'test_helper'

describe "Date Range class" do
before do
@data_range = Hotel::DateRange.new(
start_date = Date.new(2010,03,02),
end_date = Date.new(2010,03,05)
)
@date_range_two = Hotel::DateRange.new(
start_date = Date.new(2010,03,8),
end_date = Date.new(2010,03,10)
)
@date_range_three = Hotel::DateRange.new(
start_date = Date.new(2010,03,8),
end_date = Date.new(2010,03,10)
)
end

it "is an instance of Date Range" do
expect(@data_range).must_be_kind_of Hotel::DateRange
end

describe "overlap?" do
it "will return false if the time is not overlapping" do
expect(@date_range_two.overlap?(@data_range)).must_equal false
end

it "will return true if the time is overlapping" do

Choose a reason for hiding this comment

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

These are good nominal case tests. It is important to thoroughly test the different ways that dates can overlap. See this pseudo code from the design-scaffold

  describe "overlap?" do
    before do
      start_date = Date.new(2017, 01, 01)
      end_date = start_date + 3

      @range = Hotel::DateRange.new(start_date, end_date)
    end

    it "returns true for the same range" do
      start_date = @range.start_date
      end_date = @range.end_date
      test_range = Hotel::DateRange.new(start_date, end_date)

      expect(@range.overlap?(test_range)).must_equal true
    end

    xit "returns true for a contained range" do
    end

    xit "returns true for a range that overlaps in front" do
    end

    xit "returns true for a range that overlaps in the back" do
    end

    xit "returns true for a containing range" do
    end

    xit "returns false for a range starting on the end_date date" do
    end

    xit "returns false for a range ending on the start_date date" do
    end

    xit "returns false for a range completely before" do
    end

    xit "returns false for a date completely after" do
    end
  end

  xdescribe "include?" do
    it "reutrns false if the date is clearly out" do
    end

    it "returns true for dates in the range" do
    end

    it "returns false for the end_date date" do
    end
  end

expect(@date_range_two.overlap?(@date_range_three)).must_equal true
end
end
end

Loading