From c90c20d44e26895baff86200dc8eb20592306f09 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Tue, 5 Sep 2017 13:28:51 -0700 Subject: [PATCH 01/26] Set up project and test files --- Rakefile | 9 +++++++++ lib/reservation.rb | 0 lib/room.rb | 0 specs/reservation_spec.rb | 1 + specs/room_spec.rb | 1 + specs/spec_helper.rb | 14 ++++++++++++++ 6 files changed, 25 insertions(+) create mode 100644 Rakefile create mode 100644 lib/reservation.rb create mode 100644 lib/room.rb create mode 100644 specs/reservation_spec.rb create mode 100644 specs/room_spec.rb create mode 100644 specs/spec_helper.rb diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..f4f704fca --- /dev/null +++ b/Rakefile @@ -0,0 +1,9 @@ +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.libs = ["lib"] + t.warning = false + t.test_files = FileList['specs/*_spec.rb'] +end + +task default: :test diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..e69de29bb diff --git a/lib/room.rb b/lib/room.rb new file mode 100644 index 000000000..e69de29bb diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb new file mode 100644 index 000000000..95fb705ac --- /dev/null +++ b/specs/reservation_spec.rb @@ -0,0 +1 @@ +require_relative 'reservation_spec' diff --git a/specs/room_spec.rb b/specs/room_spec.rb new file mode 100644 index 000000000..ae9c220ea --- /dev/null +++ b/specs/room_spec.rb @@ -0,0 +1 @@ +require_relative 'spec_helper' diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 000000000..1408ddb4e --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,14 @@ +require 'simplecov' +SimpleCov.start + +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/skip_dsl' + +require_relative '../lib/room' +require_relative '../lib/reservation' + +reporter_options = { color:true} +Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new(reporter_options) + +# Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new From 5921835a4597bb96a72559121d2051ce448948c1 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Tue, 5 Sep 2017 14:18:32 -0700 Subject: [PATCH 02/26] Set up initialize and self.all (and tests) for Room class --- lib/room.rb | 44 +++++++++++++++++++++++++++++++++++++++ specs/room_spec.rb | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/lib/room.rb b/lib/room.rb index e69de29bb..6ad06d676 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -0,0 +1,44 @@ +require_relative 'reservation' + +module Hotel + + NUM_ROOMS = 20 + + class Room + + DEFAULT_RATE = 200 + + attr_reader :room_num + attr_accessor :rate + + def initialize(room_num, rate = DEFAULT_RATE) + + if valid_room_num?(room_num) + @room_num = room_num + else + raise ArgumentError.new("Not a valid room number") + end + + @rate = rate + end + + def self.all + # create a list of all hotel rooms + all_rooms = [] + + (1..NUM_ROOMS).each do |num| + all_rooms << Room.new(num) + end + + return all_rooms + end + + private + + def valid_room_num?(num) + return num.class == Integer && num >= 1 && num <= 20 + end + + end # end of Room class + +end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index ae9c220ea..38e0eb58a 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -1 +1,52 @@ require_relative 'spec_helper' + +describe "Testing Room class" do + describe "#initialize" do + before do + @room = Hotel::Room.new(4) + end + + it "Creates a Room object" do + @room.must_be_instance_of Hotel::Room + end + + it "Sets a default rate if no rate provided" do + @room.rate.must_equal Hotel::Room::DEFAULT_RATE + end + + it "Raises an error if room number isn't between 1 & 20" do + proc { Hotel::Room.new(0) }.must_raise ArgumentError + proc { Hotel::Room.new(-2) }.must_raise ArgumentError + proc { Hotel::Room.new(21) }.must_raise ArgumentError + end + + it "Raises an error if room number isn't an integer" do + proc { Hotel::Room.new("cat") }.must_raise ArgumentError + proc { Hotel::Room.new(4.23) }.must_raise ArgumentError + proc { Hotel::Room.new(nil) }.must_raise ArgumentError + end + + end + + describe "#self.all" do + before do + @all_rooms = Hotel::Room.all + end + + it "Returns a list of all the rooms in the hotel" do + @all_rooms.must_be_kind_of Array + @all_rooms.length.must_equal Hotel::NUM_ROOMS + end + + it "Each hotel must have a different number between 1 & NUM_ROOMS" do + room_nums = (1..Hotel::NUM_ROOMS).to_a + + @all_rooms.each do |room| + room_nums.delete(room.room_num) + end + + room_nums.must_equal [] + end + + end +end From 7152f16db0ffa5c3f7e638a201b88748e2b3e08a Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Tue, 5 Sep 2017 15:58:49 -0700 Subject: [PATCH 03/26] Initialized Reservation class (with tests) --- lib/reservation.rb | 22 ++++++++++++++++++++++ specs/reservation_spec.rb | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index e69de29bb..3722b9597 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -0,0 +1,22 @@ +require 'date' +require_relative 'room' + +module Hotel + + class Reservation + attr_accessor :check_in, :check_out, :room_num + + def initialize(check_in, check_out, room_num) + + # check input + raise ArgumentError.new("Check out must be later than check in") if check_in >= check_out + + @check_in = check_in + @check_out = check_out + @room_num = room_num + + end + + + end # end of Reservation class +end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 95fb705ac..fd09c91c0 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -1 +1,35 @@ -require_relative 'reservation_spec' +require_relative 'spec_helper' + +describe "Testing Reservation class" do + describe "#initialize" do + before do + @res = Hotel::Reservation.new(Date.new(2017,9,4), Date.new(2017,9,7), 4) + end + + it "Creates a Reservation with a date range and room number" do + @res.check_in.must_be_instance_of Date + @res.check_out.must_be_instance_of Date + @res.room_num.must_be_kind_of Integer + end + + it "Raises an error if check_out date isn't later than check_in date" do + check_in = Date.new(2017,9,5) + check_out = Date.new(2017,8,5) + + proc { Hotel::Reservation.new(check_in, check_out, 2) }.must_raise ArgumentError + + check_out = Date.new(2017,9,5) + proc { Hotel::Reservation.new(check_in, check_out, 2) }.must_raise ArgumentError + end + + # it "Raises an error if room num isn't a valid num" do + # invalid_nums = ["cat", nil, 3.14, -1, 0, Hotel::NUM_ROOMS + 1] + # check_in = Date.new(2017,9,5) + # check_out = Date.new(2017,9,8) + # + # invalid_nums.each do |not_num| + # proc { Hotel::Reservation.new(check_in, check_out, not_num) }.must_raise ArgumentError + # end + # end + end +end From 42d4a854fc2d8b061f1a5fa3a7d959779451cc10 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Tue, 5 Sep 2017 16:10:25 -0700 Subject: [PATCH 04/26] Added reserve method to Room class --- lib/room.rb | 9 ++++++-- specs/room_spec.rb | 49 ++++++++++++++++++++++++++++++++++++-------- specs/spec_helper.rb | 1 + 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/lib/room.rb b/lib/room.rb index 6ad06d676..8a11671ed 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -8,7 +8,7 @@ class Room DEFAULT_RATE = 200 - attr_reader :room_num + attr_reader :room_num, :reservations attr_accessor :rate def initialize(room_num, rate = DEFAULT_RATE) @@ -19,6 +19,7 @@ def initialize(room_num, rate = DEFAULT_RATE) raise ArgumentError.new("Not a valid room number") end + @reservations = [] @rate = rate end @@ -26,13 +27,17 @@ def self.all # create a list of all hotel rooms all_rooms = [] - (1..NUM_ROOMS).each do |num| + (1..Hotel::NUM_ROOMS).each do |num| all_rooms << Room.new(num) end return all_rooms end + def reserve(start_date, end_date) + @reservations << Hotel::Reservation.new(start_date, end_date, @room_num) + end + private def valid_room_num?(num) diff --git a/specs/room_spec.rb b/specs/room_spec.rb index 38e0eb58a..65b67c6e1 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -14,18 +14,26 @@ @room.rate.must_equal Hotel::Room::DEFAULT_RATE end - it "Raises an error if room number isn't between 1 & 20" do - proc { Hotel::Room.new(0) }.must_raise ArgumentError - proc { Hotel::Room.new(-2) }.must_raise ArgumentError - proc { Hotel::Room.new(21) }.must_raise ArgumentError - end + it "Raises an error if room number isn't valid num" do + invalid_nums = ["cat", 31.4, nil, 0, -1, Hotel::NUM_ROOMS + 1] - it "Raises an error if room number isn't an integer" do - proc { Hotel::Room.new("cat") }.must_raise ArgumentError - proc { Hotel::Room.new(4.23) }.must_raise ArgumentError - proc { Hotel::Room.new(nil) }.must_raise ArgumentError + invalid_nums.each do |item| + proc { Hotel::Room.new(item) }.must_raise ArgumentError + end end + # it "Raises an error if room number isn't between 1 & 20" do + # proc { Hotel::Room.new(0) }.must_raise ArgumentError + # proc { Hotel::Room.new(-2) }.must_raise ArgumentError + # proc { Hotel::Room.new(21) }.must_raise ArgumentError + # end + # + # it "Raises an error if room number isn't an integer" do + # proc { Hotel::Room.new("cat") }.must_raise ArgumentError + # proc { Hotel::Room.new(4.23) }.must_raise ArgumentError + # proc { Hotel::Room.new(nil) }.must_raise ArgumentError + # end + end describe "#self.all" do @@ -49,4 +57,27 @@ end end + + describe "#reserve" do + before do + @room = Hotel::Room.new(3) + @check_in = Date.new(2017,9,5) + @check_out = Date.new(2017,9,8) + + @room.reserve(@check_in, @check_out) + end + + it "Adds the reservation to the room's reservations array" do + @room.reservations.length.must_equal 1 + @room.reservations[0].must_be_kind_of Hotel::Reservation + end + + it "Reserves the room for the specified start and end dates" do + res = @room.reservations[0] + + res.check_in.must_equal @check_in + res.check_out.must_equal @check_out + end + + end end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb index 1408ddb4e..83249ca9b 100644 --- a/specs/spec_helper.rb +++ b/specs/spec_helper.rb @@ -4,6 +4,7 @@ require 'minitest/autorun' require 'minitest/reporters' require 'minitest/skip_dsl' +require 'date' require_relative '../lib/room' require_relative '../lib/reservation' From b7550c52350187043531c91eae060f63d43cf1e0 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Tue, 5 Sep 2017 19:24:30 -0700 Subject: [PATCH 05/26] Added hotel class --- lib/hotel.rb | 33 +++++++++++++++++++++++++++++++++ lib/reservation.rb | 10 ++++++++++ lib/room.rb | 17 ++++++++++++++++- specs/hotel_spec.rb | 39 +++++++++++++++++++++++++++++++++++++++ specs/reservation_spec.rb | 35 ++++++++++++++++++++++++++--------- specs/room_spec.rb | 12 ++++++++++++ specs/spec_helper.rb | 1 + 7 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 lib/hotel.rb create mode 100644 specs/hotel_spec.rb diff --git a/lib/hotel.rb b/lib/hotel.rb new file mode 100644 index 000000000..847a32969 --- /dev/null +++ b/lib/hotel.rb @@ -0,0 +1,33 @@ +require_relative 'room' +require_relative 'reservation' + +module Hotel + + class Hotel + + NUM_ROOMS = 20 + + attr_reader :rooms + + def initialize(num_rooms = NUM_ROOMS) + # check input + raise ArgumentError.new("Not a valid number of rooms") if !is_valid?(num_rooms) + + @rooms = [] + + # loop through num_rooms and add rooms to array + (1..num_rooms).each do |num| + @rooms << ::Hotel::Room.new(num) + end + + end + + private + + def is_valid?(num) + return num.is_a?(Integer) && num > 0 + end + + end # end of Hotel class + +end diff --git a/lib/reservation.rb b/lib/reservation.rb index 3722b9597..6d52ad71d 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -17,6 +17,16 @@ def initialize(check_in, check_out, room_num) end + def self.find(date) + # returns a list of all reservations for given date + # does not include reservations where check-out date == date + end + + def total_cost + num_nights = (@check_out - @check_in).to_i + return num_nights * ::Hotel::Room::DEFAULT_RATE + end + end # end of Reservation class end diff --git a/lib/room.rb b/lib/room.rb index 8a11671ed..3b47f0d7f 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -35,7 +35,9 @@ def self.all end def reserve(start_date, end_date) - @reservations << Hotel::Reservation.new(start_date, end_date, @room_num) + # add reservation if room is available and return true; else false + #if is_available + @reservations << ::Hotel::Reservation.new(start_date, end_date, @room_num) end private @@ -44,6 +46,19 @@ def valid_room_num?(num) return num.class == Integer && num >= 1 && num <= 20 end + # def is_available?(start_date, end_date) + # @reservations.each do |reservation| + # check_in = reservation.check_in + # check_out = reservation.check_out + # + # if date >= check_in && date < check_out + # return false + # end + # end + # + # return true + # end + end # end of Room class end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb new file mode 100644 index 000000000..4eda127fc --- /dev/null +++ b/specs/hotel_spec.rb @@ -0,0 +1,39 @@ +require_relative 'spec_helper' + +describe "Testing Hotel class" do + describe "#initialize" do + before do + @hotel = Hotel::Hotel.new + end + + it "Creates a hotel class with an array of rooms" do + @hotel.must_be_instance_of Hotel::Hotel + + rooms = @hotel.rooms + rooms.must_be_instance_of Array + + rooms.each do |room| + room.must_be_instance_of Hotel::Room + end + end + + it "Creates a hotel with NUM_ROOMS num of rooms as the default" do + @hotel.rooms.length.must_equal Hotel::Hotel::NUM_ROOMS + end + + it "Creates a hotel with the specified number of rooms" do + num_rooms = 17 + new_hotel = Hotel::Hotel.new(num_rooms) + new_hotel.rooms.length.must_equal num_rooms + end + + it "Raises an error if not passed a valid number for num of rooms" do + invalid_nums = [-1, 0, "dog", 3.14, nil, ""] + + invalid_nums.each do |item| + proc { Hotel::Hotel.new(item) }.must_raise ArgumentError + end + end + + end +end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index fd09c91c0..603738765 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -22,14 +22,31 @@ proc { Hotel::Reservation.new(check_in, check_out, 2) }.must_raise ArgumentError end - # it "Raises an error if room num isn't a valid num" do - # invalid_nums = ["cat", nil, 3.14, -1, 0, Hotel::NUM_ROOMS + 1] - # check_in = Date.new(2017,9,5) - # check_out = Date.new(2017,9,8) - # - # invalid_nums.each do |not_num| - # proc { Hotel::Reservation.new(check_in, check_out, not_num) }.must_raise ArgumentError - # end - # end end + + describe "total_cost" do + before do + @check_in = Date.new(2017,9,5) + @check_out = Date.new(2017,9,8) + @res = Hotel::Reservation.new(@check_in, @check_out, 4) + end + + it "Returns the total cost of the reservation" do + num_nights = (@check_out - @check_in).to_i + expected_cost = num_nights * (Hotel::Room::DEFAULT_RATE) + + @res.total_cost.must_equal expected_cost + end + + end + + # describe "#self.find" do + # before do + # date_to_check = Date.new(2017,9,5) + # end + # + # it "Returns a list of Reservations for a given date" do + # + # end + # end end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index 65b67c6e1..d08500f81 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -79,5 +79,17 @@ res.check_out.must_equal @check_out end + # it "Returns true if the room is added" do + # @room.reserve(Date.new(2017,8,5), Date.new(2017,8,8)).must_equal true + # @room.reservations.length.must_equal 2 + # end + # + # it "Doesn't reserve the room if the room isn't available" do + # # bad_res = @room.reserve(@check_in, @check_out) + # # bad_res.must_equal false + # @room.reserve(@check_in, @check_out).must_equal false + # @room.reservations.length.must_equal 1 + # end + end end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb index 83249ca9b..401b00c93 100644 --- a/specs/spec_helper.rb +++ b/specs/spec_helper.rb @@ -8,6 +8,7 @@ require_relative '../lib/room' require_relative '../lib/reservation' +require_relative '../lib/hotel' reporter_options = { color:true} Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new(reporter_options) From 2fca0c90f9b53ae9c65aca93e4b837316749150c Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Tue, 5 Sep 2017 21:01:30 -0700 Subject: [PATCH 06/26] Implemented all_reservations metho in hotel and added more error checking in tests --- lib/hotel.rb | 23 +++++++++++++++++++++++ lib/reservation.rb | 37 ++++++++++++++++++++++++++++++++++--- specs/hotel_spec.rb | 27 +++++++++++++++++++++++++++ specs/reservation_spec.rb | 18 ++++++++++++++++-- 4 files changed, 100 insertions(+), 5 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 847a32969..8251610eb 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -22,6 +22,29 @@ def initialize(num_rooms = NUM_ROOMS) end + def reserve(start_date, end_date, room) + # TODO check if available and return true if added; else false + + room.reserve(start_date, end_date) + + end + + def all_reservations + # returns a list of all reservations for the hotel + reservations = [] + + @rooms.each do |room| + reservations << room.reservations + end + + return reservations + end + + def find_reservations_by_date(date) + # returns a list of all reservations for the given date + # doesn't include rooms where check-out date == date + end + private def is_valid?(num) diff --git a/lib/reservation.rb b/lib/reservation.rb index 6d52ad71d..33c8bc0ba 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -4,11 +4,18 @@ module Hotel class Reservation + include Comparable + attr_accessor :check_in, :check_out, :room_num def initialize(check_in, check_out, room_num) # check input + check_in = check_date(check_in) + check_out = check_date(check_out) + + raise ArgumentError.new("Invalid date(s)") if check_in == nil || check_out == nil + raise ArgumentError.new("Check out must be later than check in") if check_in >= check_out @check_in = check_in @@ -17,16 +24,40 @@ def initialize(check_in, check_out, room_num) end - def self.find(date) - # returns a list of all reservations for given date - # does not include reservations where check-out date == date + def ==(other_reservation) + return @check_in == other_reservation.check_in && @check_out == other_reservation.check_out && @room_num == other_reservation.room_num end + # def self.find(date) + # # returns a list of all reservations for given date + # # does not include reservations where check-out date == date + # + # end + def total_cost num_nights = (@check_out - @check_in).to_i return num_nights * ::Hotel::Room::DEFAULT_RATE end + private + + def check_date(date) + if date.is_a?Date + return date + else + begin date = Date.parse(date) + rescue ArgumentError + return nil + rescue TypeError + return nil + else + return date + end + end + end + + + end # end of Reservation class end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 4eda127fc..a86f7c4ab 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -36,4 +36,31 @@ end end + + describe "#reserve" do + before do + @hotel = Hotel::Hotel.new + @room1 = @hotel.rooms[0] + end + + it "Reserves the given room for the given dates" do + @room1.reservations.must_equal [] + + @hotel.reserve('2017/9/3', '2017/9/5', @room1) + new_res = Hotel::Reservation.new(Date.parse('2017/9/3'), Date.parse('2017/9/5'), @room1.room_num) + @room1.reservations[0].must_equal new_res + end + end + + xdescribe "#find_reservations_by_date" do + before do + @hotel = Hotel.new + + end + + it "Returns a list of reservations" do + + end + end + end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 603738765..bfe3348c4 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -13,8 +13,8 @@ end it "Raises an error if check_out date isn't later than check_in date" do - check_in = Date.new(2017,9,5) - check_out = Date.new(2017,8,5) + check_in = '2017/9/5' + check_out = '2017/8/5' proc { Hotel::Reservation.new(check_in, check_out, 2) }.must_raise ArgumentError @@ -22,6 +22,20 @@ proc { Hotel::Reservation.new(check_in, check_out, 2) }.must_raise ArgumentError end + it "Raises an error if check in or check out aren't date objects or can't be parsed as dates" do + not_dates = ["cat", nil, 0, "", -1] + valid_date = '2017/9/5' + + not_dates.each do |item| + proc { Hotel::Reservation.new(valid_date, item, 20) }.must_raise ArgumentError + end + + not_dates.each do |item| + proc {Hotel::Reservation.new(item, valid_date, 18) }.must_raise ArgumentError + end + + end + end describe "total_cost" do From 3709c03830f5e3962accab8b24b750e7ee877de1 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Tue, 5 Sep 2017 21:48:58 -0700 Subject: [PATCH 07/26] Finished wave 1 --- lib/hotel.rb | 12 +++++++++++- specs/hotel_spec.rb | 46 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 8251610eb..3df85eafb 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -34,7 +34,7 @@ def all_reservations reservations = [] @rooms.each do |room| - reservations << room.reservations + reservations.concat(room.reservations) end return reservations @@ -43,6 +43,16 @@ def all_reservations def find_reservations_by_date(date) # returns a list of all reservations for the given date # doesn't include rooms where check-out date == date + reservations = [] + + all_reservations.each do |reservation| + + if date >= reservation.check_in && date < reservation.check_out + reservations << reservation + end + end + + return reservations end private diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index a86f7c4ab..b99bd50bf 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -52,14 +52,54 @@ end end - xdescribe "#find_reservations_by_date" do + describe "#find_reservations_by_date" do before do - @hotel = Hotel.new + @hotel = Hotel::Hotel.new + + # res that doesn't conflict with 9/5/17 + 5.times do |num| + room = @hotel.rooms[0 + num] + @hotel.reserve(Date.new(2017,9,1), Date.new(2017,9,4), room) + end + + # res that does conflict with 9/5/17 + 5.times do |num| + room = @hotel.rooms[5 + num] + @hotel.reserve(Date.new(2017,9,4), Date.new(2017,9,9), room) + end + + # res with start date conflicting with 9/5/17 + 5.times do |num| + room = @hotel.rooms[10 + num] + @hotel.reserve(Date.new(2017,9,5), Date.new(2017,9,9), room) + end + # res with end date not conflicting with 9/5/17 + 5.times do |num| + room = @hotel.rooms[15 + num] + @hotel.reserve(Date.new(2017,9,3), Date.new(2017,9,5), room) + end + + @date_to_check = Date.new(2017,9,5) + @sept5_res = @hotel.find_reservations_by_date(@date_to_check) + end + + it "Returns a list of reservations for that date" do + @sept5_res.must_be_kind_of Array end - it "Returns a list of reservations" do + it "Doesn't include reservations w/a check-out date matching date" do + @sept5_res.length.must_equal 10 + + room3 = @hotel.rooms[2] + @hotel.reserve(Date.new(2017,9,4), Date.new(2017,9,5), room3) + + updated_res = @hotel.find_reservations_by_date(@date_to_check) + updated_res.length.must_equal 10 + @hotel.reserve(Date.new(2017,9,5), Date.new(2017,9,6), room3) + updated_res = @hotel.find_reservations_by_date(@date_to_check) + updated_res.length.must_equal 11 end end From f788ac1b4917b9fdbb6d9d624586b4e9440add21 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Wed, 6 Sep 2017 11:32:34 -0700 Subject: [PATCH 08/26] Commented out exceptions focused on input type instead of business logic --- lib/hotel.rb | 53 +++++++++++++++++++++++---------------- lib/reservation.rb | 53 ++++++++++++++++++++------------------- lib/room.rb | 32 +++++++++++------------ specs/hotel_spec.rb | 16 +++++++++--- specs/reservation_spec.rb | 31 ++++++++++++----------- specs/room_spec.rb | 53 +++++++++++++++++++-------------------- 6 files changed, 129 insertions(+), 109 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 3df85eafb..dae53623d 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -11,7 +11,7 @@ class Hotel def initialize(num_rooms = NUM_ROOMS) # check input - raise ArgumentError.new("Not a valid number of rooms") if !is_valid?(num_rooms) + raise ArgumentError.new("Not a valid number of rooms") if num_rooms < 1 @rooms = [] @@ -29,38 +29,49 @@ def reserve(start_date, end_date, room) end - def all_reservations - # returns a list of all reservations for the hotel - reservations = [] - - @rooms.each do |room| - reservations.concat(room.reservations) - end - - return reservations - end + # def all_reservations # is this necessary?? + # # returns a list of all reservations for the hotel + # reservations = [] + # + # rooms.each do |room| + # reservations.concat(room.reservations) + # end + # + # return reservations + # end def find_reservations_by_date(date) # returns a list of all reservations for the given date # doesn't include rooms where check-out date == date reservations = [] - all_reservations.each do |reservation| - - if date >= reservation.check_in && date < reservation.check_out - reservations << reservation - end + rooms.each do |room| + reservations.concat(room.reservations.select { |reservation| reservation.include? date }) end return reservations - end - private - - def is_valid?(num) - return num.is_a?(Integer) && num > 0 + # reservations = [] + # + # all_reservations.each do |reservation| + # + # # if date >= reservation.check_in && date < reservation.check_out + # # reservations << reservation + # # end + # if reservation.include?(date) + # reservations << reservation + # end + # end + # + # return reservations end + # private + # + # def is_valid?(num) move integer check to user input + # return num.is_a?(Integer) && num > 0 + # end + end # end of Hotel class end diff --git a/lib/reservation.rb b/lib/reservation.rb index 33c8bc0ba..0137b4ea1 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -10,11 +10,11 @@ class Reservation def initialize(check_in, check_out, room_num) - # check input - check_in = check_date(check_in) - check_out = check_date(check_out) - - raise ArgumentError.new("Invalid date(s)") if check_in == nil || check_out == nil + # # check input move check input type != date to user interface + # check_in = check_date(check_in) + # check_out = check_date(check_out) + # + # raise ArgumentError.new("Invalid date(s)") if check_in == nil || check_out == nil raise ArgumentError.new("Check out must be later than check in") if check_in >= check_out @@ -25,7 +25,11 @@ def initialize(check_in, check_out, room_num) end def ==(other_reservation) - return @check_in == other_reservation.check_in && @check_out == other_reservation.check_out && @room_num == other_reservation.room_num + return check_in == other_reservation.check_in && check_out == other_reservation.check_out && room_num == other_reservation.room_num + end + + def include?(date) + return date >= check_in && date < check_out end # def self.find(date) @@ -35,29 +39,26 @@ def ==(other_reservation) # end def total_cost - num_nights = (@check_out - @check_in).to_i + num_nights = (check_out - check_in).to_i return num_nights * ::Hotel::Room::DEFAULT_RATE end - private - - def check_date(date) - if date.is_a?Date - return date - else - begin date = Date.parse(date) - rescue ArgumentError - return nil - rescue TypeError - return nil - else - return date - end - end - end - - - + # private + # move check_date to user interface + # def check_date(date) + # if date.is_a?Date + # return date + # else + # begin date = Date.parse(date) + # rescue ArgumentError + # return nil + # rescue TypeError + # return nil + # else + # return date + # end + # end + # end end # end of Reservation class end diff --git a/lib/room.rb b/lib/room.rb index 3b47f0d7f..2203ff6da 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -2,7 +2,7 @@ module Hotel - NUM_ROOMS = 20 + # NUM_ROOMS = 20 class Room @@ -13,7 +13,7 @@ class Room def initialize(room_num, rate = DEFAULT_RATE) - if valid_room_num?(room_num) + if room_num > 0 @room_num = room_num else raise ArgumentError.new("Not a valid room number") @@ -23,28 +23,28 @@ def initialize(room_num, rate = DEFAULT_RATE) @rate = rate end - def self.all - # create a list of all hotel rooms - all_rooms = [] - - (1..Hotel::NUM_ROOMS).each do |num| - all_rooms << Room.new(num) - end - - return all_rooms - end + # def self.all + # # create a list of all hotel rooms + # all_rooms = [] + # + # (1..Hotel::NUM_ROOMS).each do |num| + # all_rooms << Room.new(num) + # end + # + # return all_rooms + # end def reserve(start_date, end_date) # add reservation if room is available and return true; else false #if is_available - @reservations << ::Hotel::Reservation.new(start_date, end_date, @room_num) + reservations << ::Hotel::Reservation.new(start_date, end_date, room_num) end private - def valid_room_num?(num) - return num.class == Integer && num >= 1 && num <= 20 - end + # def valid_room_num?(num) + # return num >= 1 && num <= ::Hotel::Hotel::NUM_ROOMS + # end # def is_available?(start_date, end_date) # @reservations.each do |reservation| diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index b99bd50bf..6ae9e1590 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -28,10 +28,18 @@ end it "Raises an error if not passed a valid number for num of rooms" do - invalid_nums = [-1, 0, "dog", 3.14, nil, ""] + proc { Hotel::Hotel.new(-1) }.must_raise ArgumentError + proc { Hotel::Hotel.new(0) }.must_raise ArgumentError + end + + it "Creates rooms with room nums between 1 & specified number of rooms" do + num_rooms = 25 + big_hotel = Hotel::Hotel.new(num_rooms) + num_big_hotel_rooms = big_hotel.rooms.length - invalid_nums.each do |item| - proc { Hotel::Hotel.new(item) }.must_raise ArgumentError + big_hotel.rooms.each do |room| + room.room_num.must_be :>=, 1 + room.room_num.must_be :<=, num_big_hotel_rooms end end @@ -46,7 +54,7 @@ it "Reserves the given room for the given dates" do @room1.reservations.must_equal [] - @hotel.reserve('2017/9/3', '2017/9/5', @room1) + @hotel.reserve(Date.parse('2017/9/3'), Date.parse('2017/9/5'), @room1) new_res = Hotel::Reservation.new(Date.parse('2017/9/3'), Date.parse('2017/9/5'), @room1.room_num) @room1.reservations[0].must_equal new_res end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index bfe3348c4..c5c53c576 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -13,8 +13,8 @@ end it "Raises an error if check_out date isn't later than check_in date" do - check_in = '2017/9/5' - check_out = '2017/8/5' + check_in = Date.new(2017,9,5) + check_out = Date.new(2017,8,5) proc { Hotel::Reservation.new(check_in, check_out, 2) }.must_raise ArgumentError @@ -22,19 +22,20 @@ proc { Hotel::Reservation.new(check_in, check_out, 2) }.must_raise ArgumentError end - it "Raises an error if check in or check out aren't date objects or can't be parsed as dates" do - not_dates = ["cat", nil, 0, "", -1] - valid_date = '2017/9/5' - - not_dates.each do |item| - proc { Hotel::Reservation.new(valid_date, item, 20) }.must_raise ArgumentError - end - - not_dates.each do |item| - proc {Hotel::Reservation.new(item, valid_date, 18) }.must_raise ArgumentError - end - - end + # move this to user interface + # it "Raises an error if check in or check out aren't date objects or can't be parsed as dates" do + # not_dates = ["cat", nil, 0, "", -1] + # valid_date = '2017/9/5' + # + # not_dates.each do |item| + # proc { Hotel::Reservation.new(valid_date, item, 20) }.must_raise ArgumentError + # end + # + # not_dates.each do |item| + # proc {Hotel::Reservation.new(item, valid_date, 18) }.must_raise ArgumentError + # end + # + # end end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index d08500f81..1759ca632 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -14,12 +14,10 @@ @room.rate.must_equal Hotel::Room::DEFAULT_RATE end - it "Raises an error if room number isn't valid num" do - invalid_nums = ["cat", 31.4, nil, 0, -1, Hotel::NUM_ROOMS + 1] - - invalid_nums.each do |item| - proc { Hotel::Room.new(item) }.must_raise ArgumentError - end + it "Raises an error if room number isn't a valid num" do + # doesn't test for room num > 20 b/c optional param in Hotel allows for more rooms + proc { Hotel::Room.new(-1) }.must_raise ArgumentError + proc { Hotel::Room.new(0) }.must_raise ArgumentError end # it "Raises an error if room number isn't between 1 & 20" do @@ -28,6 +26,7 @@ # proc { Hotel::Room.new(21) }.must_raise ArgumentError # end # + # moving input check to user interface # it "Raises an error if room number isn't an integer" do # proc { Hotel::Room.new("cat") }.must_raise ArgumentError # proc { Hotel::Room.new(4.23) }.must_raise ArgumentError @@ -36,27 +35,27 @@ end - describe "#self.all" do - before do - @all_rooms = Hotel::Room.all - end - - it "Returns a list of all the rooms in the hotel" do - @all_rooms.must_be_kind_of Array - @all_rooms.length.must_equal Hotel::NUM_ROOMS - end - - it "Each hotel must have a different number between 1 & NUM_ROOMS" do - room_nums = (1..Hotel::NUM_ROOMS).to_a - - @all_rooms.each do |room| - room_nums.delete(room.room_num) - end - - room_nums.must_equal [] - end - - end + # describe "#self.all" do + # before do + # @all_rooms = Hotel::Room.all + # end + # + # it "Returns a list of all the rooms in the hotel" do + # @all_rooms.must_be_kind_of Array + # @all_rooms.length.must_equal Hotel::Hotel::NUM_ROOMS + # end + # + # it "Each hotel must have a different number between 1 & NUM_ROOMS" do + # room_nums = (1..Hotel::Hotel::NUM_ROOMS).to_a + # + # @all_rooms.each do |room| + # room_nums.delete(room.room_num) + # end + # + # room_nums.must_equal [] + # end + # + # end describe "#reserve" do before do From 25dc2563a19872686a8c068e2de42a518f46554c Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Wed, 6 Sep 2017 13:22:00 -0700 Subject: [PATCH 09/26] Added find available rooms for date range method --- lib/hotel.rb | 36 +++++++++++++++++--- specs/hotel_spec.rb | 80 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 101 insertions(+), 15 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index dae53623d..0ab7a517e 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -13,11 +13,11 @@ def initialize(num_rooms = NUM_ROOMS) # check input raise ArgumentError.new("Not a valid number of rooms") if num_rooms < 1 - @rooms = [] + @rooms = {} - # loop through num_rooms and add rooms to array + # loop through num_rooms and add rooms to hash (1..num_rooms).each do |num| - @rooms << ::Hotel::Room.new(num) + @rooms[num] = ::Hotel::Room.new(num) end end @@ -45,10 +45,11 @@ def find_reservations_by_date(date) # doesn't include rooms where check-out date == date reservations = [] - rooms.each do |room| + rooms.each do |room_num, room| reservations.concat(room.reservations.select { |reservation| reservation.include? date }) end + # organize using group_by? (room_num) return reservations # reservations = [] @@ -66,6 +67,33 @@ def find_reservations_by_date(date) # return reservations end + def find_avail_rooms(start_date, end_date) + # returns a list of rooms available in the date range + avail_rooms = (1..rooms.length).to_a + date_range = (start_date...end_date).to_a # don't include end date since checkout won't conflict with start date of another res + + # iterate through all room numbers and check if room reservations include any of the dates in date range + (1..avail_rooms.length).each do |room_num| + room = rooms[room_num] + + date_range.each do |date| + room.reservations.each do |reservation| + puts "iterating through reservations for room #{room_num}" + + if reservation.include?(date) + avail_rooms.delete(room_num) + puts "breaking out...or am I?" + break + end + end + end + end + + # return list of room objects + return avail_rooms.map { |room_num| rooms[room_num] } + + end + # private # # def is_valid?(num) move integer check to user input diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 6ae9e1590..b33797e5e 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -6,13 +6,13 @@ @hotel = Hotel::Hotel.new end - it "Creates a hotel class with an array of rooms" do + it "Creates a hotel class with a hash of rooms" do @hotel.must_be_instance_of Hotel::Hotel rooms = @hotel.rooms - rooms.must_be_instance_of Array + rooms.must_be_kind_of Hash - rooms.each do |room| + rooms.each do |room_num, room| room.must_be_instance_of Hotel::Room end end @@ -37,9 +37,9 @@ big_hotel = Hotel::Hotel.new(num_rooms) num_big_hotel_rooms = big_hotel.rooms.length - big_hotel.rooms.each do |room| - room.room_num.must_be :>=, 1 - room.room_num.must_be :<=, num_big_hotel_rooms + big_hotel.rooms.each do |room_num, room| + room_num.must_be :>=, 1 + room_num.must_be :<=, num_big_hotel_rooms end end @@ -48,7 +48,7 @@ describe "#reserve" do before do @hotel = Hotel::Hotel.new - @room1 = @hotel.rooms[0] + @room1 = @hotel.rooms[1] end it "Reserves the given room for the given dates" do @@ -66,25 +66,25 @@ # res that doesn't conflict with 9/5/17 5.times do |num| - room = @hotel.rooms[0 + num] + room = @hotel.rooms[1 + num] @hotel.reserve(Date.new(2017,9,1), Date.new(2017,9,4), room) end # res that does conflict with 9/5/17 5.times do |num| - room = @hotel.rooms[5 + num] + room = @hotel.rooms[6 + num] @hotel.reserve(Date.new(2017,9,4), Date.new(2017,9,9), room) end # res with start date conflicting with 9/5/17 5.times do |num| - room = @hotel.rooms[10 + num] + room = @hotel.rooms[11 + num] @hotel.reserve(Date.new(2017,9,5), Date.new(2017,9,9), room) end # res with end date not conflicting with 9/5/17 5.times do |num| - room = @hotel.rooms[15 + num] + room = @hotel.rooms[16 + num] @hotel.reserve(Date.new(2017,9,3), Date.new(2017,9,5), room) end @@ -111,4 +111,62 @@ end end + describe "#find_avail_rooms" do + before do + @hotel = Hotel::Hotel.new + + # res that doesn't conflict with 9/5/17 - 9/7/17 + 5.times do |num| + room = @hotel.rooms[1 + num] + @hotel.reserve(Date.new(2017,9,1), Date.new(2017,9,4), room) + end + + # res that does conflict with 9/5/17-9/7/17 + 5.times do |num| + room = @hotel.rooms[6 + num] + @hotel.reserve(Date.new(2017,9,4), Date.new(2017,9,9), room) + end + + # res conflicting with 9/5/17-9/7/17 + 5.times do |num| + room = @hotel.rooms[11 + num] + @hotel.reserve(Date.new(2017,9,5), Date.new(2017,9,9), room) + end + + # res not conflicting with 9/5/17-9/7/17 + 5.times do |num| + room = @hotel.rooms[16 + num] + @hotel.reserve(Date.new(2017,9,3), Date.new(2017,9,5), room) + end + + @start_date = Date.new(2017,9,5) + @end_date = Date.new(2017,9,7) + end + + it "Returns a list of rooms available for the given date range" do + avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) + avail_rooms.must_be_kind_of Array + + avail_rooms.each do |room| + room.must_be_instance_of Hotel::Room + end + end + + it "Counts rooms as available if check_out date equals start_date of another reservation" do + expected_availability = 10 + avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) + avail_rooms.length.must_equal expected_availability + + room1 = @hotel.rooms[1] + @hotel.reserve(Date.new(2017,9,4), @start_date, room1) + @hotel.find_avail_rooms(@start_date, @end_date).must_equal avail_rooms + + @hotel.reserve(@start_date, Date.new(2017,9,6), room1) + updated_avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) + updated_avail_rooms.length.must_equal expected_availability - 1 + updated_avail_rooms.wont_include room1 + end + end + + end From a89bc7e05a6dec383f89c9c874ced9c8129360be Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Wed, 6 Sep 2017 14:05:27 -0700 Subject: [PATCH 10/26] Added is_booked method to Room class --- lib/room.rb | 12 ++++++++++++ specs/room_spec.rb | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/lib/room.rb b/lib/room.rb index 2203ff6da..4c77c249c 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -40,6 +40,18 @@ def reserve(start_date, end_date) reservations << ::Hotel::Reservation.new(start_date, end_date, room_num) end + def is_booked?(date) + return reservations.any? { |reservation| reservation.include?(date) } + + # reservations.each do |reservation| + # if reservation.include?(date) + # return true + # end + # end + # + # return false + end + private # def valid_room_num?(num) diff --git a/specs/room_spec.rb b/specs/room_spec.rb index 1759ca632..eafa82934 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -91,4 +91,20 @@ # end end + + describe "#is_booked?" do + it "Returns true if the room is booked for a given date" do + room = Hotel::Room.new(3) + check_in = Date.new(2017,9,5) + check_out = Date.new(2017,9,8) + + room.reserve(check_in, check_out) + room.is_booked?(Date.new(2017,9,6)).must_equal true + room.is_booked?(Date.new(2017,9,8)).must_equal false + + room.reserve(Date.new(2017,9,8), Date.new(2017,9,10)) + room.is_booked?(Date.new(2017,9,8)).must_equal true + + end + end end From 13531e4356ecfb770b84a4df9c0795e13b37ca58 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Wed, 6 Sep 2017 15:25:23 -0700 Subject: [PATCH 11/26] Refactored find_avail_rooms method --- lib/hotel.rb | 43 +++++++------------------------------------ lib/room.rb | 15 +++++++++++++-- specs/hotel_spec.rb | 13 ++++++++++--- 3 files changed, 30 insertions(+), 41 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 0ab7a517e..d04d87e5f 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -52,49 +52,20 @@ def find_reservations_by_date(date) # organize using group_by? (room_num) return reservations - # reservations = [] - # - # all_reservations.each do |reservation| - # - # # if date >= reservation.check_in && date < reservation.check_out - # # reservations << reservation - # # end - # if reservation.include?(date) - # reservations << reservation - # end - # end - # - # return reservations end def find_avail_rooms(start_date, end_date) - # returns a list of rooms available in the date range - avail_rooms = (1..rooms.length).to_a - date_range = (start_date...end_date).to_a # don't include end date since checkout won't conflict with start date of another res - - # iterate through all room numbers and check if room reservations include any of the dates in date range - (1..avail_rooms.length).each do |room_num| - room = rooms[room_num] - - date_range.each do |date| - room.reservations.each do |reservation| - puts "iterating through reservations for room #{room_num}" - - if reservation.include?(date) - avail_rooms.delete(room_num) - puts "breaking out...or am I?" - break - end - end - end - end + # returns a hash of rooms available in the date range + + # check input + raise ArgumentError.new("End date must be after start date") if start_date >= end_date - # return list of room objects - return avail_rooms.map { |room_num| rooms[room_num] } + return rooms.reject { |room_num, room| room.is_booked?(start_date, end_date) } end - # private + private + # # def is_valid?(num) move integer check to user input # return num.is_a?(Integer) && num > 0 diff --git a/lib/room.rb b/lib/room.rb index 4c77c249c..85725f566 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -40,8 +40,19 @@ def reserve(start_date, end_date) reservations << ::Hotel::Reservation.new(start_date, end_date, room_num) end - def is_booked?(date) - return reservations.any? { |reservation| reservation.include?(date) } + def is_booked?(start_date, end_date = start_date.next_day) + # don't include final date since check-out doesn't conflict with check-in of a new reservation + date_range = (start_date...end_date).to_a + + reservations.each do |reservation| + date_range.each do |date| + if reservation.include?(date) + return true + end + end + end + + return false # reservations.each do |reservation| # if reservation.include?(date) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index b33797e5e..9368f6c1d 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -143,11 +143,11 @@ @end_date = Date.new(2017,9,7) end - it "Returns a list of rooms available for the given date range" do + it "Returns a hash of rooms available for the given date range" do avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) - avail_rooms.must_be_kind_of Array + avail_rooms.must_be_kind_of Hash - avail_rooms.each do |room| + avail_rooms.each do |room_num, room| room.must_be_instance_of Hotel::Room end end @@ -166,6 +166,13 @@ updated_avail_rooms.length.must_equal expected_availability - 1 updated_avail_rooms.wont_include room1 end + + it "Raises ArgumentError if start date is later than end date" do + room1 = @hotel.rooms[1] + proc { @hotel.find_avail_rooms(@end_date, @start_date, room1) }.must_raise ArgumentError + + proc { @hotel.find_avail_rooms(@end_date, @end_date, room1) }.must_raise ArgumentError + end end From 6f526566f0a0b1292d723e2ccd092ae82fca033f Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Wed, 6 Sep 2017 15:51:30 -0700 Subject: [PATCH 12/26] Finished wave 2 --- lib/hotel.rb | 4 +-- lib/room.rb | 9 ++++-- specs/hotel_spec.rb | 5 ++++ specs/room_spec.rb | 67 +++++++++++++++++---------------------------- 4 files changed, 39 insertions(+), 46 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index d04d87e5f..bf3dc48e2 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -23,9 +23,9 @@ def initialize(num_rooms = NUM_ROOMS) end def reserve(start_date, end_date, room) - # TODO check if available and return true if added; else false + raise ArgumentError.new("Room #{room.room_num} isn't available for the selected dates") if room.is_booked?(start_date, end_date) - room.reserve(start_date, end_date) + return room.reserve(start_date, end_date) end diff --git a/lib/room.rb b/lib/room.rb index 85725f566..4b24971e7 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -37,7 +37,12 @@ def initialize(room_num, rate = DEFAULT_RATE) def reserve(start_date, end_date) # add reservation if room is available and return true; else false #if is_available - reservations << ::Hotel::Reservation.new(start_date, end_date, room_num) + if !is_booked?(start_date, end_date) + reservations << ::Hotel::Reservation.new(start_date, end_date, room_num) + return true + end + + return false end def is_booked?(start_date, end_date = start_date.next_day) @@ -51,7 +56,7 @@ def is_booked?(start_date, end_date = start_date.next_day) end end end - + return false # reservations.each do |reservation| diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 9368f6c1d..d9253d748 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -58,6 +58,11 @@ new_res = Hotel::Reservation.new(Date.parse('2017/9/3'), Date.parse('2017/9/5'), @room1.room_num) @room1.reservations[0].must_equal new_res end + + it "Raises error when it tries to reserve a room that isn't available" do + @hotel.reserve(Date.new(2017,9,5), Date.new(2017,9,8), @room1) + proc { @hotel.reserve(Date.new(2017,9,7), Date.new(2017,9,8), @room1) }.must_raise ArgumentError + end end describe "#find_reservations_by_date" do diff --git a/specs/room_spec.rb b/specs/room_spec.rb index eafa82934..a3e7b6d4d 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -35,28 +35,6 @@ end - # describe "#self.all" do - # before do - # @all_rooms = Hotel::Room.all - # end - # - # it "Returns a list of all the rooms in the hotel" do - # @all_rooms.must_be_kind_of Array - # @all_rooms.length.must_equal Hotel::Hotel::NUM_ROOMS - # end - # - # it "Each hotel must have a different number between 1 & NUM_ROOMS" do - # room_nums = (1..Hotel::Hotel::NUM_ROOMS).to_a - # - # @all_rooms.each do |room| - # room_nums.delete(room.room_num) - # end - # - # room_nums.must_equal [] - # end - # - # end - describe "#reserve" do before do @room = Hotel::Room.new(3) @@ -78,33 +56,38 @@ res.check_out.must_equal @check_out end - # it "Returns true if the room is added" do - # @room.reserve(Date.new(2017,8,5), Date.new(2017,8,8)).must_equal true - # @room.reservations.length.must_equal 2 - # end - # - # it "Doesn't reserve the room if the room isn't available" do - # # bad_res = @room.reserve(@check_in, @check_out) - # # bad_res.must_equal false - # @room.reserve(@check_in, @check_out).must_equal false - # @room.reservations.length.must_equal 1 - # end + it "Returns true if the room is added" do + @room.reserve(Date.new(2017,8,5), Date.new(2017,8,8)).must_equal true + @room.reservations.length.must_equal 2 + end + + it "Doesn't reserve the room if the room isn't available" do + # bad_res = @room.reserve(@check_in, @check_out) + # bad_res.must_equal false + @room.reserve(@check_in, @check_out).must_equal false + @room.reservations.length.must_equal 1 + end end describe "#is_booked?" do - it "Returns true if the room is booked for a given date" do - room = Hotel::Room.new(3) - check_in = Date.new(2017,9,5) - check_out = Date.new(2017,9,8) + before do + @room = Hotel::Room.new(3) + @check_in = Date.new(2017,9,5) + @check_out = Date.new(2017,9,8) + @room.reserve(@check_in, @check_out) + end - room.reserve(check_in, check_out) - room.is_booked?(Date.new(2017,9,6)).must_equal true - room.is_booked?(Date.new(2017,9,8)).must_equal false + it "Returns true if the room is booked for a given date" do + @room.is_booked?(Date.new(2017,9,6)).must_equal true + @room.is_booked?(Date.new(2017,9,8)).must_equal false - room.reserve(Date.new(2017,9,8), Date.new(2017,9,10)) - room.is_booked?(Date.new(2017,9,8)).must_equal true + @room.reserve(Date.new(2017,9,8), Date.new(2017,9,10)) + @room.is_booked?(Date.new(2017,9,8)).must_equal true + end + it "Returns true if room is booked for given date range" do + @room.is_booked?(Date.new(2017,9,6), Date.new(2017,9,8)).must_equal true end end end From 9fe74cfc5949437dd7e904e66fd312bee08cf66b Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Thu, 7 Sep 2017 10:19:19 -0700 Subject: [PATCH 13/26] Set up Block class --- lib/block.rb | 23 +++++++++++++++++++++++ specs/block_spec.rb | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 lib/block.rb create mode 100644 specs/block_spec.rb diff --git a/lib/block.rb b/lib/block.rb new file mode 100644 index 000000000..afb082560 --- /dev/null +++ b/lib/block.rb @@ -0,0 +1,23 @@ +require_relative 'reservation' +require_relative 'room' + +module Hotel + + class Block + + MAX_ROOMS = 5 + + attr_accessor :check_in, :check_out, :discount, :room_block + + def initialize(check_in, check_out, discount, room_block) + raise ArgumentError.new("Can't have more than #{MAX_ROOMS} number of rooms in a block") if room_block.length > MAX_ROOMS + + @check_in = check_in + @check_out = check_out + @discount = discount + @room_block = room_block + end + + end # end of Block class + +end diff --git a/specs/block_spec.rb b/specs/block_spec.rb new file mode 100644 index 000000000..6cb349e0e --- /dev/null +++ b/specs/block_spec.rb @@ -0,0 +1,34 @@ +require_relative 'spec_helper' + +describe "Testing Block class" do + describe "#initialize" do + before do + @rooms = [] + 4.times do |num| + @rooms << Hotel::Room.new(num + 1) + end + + @check_in = Date.new(2017,9,3) + @check_out = Date.new(2017,9,5) + + @block = Hotel::Block.new(@check_in, @check_out, 0.2, @rooms) + end + + it "Creates a Block with a check_in and check_out date, an array of rooms, and a discounted rate" do + room1 = @block.room_block[0] + + @block.must_be_instance_of Hotel::Block + @block.check_in.must_equal @check_in + @block.check_out.must_equal @check_out + @block.room_block.must_equal @rooms + (@block.discount * room1.rate).must_be :<, room1.rate + end + + it "Creates a block with no more than MAX_ROOMS num of rooms" do + @rooms << Hotel::Room.new(5) + @rooms << Hotel::Room.new(6) + + proc {Hotel::Block.new(@check_in, @check_out, 0.2, @rooms) }.must_raise ArgumentError + end + end +end From 75ff9a6e000a01f83c1883962b7ea80f3605ae65 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Thu, 7 Sep 2017 10:19:48 -0700 Subject: [PATCH 14/26] Added rate attribute to Reservation class --- lib/reservation.rb | 25 ++++++++++++++++++++----- lib/room.rb | 38 +++++++++++++++++++------------------- specs/hotel_spec.rb | 2 +- specs/reservation_spec.rb | 9 +++++---- specs/spec_helper.rb | 2 ++ 5 files changed, 47 insertions(+), 29 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 0137b4ea1..4bd3475ae 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -6,9 +6,9 @@ module Hotel class Reservation include Comparable - attr_accessor :check_in, :check_out, :room_num + attr_accessor :check_in, :check_out, :room_num, :rate - def initialize(check_in, check_out, room_num) + def initialize(check_in, check_out, room) # # check input move check input type != date to user interface # check_in = check_date(check_in) @@ -17,10 +17,11 @@ def initialize(check_in, check_out, room_num) # raise ArgumentError.new("Invalid date(s)") if check_in == nil || check_out == nil raise ArgumentError.new("Check out must be later than check in") if check_in >= check_out - + # @reservation_id = rand(100000..999999) @check_in = check_in @check_out = check_out - @room_num = room_num + @room_num = room.room_num + @rate = room.rate end @@ -40,7 +41,21 @@ def include?(date) def total_cost num_nights = (check_out - check_in).to_i - return num_nights * ::Hotel::Room::DEFAULT_RATE + # return num_nights * ::Hotel::Room::DEFAULT_RATE + return num_nights * rate + end + + private + + def to_s + # return human readable representation + s = "Reservation id: #{reservation_id}\n" + s += "Room number: #{room_num}\n" + s += "Check-in: #{check_in}\n" + s += "Check-out: #{check_out}\n" + + return s + end # private diff --git a/lib/room.rb b/lib/room.rb index 4b24971e7..7522e487b 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -5,6 +5,7 @@ module Hotel # NUM_ROOMS = 20 class Room + include Comparable DEFAULT_RATE = 200 @@ -23,22 +24,14 @@ def initialize(room_num, rate = DEFAULT_RATE) @rate = rate end - # def self.all - # # create a list of all hotel rooms - # all_rooms = [] - # - # (1..Hotel::NUM_ROOMS).each do |num| - # all_rooms << Room.new(num) - # end - # - # return all_rooms - # end + def <=>(other_room) + room_num <=> other_room.room_num + end def reserve(start_date, end_date) # add reservation if room is available and return true; else false - #if is_available if !is_booked?(start_date, end_date) - reservations << ::Hotel::Reservation.new(start_date, end_date, room_num) + reservations << ::Hotel::Reservation.new(start_date, end_date, self) # replacing room_num with self return true end @@ -59,17 +52,24 @@ def is_booked?(start_date, end_date = start_date.next_day) return false - # reservations.each do |reservation| - # if reservation.include?(date) - # return true - # end - # end - # - # return false end private + def to_s + # return human readable representation + s = "Room number: #{room_num}\n" + s += "Rate per night: $#{rate}\n" + s += "Reservations:\n" + + reservations.each do |reservation| + s += reservation.to_s + end + + return s + + end + # def valid_room_num?(num) # return num >= 1 && num <= ::Hotel::Hotel::NUM_ROOMS # end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index d9253d748..f8dccc23a 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -55,7 +55,7 @@ @room1.reservations.must_equal [] @hotel.reserve(Date.parse('2017/9/3'), Date.parse('2017/9/5'), @room1) - new_res = Hotel::Reservation.new(Date.parse('2017/9/3'), Date.parse('2017/9/5'), @room1.room_num) + new_res = Hotel::Reservation.new(Date.parse('2017/9/3'), Date.parse('2017/9/5'), @room1) @room1.reservations[0].must_equal new_res end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index c5c53c576..733a044ef 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -3,7 +3,8 @@ describe "Testing Reservation class" do describe "#initialize" do before do - @res = Hotel::Reservation.new(Date.new(2017,9,4), Date.new(2017,9,7), 4) + @room = Hotel::Room.new(4) + @res = Hotel::Reservation.new(Date.new(2017,9,4), Date.new(2017,9,7), @room) end it "Creates a Reservation with a date range and room number" do @@ -16,10 +17,10 @@ check_in = Date.new(2017,9,5) check_out = Date.new(2017,8,5) - proc { Hotel::Reservation.new(check_in, check_out, 2) }.must_raise ArgumentError + proc { Hotel::Reservation.new(check_in, check_out, @room) }.must_raise ArgumentError check_out = Date.new(2017,9,5) - proc { Hotel::Reservation.new(check_in, check_out, 2) }.must_raise ArgumentError + proc { Hotel::Reservation.new(check_in, check_out, @room) }.must_raise ArgumentError end # move this to user interface @@ -43,7 +44,7 @@ before do @check_in = Date.new(2017,9,5) @check_out = Date.new(2017,9,8) - @res = Hotel::Reservation.new(@check_in, @check_out, 4) + @res = Hotel::Reservation.new(@check_in, @check_out, Hotel::Room.new(4)) end it "Returns the total cost of the reservation" do diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb index 401b00c93..c441a131f 100644 --- a/specs/spec_helper.rb +++ b/specs/spec_helper.rb @@ -4,11 +4,13 @@ require 'minitest/autorun' require 'minitest/reporters' require 'minitest/skip_dsl' +require 'pry' require 'date' require_relative '../lib/room' require_relative '../lib/reservation' require_relative '../lib/hotel' +require_relative '../lib/block' reporter_options = { color:true} Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new(reporter_options) From c8e3547c266a2c054afca55fe196d5b65f6043a9 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Thu, 7 Sep 2017 15:16:17 -0700 Subject: [PATCH 15/26] Added reservable module --- lib/block.rb | 9 ++++++++- lib/reservable.rb | 18 ++++++++++++++++++ lib/reservation.rb | 26 ++++++++++++-------------- specs/block_spec.rb | 10 ++++++++++ specs/reservable_spec.rb | 5 +++++ specs/spec_helper.rb | 1 + 6 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 lib/reservable.rb create mode 100644 specs/reservable_spec.rb diff --git a/lib/block.rb b/lib/block.rb index afb082560..93e44e9be 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -1,21 +1,28 @@ require_relative 'reservation' require_relative 'room' +require_relative 'reservable' module Hotel class Block + include Reservable MAX_ROOMS = 5 attr_accessor :check_in, :check_out, :discount, :room_block def initialize(check_in, check_out, discount, room_block) + # check input raise ArgumentError.new("Can't have more than #{MAX_ROOMS} number of rooms in a block") if room_block.length > MAX_ROOMS + raise ArgumentError.new("Can't have unavailable rooms in the block") if room_block.any? { |room| room.is_booked?(check_in, check_out) } + @check_in = check_in @check_out = check_out @discount = discount - @room_block = room_block + @room_block = room_block # array of rooms + + valid_dates? # this seems not efficient/ideal end end # end of Block class diff --git a/lib/reservable.rb b/lib/reservable.rb new file mode 100644 index 000000000..5b8cb503b --- /dev/null +++ b/lib/reservable.rb @@ -0,0 +1,18 @@ +require 'date' + +module Reservable + + def valid_dates? + raise ArgumentError.new("Check out must be later than check in") if @check_in >= @check_out + end + + def total_cost(rate = @rate) + num_nights = (@check_out - @check_in).to_i + return (num_nights * rate) + end + + def include?(date) + return date >= @check_in && date < @check_out + end + +end diff --git a/lib/reservation.rb b/lib/reservation.rb index 4bd3475ae..fb796d3ef 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -1,10 +1,12 @@ require 'date' require_relative 'room' +require_relative 'reservable' module Hotel class Reservation include Comparable + include Reservable attr_accessor :check_in, :check_out, :room_num, :rate @@ -16,34 +18,30 @@ def initialize(check_in, check_out, room) # # raise ArgumentError.new("Invalid date(s)") if check_in == nil || check_out == nil - raise ArgumentError.new("Check out must be later than check in") if check_in >= check_out + # raise ArgumentError.new("Check out must be later than check in") if check_in >= check_out # @reservation_id = rand(100000..999999) @check_in = check_in @check_out = check_out @room_num = room.room_num @rate = room.rate + valid_dates? + end def ==(other_reservation) return check_in == other_reservation.check_in && check_out == other_reservation.check_out && room_num == other_reservation.room_num end - def include?(date) - return date >= check_in && date < check_out - end - - # def self.find(date) - # # returns a list of all reservations for given date - # # does not include reservations where check-out date == date - # + # def include?(date) + # return date >= check_in && date < check_out # end - def total_cost - num_nights = (check_out - check_in).to_i - # return num_nights * ::Hotel::Room::DEFAULT_RATE - return num_nights * rate - end + # def total_cost + # num_nights = (check_out - check_in).to_i + # # return num_nights * ::Hotel::Room::DEFAULT_RATE + # return num_nights * rate + # end private diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 6cb349e0e..f4b1a5ba2 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -30,5 +30,15 @@ proc {Hotel::Block.new(@check_in, @check_out, 0.2, @rooms) }.must_raise ArgumentError end + + it "Raises an error if it tries to include an unavailable room for the given dates in the block" do + unavail_room = @rooms[0] + unavail_room.reserve(@check_in, @check_out) + + proc { Hotel::Block.new(@check_in, @check_out, 0.2, @rooms) }.must_raise ArgumentError + + end end + + end diff --git a/specs/reservable_spec.rb b/specs/reservable_spec.rb new file mode 100644 index 000000000..1cb72df61 --- /dev/null +++ b/specs/reservable_spec.rb @@ -0,0 +1,5 @@ +require_relative 'spec_helper' + +describe "Testing Reservable module" do + +end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb index c441a131f..2900bb250 100644 --- a/specs/spec_helper.rb +++ b/specs/spec_helper.rb @@ -11,6 +11,7 @@ require_relative '../lib/reservation' require_relative '../lib/hotel' require_relative '../lib/block' +require_relative '../lib/reservable' reporter_options = { color:true} Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new(reporter_options) From 432323b54a4fdc9e79135dc87d25477028753ef6 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Thu, 7 Sep 2017 21:06:32 -0700 Subject: [PATCH 16/26] Added methods to find available rooms in Block class --- lib/block.rb | 12 +++++++++++- lib/room.rb | 18 +++++++++++++++++- specs/block_spec.rb | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index 93e44e9be..179d90277 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -19,12 +19,22 @@ def initialize(check_in, check_out, discount, room_block) @check_in = check_in @check_out = check_out - @discount = discount + @discount = discount # rate of discount as a decimal (e.g. 0.2 for 20% off) @room_block = room_block # array of rooms valid_dates? # this seems not efficient/ideal end + def is_available?(room) + raise ArgumentError.new("Room number #{room.room_num} isn't in the block") if !room_block.include?(room) + + return !room.is_booked?(check_in, check_out) + end + + def find_avail_in_block + return room_block.select { |room| is_available?(room) } + end + end # end of Block class end diff --git a/lib/room.rb b/lib/room.rb index 7522e487b..d4e4c95ad 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -9,7 +9,7 @@ class Room DEFAULT_RATE = 200 - attr_reader :room_num, :reservations + attr_reader :room_num, :reservations, :blocks attr_accessor :rate def initialize(room_num, rate = DEFAULT_RATE) @@ -21,6 +21,7 @@ def initialize(room_num, rate = DEFAULT_RATE) end @reservations = [] + @blocks = [] @rate = rate end @@ -54,6 +55,21 @@ def is_booked?(start_date, end_date = start_date.next_day) end + def is_blocked?(start_date, end_date = start_date.next_day) + date_range = (start_date...end_date).to_a + + blocks.each do |block| + date_range.each do |date| + if block.include?(date) + return true + end + end + end + + return false + + end + private def to_s diff --git a/specs/block_spec.rb b/specs/block_spec.rb index f4b1a5ba2..30dba6776 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -40,5 +40,50 @@ end end + describe "#is_available" do + let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } + let(:check_in) { Date.new(2017,9,3) } + let(:check_out) { Date.new(2017,9,5) } + let(:block) { Hotel::Block.new(Date.new(2017,9,3), Date.new(2017,9,5), 0.2, rooms)} + + it "Returns true if a room in the block is available" do + room1 = rooms[0] + block.is_available?(room1).must_equal true + + room1.reserve(check_in, check_out) + block.is_available?(room1).must_equal false + end + + it "Raises an argument error if room isn't in the block" do + wrong_room = Hotel::Room.new(6) + proc { block.is_available?(wrong_room) }.must_raise ArgumentError + end + end + + describe "#find_avail_in_block" do + let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } + let(:check_in) { Date.new(2017,9,3) } + let(:check_out) { Date.new(2017,9,5) } + let(:block) { Hotel::Block.new(Date.new(2017,9,3), Date.new(2017,9,5), 0.2, rooms)} + + it "Returns a list of rooms that are available in the block" do + block.find_avail_in_block.must_equal rooms + + rooms[0].reserve(check_in, check_out) + rooms[1].reserve(check_in, check_out) + + block.find_avail_in_block.must_equal rooms[2..-1] + end + + it "Returns an empty array if no rooms available" do + block.find_avail_in_block.must_equal rooms + + 5.times do |num| + rooms[num].reserve(check_in, check_out) + end + + block.find_avail_in_block.must_equal [] + end + end end From f20a7d0c465a3aa01164e799743330c82c6c4d44 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Thu, 7 Sep 2017 22:04:44 -0700 Subject: [PATCH 17/26] Added reserve method in Block and modified Room.reserve to return Reservation --- lib/block.rb | 10 +++++++++- lib/room.rb | 20 ++++++++++++++------ specs/block_spec.rb | 43 +++++++++++++++++++++++++++++++++++-------- specs/room_spec.rb | 26 ++++++++++++++++++-------- 4 files changed, 76 insertions(+), 23 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index 179d90277..35d53c235 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -26,7 +26,7 @@ def initialize(check_in, check_out, discount, room_block) end def is_available?(room) - raise ArgumentError.new("Room number #{room.room_num} isn't in the block") if !room_block.include?(room) + raise ArgumentError.new("Room #{room.room_num} isn't in the block") if !room_block.include?(room) return !room.is_booked?(check_in, check_out) end @@ -35,6 +35,14 @@ def find_avail_in_block return room_block.select { |room| is_available?(room) } end + def reserve(room) + raise ArgumentError.new("Room #{room.room_num} isn't in the block") if !room_block.include?(room) + + raise ArgumentError.new("Room #{room.room_num} isn't available for the selected dates") if room.is_booked?(check_in, check_out) + + return room.reserve(check_in, check_out) + end + end # end of Block class end diff --git a/lib/room.rb b/lib/room.rb index d4e4c95ad..9325ef4bc 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -30,13 +30,21 @@ def <=>(other_room) end def reserve(start_date, end_date) - # add reservation if room is available and return true; else false - if !is_booked?(start_date, end_date) - reservations << ::Hotel::Reservation.new(start_date, end_date, self) # replacing room_num with self - return true - end + # TODO maybe return the actual reservation object here instead? And both Hotel/Block check if booked; throw out check here? - return false + raise ArgumentError.new("Room #{room_num} isn't available for the given dates") if is_booked?(start_date, end_date) + + new_reservation = ::Hotel::Reservation.new(start_date, end_date, self) + reservations << new_reservation + + return new_reservation + # add reservation if room is available and return true; else false + # if !is_booked?(start_date, end_date) + # reservations << ::Hotel::Reservation.new(start_date, end_date, self) # replacing room_num with self + # return true + # end + # + # return false end def is_booked?(start_date, end_date = start_date.next_day) diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 30dba6776..649a1a4b6 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -1,6 +1,12 @@ require_relative 'spec_helper' describe "Testing Block class" do + + let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } + let(:check_in) { Date.new(2017,9,3) } + let(:check_out) { Date.new(2017,9,5) } + let(:block) { Hotel::Block.new(Date.new(2017,9,3), Date.new(2017,9,5), 0.2, rooms)} + describe "#initialize" do before do @rooms = [] @@ -41,10 +47,10 @@ end describe "#is_available" do - let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } - let(:check_in) { Date.new(2017,9,3) } - let(:check_out) { Date.new(2017,9,5) } - let(:block) { Hotel::Block.new(Date.new(2017,9,3), Date.new(2017,9,5), 0.2, rooms)} + # let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } + # let(:check_in) { Date.new(2017,9,3) } + # let(:check_out) { Date.new(2017,9,5) } + # let(:block) { Hotel::Block.new(Date.new(2017,9,3), Date.new(2017,9,5), 0.2, rooms)} it "Returns true if a room in the block is available" do room1 = rooms[0] @@ -61,10 +67,10 @@ end describe "#find_avail_in_block" do - let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } - let(:check_in) { Date.new(2017,9,3) } - let(:check_out) { Date.new(2017,9,5) } - let(:block) { Hotel::Block.new(Date.new(2017,9,3), Date.new(2017,9,5), 0.2, rooms)} + # let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } + # let(:check_in) { Date.new(2017,9,3) } + # let(:check_out) { Date.new(2017,9,5) } + # let(:block) { Hotel::Block.new(Date.new(2017,9,3), Date.new(2017,9,5), 0.2, rooms)} it "Returns a list of rooms that are available in the block" do block.find_avail_in_block.must_equal rooms @@ -86,4 +92,25 @@ end end + describe "#reserve" do + let(:room_to_reserve) { rooms[0] } + + it "Reserves a room for the dates of the block" do + block_res = block.reserve(room_to_reserve) + + block_res.check_in.must_equal check_in + block_res.check_out.must_equal check_out + end + + it "Raises an error if it tries to reserve a room not in the block" do + room_outside_block = Hotel::Room.new(20) + proc { block.reserve(room_outside_block) }.must_raise ArgumentError + end + + it "Raises an error if it tries to reserve an room that's already reserved" do + block.reserve(room_to_reserve) + proc {block.reserve(room_to_reserve) }.must_raise ArgumentError + end + end + end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index a3e7b6d4d..811a09a01 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -56,18 +56,28 @@ res.check_out.must_equal @check_out end - it "Returns true if the room is added" do - @room.reserve(Date.new(2017,8,5), Date.new(2017,8,8)).must_equal true - @room.reservations.length.must_equal 2 + it "Raises an error if the room isn't available" do + proc { @room.reserve(@check_in, @check_out) }.must_raise ArgumentError end - it "Doesn't reserve the room if the room isn't available" do - # bad_res = @room.reserve(@check_in, @check_out) - # bad_res.must_equal false - @room.reserve(@check_in, @check_out).must_equal false - @room.reservations.length.must_equal 1 + it "Returns the new reservation if the reservation is created" do + new_res = Hotel::Reservation.new(@check_out, @check_out.next_day, @room) + + @room.reserve(@check_out, @check_out.next_day).must_equal new_res end + # it "Returns true if the room is added" do + # @room.reserve(Date.new(2017,8,5), Date.new(2017,8,8)).must_equal true + # @room.reservations.length.must_equal 2 + # end + # + # it "Doesn't reserve the room if the room isn't available" do + # # bad_res = @room.reserve(@check_in, @check_out) + # # bad_res.must_equal false + # @room.reserve(@check_in, @check_out).must_equal false + # @room.reservations.length.must_equal 1 + # end + end describe "#is_booked?" do From 61f4fd388676d72b09c5f669c72089171bc7cee7 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Fri, 8 Sep 2017 13:42:30 -0700 Subject: [PATCH 18/26] Finished wave 3, code needs cleaned up --- lib/block.rb | 9 +++- lib/hotel.rb | 6 +-- lib/reservable.rb | 8 +++- lib/reservation.rb | 2 +- lib/room.rb | 18 ++++---- specs/block_spec.rb | 32 ++++++++------ specs/hotel_spec.rb | 87 +++++++++++++++++++++++++-------------- specs/reservation_spec.rb | 27 +++++++----- specs/room_spec.rb | 65 +++++++++++++++++++---------- 9 files changed, 163 insertions(+), 91 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index 35d53c235..9fce02c9d 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -13,16 +13,21 @@ class Block def initialize(check_in, check_out, discount, room_block) # check input + # TODO fix discount / rate in room and block raise ArgumentError.new("Can't have more than #{MAX_ROOMS} number of rooms in a block") if room_block.length > MAX_ROOMS - raise ArgumentError.new("Can't have unavailable rooms in the block") if room_block.any? { |room| room.is_booked?(check_in, check_out) } + raise ArgumentError.new("Can't have unavailable rooms in the block") if room_block.any? { |room| room.is_booked?(check_in, check_out) || room.is_blocked?(check_in, check_out) } @check_in = check_in @check_out = check_out + valid_dates? + @discount = discount # rate of discount as a decimal (e.g. 0.2 for 20% off) @room_block = room_block # array of rooms - valid_dates? # this seems not efficient/ideal + # add block to each room + room_block.cycle(1) { |room| room.blocks << self } + end def is_available?(room) diff --git a/lib/hotel.rb b/lib/hotel.rb index bf3dc48e2..e777cc107 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -23,7 +23,7 @@ def initialize(num_rooms = NUM_ROOMS) end def reserve(start_date, end_date, room) - raise ArgumentError.new("Room #{room.room_num} isn't available for the selected dates") if room.is_booked?(start_date, end_date) + raise ArgumentError.new("Room #{room.room_num} isn't available for the selected dates") if room.is_booked?(start_date, end_date) || room.is_blocked?(start_date, end_date) return room.reserve(start_date, end_date) @@ -60,11 +60,11 @@ def find_avail_rooms(start_date, end_date) # check input raise ArgumentError.new("End date must be after start date") if start_date >= end_date - return rooms.reject { |room_num, room| room.is_booked?(start_date, end_date) } + return rooms.reject { |room_num, room| room.is_booked?(start_date, end_date) || room.is_blocked?(start_date, end_date) } end - private + # private # # def is_valid?(num) move integer check to user input diff --git a/lib/reservable.rb b/lib/reservable.rb index 5b8cb503b..c751f9aec 100644 --- a/lib/reservable.rb +++ b/lib/reservable.rb @@ -3,7 +3,13 @@ module Reservable def valid_dates? - raise ArgumentError.new("Check out must be later than check in") if @check_in >= @check_out + if @check_in >= @check_out + raise ArgumentError.new("Check out must be later than check in") + + elsif @check_in < Date.today + raise ArgumentError.new("Can't reserve a room for date that's already passed") + end + end def total_cost(rate = @rate) diff --git a/lib/reservation.rb b/lib/reservation.rb index fb796d3ef..f4a6d6975 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -43,7 +43,7 @@ def ==(other_reservation) # return num_nights * rate # end - private + #private def to_s # return human readable representation diff --git a/lib/room.rb b/lib/room.rb index 9325ef4bc..6a912edf0 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -30,7 +30,6 @@ def <=>(other_room) end def reserve(start_date, end_date) - # TODO maybe return the actual reservation object here instead? And both Hotel/Block check if booked; throw out check here? raise ArgumentError.new("Room #{room_num} isn't available for the given dates") if is_booked?(start_date, end_date) @@ -38,13 +37,7 @@ def reserve(start_date, end_date) reservations << new_reservation return new_reservation - # add reservation if room is available and return true; else false - # if !is_booked?(start_date, end_date) - # reservations << ::Hotel::Reservation.new(start_date, end_date, self) # replacing room_num with self - # return true - # end - # - # return false + end def is_booked?(start_date, end_date = start_date.next_day) @@ -78,7 +71,7 @@ def is_blocked?(start_date, end_date = start_date.next_day) end - private + #private def to_s # return human readable representation @@ -90,7 +83,12 @@ def to_s s += reservation.to_s end - return s + s += "Blocks:\n" + blocks.each do |block| + s += block.to_s + end + + return (s += "\n") end diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 649a1a4b6..e96b14321 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -3,9 +3,9 @@ describe "Testing Block class" do let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } - let(:check_in) { Date.new(2017,9,3) } - let(:check_out) { Date.new(2017,9,5) } - let(:block) { Hotel::Block.new(Date.new(2017,9,3), Date.new(2017,9,5), 0.2, rooms)} + let(:check_in) { Date.today } + let(:check_out) { Date.today + 2 } + let(:block) { Hotel::Block.new(Date.today, Date.today + 2, 0.2, rooms)} describe "#initialize" do before do @@ -14,8 +14,8 @@ @rooms << Hotel::Room.new(num + 1) end - @check_in = Date.new(2017,9,3) - @check_out = Date.new(2017,9,5) + @check_in = Date.today + @check_out = Date.today + 2 @block = Hotel::Block.new(@check_in, @check_out, 0.2, @rooms) end @@ -42,15 +42,25 @@ unavail_room.reserve(@check_in, @check_out) proc { Hotel::Block.new(@check_in, @check_out, 0.2, @rooms) }.must_raise ArgumentError + end + + it "Adds itself to each room's list of blocks" do + @rooms.each do |room| + room.blocks.length.must_equal 1 + room.blocks.must_include @block + end + + new_block = Hotel::Block.new(@check_out, @check_out + 3, 0.2, @rooms) + + @rooms.each do |room| + room.blocks.length.must_equal 2 + room.blocks.must_include new_block + end end end describe "#is_available" do - # let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } - # let(:check_in) { Date.new(2017,9,3) } - # let(:check_out) { Date.new(2017,9,5) } - # let(:block) { Hotel::Block.new(Date.new(2017,9,3), Date.new(2017,9,5), 0.2, rooms)} it "Returns true if a room in the block is available" do room1 = rooms[0] @@ -67,10 +77,6 @@ end describe "#find_avail_in_block" do - # let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } - # let(:check_in) { Date.new(2017,9,3) } - # let(:check_out) { Date.new(2017,9,5) } - # let(:block) { Hotel::Block.new(Date.new(2017,9,3), Date.new(2017,9,5), 0.2, rooms)} it "Returns a list of rooms that are available in the block" do block.find_avail_in_block.must_equal rooms diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index f8dccc23a..cffbd69c0 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -46,23 +46,39 @@ end describe "#reserve" do - before do - @hotel = Hotel::Hotel.new - @room1 = @hotel.rooms[1] - end + # before do + # @hotel = Hotel::Hotel.new + # @room1 = @hotel.rooms[1] + # end + let(:hotel) { Hotel::Hotel.new } + let(:room1) { hotel.rooms[1] } + let(:check_in) { Date.today } + let(:check_out) { Date.today + 3 } it "Reserves the given room for the given dates" do - @room1.reservations.must_equal [] + room1.reservations.must_equal [] - @hotel.reserve(Date.parse('2017/9/3'), Date.parse('2017/9/5'), @room1) - new_res = Hotel::Reservation.new(Date.parse('2017/9/3'), Date.parse('2017/9/5'), @room1) - @room1.reservations[0].must_equal new_res + hotel.reserve(Date.today + 4, Date.today + 6, room1) + new_res = Hotel::Reservation.new(Date.today + 4, Date.today + 6, room1) + room1.reservations[0].must_equal new_res end - it "Raises error when it tries to reserve a room that isn't available" do - @hotel.reserve(Date.new(2017,9,5), Date.new(2017,9,8), @room1) - proc { @hotel.reserve(Date.new(2017,9,7), Date.new(2017,9,8), @room1) }.must_raise ArgumentError + it "Raises error when it tries to reserve a room that's already reserved" do + + hotel.reserve(check_in, check_out, room1) + + proc { hotel.reserve(check_in + 2, check_out, room1) }.must_raise ArgumentError + end + + it "Raises error when it tries to reserve a room that's in a block" do + + Hotel::Block.new(check_out, check_out + 3, 0.2, [room1]) + + proc { hotel.reserve(check_out, check_out + 1, room1) }.must_raise ArgumentError + + end + end describe "#find_reservations_by_date" do @@ -72,28 +88,28 @@ # res that doesn't conflict with 9/5/17 5.times do |num| room = @hotel.rooms[1 + num] - @hotel.reserve(Date.new(2017,9,1), Date.new(2017,9,4), room) + @hotel.reserve(Date.new(2018,9,1), Date.new(2018,9,4), room) end # res that does conflict with 9/5/17 5.times do |num| room = @hotel.rooms[6 + num] - @hotel.reserve(Date.new(2017,9,4), Date.new(2017,9,9), room) + @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,9), room) end # res with start date conflicting with 9/5/17 5.times do |num| room = @hotel.rooms[11 + num] - @hotel.reserve(Date.new(2017,9,5), Date.new(2017,9,9), room) + @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,9), room) end # res with end date not conflicting with 9/5/17 5.times do |num| room = @hotel.rooms[16 + num] - @hotel.reserve(Date.new(2017,9,3), Date.new(2017,9,5), room) + @hotel.reserve(Date.new(2018,9,3), Date.new(2018,9,5), room) end - @date_to_check = Date.new(2017,9,5) + @date_to_check = Date.new(2018,9,5) @sept5_res = @hotel.find_reservations_by_date(@date_to_check) end @@ -105,12 +121,12 @@ @sept5_res.length.must_equal 10 room3 = @hotel.rooms[2] - @hotel.reserve(Date.new(2017,9,4), Date.new(2017,9,5), room3) + @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,5), room3) updated_res = @hotel.find_reservations_by_date(@date_to_check) updated_res.length.must_equal 10 - @hotel.reserve(Date.new(2017,9,5), Date.new(2017,9,6), room3) + @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,6), room3) updated_res = @hotel.find_reservations_by_date(@date_to_check) updated_res.length.must_equal 11 end @@ -120,32 +136,33 @@ before do @hotel = Hotel::Hotel.new - # res that doesn't conflict with 9/5/17 - 9/7/17 + # res that doesn't conflict with 9/5/18 - 9/7/18 5.times do |num| room = @hotel.rooms[1 + num] - @hotel.reserve(Date.new(2017,9,1), Date.new(2017,9,4), room) + @hotel.reserve(Date.new(2018,9,1), Date.new(2018,9,4), room) end - # res that does conflict with 9/5/17-9/7/17 + # res that does conflict with 9/5/18-9/7/18 5.times do |num| room = @hotel.rooms[6 + num] - @hotel.reserve(Date.new(2017,9,4), Date.new(2017,9,9), room) + @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,9), room) end - # res conflicting with 9/5/17-9/7/17 + # res conflicting with 9/5/18-9/7/18 5.times do |num| room = @hotel.rooms[11 + num] - @hotel.reserve(Date.new(2017,9,5), Date.new(2017,9,9), room) + @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,9), room) end - # res not conflicting with 9/5/17-9/7/17 + # res not conflicting with 9/5/18-9/7/18 5.times do |num| room = @hotel.rooms[16 + num] - @hotel.reserve(Date.new(2017,9,3), Date.new(2017,9,5), room) + @hotel.reserve(Date.new(2018,9,3), Date.new(2018,9,5), room) end - @start_date = Date.new(2017,9,5) - @end_date = Date.new(2017,9,7) + @start_date = Date.new(2018,9,5) + @end_date = Date.new(2018,9,7) + end it "Returns a hash of rooms available for the given date range" do @@ -163,13 +180,23 @@ avail_rooms.length.must_equal expected_availability room1 = @hotel.rooms[1] - @hotel.reserve(Date.new(2017,9,4), @start_date, room1) + @hotel.reserve(Date.new(2018,9,4), @start_date, room1) @hotel.find_avail_rooms(@start_date, @end_date).must_equal avail_rooms - @hotel.reserve(@start_date, Date.new(2017,9,6), room1) + @hotel.reserve(@start_date, Date.new(2018,9,6), room1) updated_avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) updated_avail_rooms.length.must_equal expected_availability - 1 updated_avail_rooms.wont_include room1 + + room_block = (@hotel.rooms.select { |room_num, room| room_num > 15 }).values + Hotel::Block.new(@start_date, @end_date, 0.2, room_block) + updated_avail = @hotel.find_avail_rooms(@start_date, @end_date) + + updated_avail.length.must_equal expected_availability - 6 + room_block.each do |room| + updated_avail.wont_include room + end + end it "Raises ArgumentError if start date is later than end date" do diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 733a044ef..088503ce3 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -4,7 +4,7 @@ describe "#initialize" do before do @room = Hotel::Room.new(4) - @res = Hotel::Reservation.new(Date.new(2017,9,4), Date.new(2017,9,7), @room) + @res = Hotel::Reservation.new(Date.today, Date.today + 3, @room) end it "Creates a Reservation with a date range and room number" do @@ -13,16 +13,23 @@ @res.room_num.must_be_kind_of Integer end - it "Raises an error if check_out date isn't later than check_in date" do - check_in = Date.new(2017,9,5) - check_out = Date.new(2017,8,5) + describe "Testing Reservable methods" do - proc { Hotel::Reservation.new(check_in, check_out, @room) }.must_raise ArgumentError + it "Raises an error if check_out date isn't later than check_in date" do + check_in = Date.today + check_out = Date.new(2017,8,5) - check_out = Date.new(2017,9,5) - proc { Hotel::Reservation.new(check_in, check_out, @room) }.must_raise ArgumentError - end + proc { Hotel::Reservation.new(check_in, check_out, @room) }.must_raise ArgumentError + + check_out = Date.today + proc { Hotel::Reservation.new(check_in, check_out, @room) }.must_raise ArgumentError + end + it "Raises an error if check_in is before today's date" do + proc { Hotel::Reservation.new(Date.today - 1, Date.today, @room) }.must_raise ArgumentError + end + + end # move this to user interface # it "Raises an error if check in or check out aren't date objects or can't be parsed as dates" do # not_dates = ["cat", nil, 0, "", -1] @@ -42,8 +49,8 @@ describe "total_cost" do before do - @check_in = Date.new(2017,9,5) - @check_out = Date.new(2017,9,8) + @check_in = Date.today + @check_out = Date.today + 3 @res = Hotel::Reservation.new(@check_in, @check_out, Hotel::Room.new(4)) end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index 811a09a01..f7c63079d 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -20,6 +20,14 @@ proc { Hotel::Room.new(0) }.must_raise ArgumentError end + it "Creates an empty array of Reservation objects" do + @room.reservations.must_equal [] + end + + it "Creates an empty array of Block objects" do + @room.blocks.must_equal [] + end + # it "Raises an error if room number isn't between 1 & 20" do # proc { Hotel::Room.new(0) }.must_raise ArgumentError # proc { Hotel::Room.new(-2) }.must_raise ArgumentError @@ -38,8 +46,8 @@ describe "#reserve" do before do @room = Hotel::Room.new(3) - @check_in = Date.new(2017,9,5) - @check_out = Date.new(2017,9,8) + @check_in = Date.new(2018,9,5) + @check_out = Date.new(2018,9,8) @room.reserve(@check_in, @check_out) end @@ -66,38 +74,53 @@ @room.reserve(@check_out, @check_out.next_day).must_equal new_res end - # it "Returns true if the room is added" do - # @room.reserve(Date.new(2017,8,5), Date.new(2017,8,8)).must_equal true - # @room.reservations.length.must_equal 2 - # end - # - # it "Doesn't reserve the room if the room isn't available" do - # # bad_res = @room.reserve(@check_in, @check_out) - # # bad_res.must_equal false - # @room.reserve(@check_in, @check_out).must_equal false - # @room.reservations.length.must_equal 1 - # end - end describe "#is_booked?" do before do @room = Hotel::Room.new(3) - @check_in = Date.new(2017,9,5) - @check_out = Date.new(2017,9,8) + @check_in = Date.new(2018,9,5) + @check_out = Date.new(2018,9,8) @room.reserve(@check_in, @check_out) end it "Returns true if the room is booked for a given date" do - @room.is_booked?(Date.new(2017,9,6)).must_equal true - @room.is_booked?(Date.new(2017,9,8)).must_equal false + @room.is_booked?(Date.new(2018,9,6)).must_equal true + @room.is_booked?(Date.new(2018,9,8)).must_equal false - @room.reserve(Date.new(2017,9,8), Date.new(2017,9,10)) - @room.is_booked?(Date.new(2017,9,8)).must_equal true + @room.reserve(Date.new(2018,9,8), Date.new(2018,9,10)) + @room.is_booked?(Date.new(2018,9,8)).must_equal true end it "Returns true if room is booked for given date range" do - @room.is_booked?(Date.new(2017,9,6), Date.new(2017,9,8)).must_equal true + @room.is_booked?(Date.new(2018,9,6), Date.new(2018,9,8)).must_equal true + end + end + + describe "#is_blocked?" do + let(:rooms) { [2, 4, 5, 9, 20].map { |num| Hotel::Room.new(num) } } + let(:check_in) { Date.new(2018,9,3) } + let(:check_out) { Date.new(2018,9,5) } + # let(:block) { Hotel::Block.new(Date.new(2017,9,3), Date.new(2017,9,5), 0.2, rooms) } + + it "Returns true if a room is in a block for the given date range (no reservation)" do + Hotel::Block.new(check_in, check_out, 0.2, rooms) + blocked_room = rooms[0] + blocked_room.is_blocked?(check_in, check_out).must_equal true + + unblocked_room = Hotel::Room.new(15) + unblocked_room.is_blocked?(check_in, check_out).must_equal false + end + + it "Returns true if a room is in a block for the given date range (with reservation)" do + new_block = Hotel::Block.new(check_in, check_out, 0.2, rooms) + reserved_room = rooms[0] + new_block.reserve(reserved_room) + reserved_room.is_blocked?(check_in, check_out).must_equal true + + unblocked_room_with_res = Hotel::Room.new(15) + unblocked_room_with_res.reserve(check_in, check_out) + unblocked_room_with_res.is_blocked?(check_in, check_out).must_equal false end end end From cdbe45dc5d4615abe7b81130d594c3034f62bba5 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Fri, 8 Sep 2017 14:26:04 -0700 Subject: [PATCH 19/26] Refactored is_booked and is_blocked methods --- lib/room.rb | 67 ++++++++++++++++++----------------------------------- 1 file changed, 22 insertions(+), 45 deletions(-) diff --git a/lib/room.rb b/lib/room.rb index 6a912edf0..8fdb3aff0 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -14,15 +14,13 @@ class Room def initialize(room_num, rate = DEFAULT_RATE) - if room_num > 0 - @room_num = room_num - else - raise ArgumentError.new("Not a valid room number") - end + raise ArgumentError.new("Not a valid room number") if room_num < 1 + @room_num = room_num @reservations = [] @blocks = [] @rate = rate + end def <=>(other_room) @@ -37,42 +35,21 @@ def reserve(start_date, end_date) reservations << new_reservation return new_reservation - + end def is_booked?(start_date, end_date = start_date.next_day) - # don't include final date since check-out doesn't conflict with check-in of a new reservation - date_range = (start_date...end_date).to_a - - reservations.each do |reservation| - date_range.each do |date| - if reservation.include?(date) - return true - end - end - end - return false + return array_include_date?(reservations, start_date, end_date) end def is_blocked?(start_date, end_date = start_date.next_day) - date_range = (start_date...end_date).to_a - blocks.each do |block| - date_range.each do |date| - if block.include?(date) - return true - end - end - end - - return false + return array_include_date?(blocks, start_date, end_date) end - #private - def to_s # return human readable representation s = "Room number: #{room_num}\n" @@ -92,22 +69,22 @@ def to_s end - # def valid_room_num?(num) - # return num >= 1 && num <= ::Hotel::Hotel::NUM_ROOMS - # end - - # def is_available?(start_date, end_date) - # @reservations.each do |reservation| - # check_in = reservation.check_in - # check_out = reservation.check_out - # - # if date >= check_in && date < check_out - # return false - # end - # end - # - # return true - # end + private + + def array_include_date?(array, start_date, end_date) + # don't include final date since check-out doesn't conflict with check-in of a new reservation + date_range = (start_date...end_date).to_a + + array.each do |item| + date_range.each do |date| + if item.include?(date) + return true + end + end + end + + return false + end end # end of Room class From ab468cd52b269e3ad1710a7a315d8784cd64cc8d Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Fri, 8 Sep 2017 19:29:05 -0700 Subject: [PATCH 20/26] Added discounted_cost to Block class and cleaned up some code --- lib/block.rb | 11 +++++++++-- lib/hotel.rb | 17 ++++++----------- lib/room.rb | 4 ++++ specs/block_spec.rb | 24 ++++++++++++++++++------ specs/hotel_spec.rb | 31 ++++++++++++------------------- 5 files changed, 49 insertions(+), 38 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index 9fce02c9d..c2ad61cb1 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -16,13 +16,15 @@ def initialize(check_in, check_out, discount, room_block) # TODO fix discount / rate in room and block raise ArgumentError.new("Can't have more than #{MAX_ROOMS} number of rooms in a block") if room_block.length > MAX_ROOMS - raise ArgumentError.new("Can't have unavailable rooms in the block") if room_block.any? { |room| room.is_booked?(check_in, check_out) || room.is_blocked?(check_in, check_out) } + raise ArgumentError.new("Can't have unavailable rooms in the block") if room_block.any? { |room| room.unavailable?(check_in, check_out) } + + raise ArgumentError.new("Not a discounted rate") if discount >= 1 || discount <= 0 @check_in = check_in @check_out = check_out valid_dates? - @discount = discount # rate of discount as a decimal (e.g. 0.2 for 20% off) + @discount = discount # discount as decimal (e.g. 0.8 for 80% of orig rate) @room_block = room_block # array of rooms # add block to each room @@ -48,6 +50,11 @@ def reserve(room) return room.reserve(check_in, check_out) end + def discounted_cost(room) + rate = room.rate * discount + return total_cost(rate) + end + end # end of Block class end diff --git a/lib/hotel.rb b/lib/hotel.rb index e777cc107..9b959e9b6 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -23,22 +23,17 @@ def initialize(num_rooms = NUM_ROOMS) end def reserve(start_date, end_date, room) - raise ArgumentError.new("Room #{room.room_num} isn't available for the selected dates") if room.is_booked?(start_date, end_date) || room.is_blocked?(start_date, end_date) + raise ArgumentError.new("Room #{room.room_num} isn't available for the selected dates") if room.unavailable?(start_date, end_date) return room.reserve(start_date, end_date) end - # def all_reservations # is this necessary?? - # # returns a list of all reservations for the hotel - # reservations = [] - # - # rooms.each do |room| - # reservations.concat(room.reservations) - # end - # - # return reservations - # end + def block(start_date, end_date, discount, rooms) + raise ArgumentError.new("One or more rooms is unavailable for the selected dates") if rooms.any? { |room| room.unavailable?(start_date, end_date) } + + return Hotel::Block.new(start_date, end_date, discount, rooms) + end def find_reservations_by_date(date) # returns a list of all reservations for the given date diff --git a/lib/room.rb b/lib/room.rb index 8fdb3aff0..a2e3e6688 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -50,6 +50,10 @@ def is_blocked?(start_date, end_date = start_date.next_day) end + def unavailable?(start_date, end_date = start_date.next_day) + return is_booked?(start_date, end_date) || is_blocked?(start_date, end_date) + end + def to_s # return human readable representation s = "Room number: #{room_num}\n" diff --git a/specs/block_spec.rb b/specs/block_spec.rb index e96b14321..52f60be32 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -5,7 +5,8 @@ let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } let(:check_in) { Date.today } let(:check_out) { Date.today + 2 } - let(:block) { Hotel::Block.new(Date.today, Date.today + 2, 0.2, rooms)} + let(:block) { Hotel::Block.new(Date.today, Date.today + 2, 0.8, rooms)} + let(:room_to_reserve) { rooms[0] } describe "#initialize" do before do @@ -17,7 +18,7 @@ @check_in = Date.today @check_out = Date.today + 2 - @block = Hotel::Block.new(@check_in, @check_out, 0.2, @rooms) + @block = Hotel::Block.new(@check_in, @check_out, 0.8, @rooms) end it "Creates a Block with a check_in and check_out date, an array of rooms, and a discounted rate" do @@ -34,14 +35,14 @@ @rooms << Hotel::Room.new(5) @rooms << Hotel::Room.new(6) - proc {Hotel::Block.new(@check_in, @check_out, 0.2, @rooms) }.must_raise ArgumentError + proc {Hotel::Block.new(@check_in, @check_out, 0.8, @rooms) }.must_raise ArgumentError end it "Raises an error if it tries to include an unavailable room for the given dates in the block" do unavail_room = @rooms[0] unavail_room.reserve(@check_in, @check_out) - proc { Hotel::Block.new(@check_in, @check_out, 0.2, @rooms) }.must_raise ArgumentError + proc { Hotel::Block.new(@check_in, @check_out, 0.8, @rooms) }.must_raise ArgumentError end it "Adds itself to each room's list of blocks" do @@ -50,7 +51,7 @@ room.blocks.must_include @block end - new_block = Hotel::Block.new(@check_out, @check_out + 3, 0.2, @rooms) + new_block = Hotel::Block.new(@check_out, @check_out + 3, 0.8, @rooms) @rooms.each do |room| room.blocks.length.must_equal 2 @@ -99,7 +100,6 @@ end describe "#reserve" do - let(:room_to_reserve) { rooms[0] } it "Reserves a room for the dates of the block" do block_res = block.reserve(room_to_reserve) @@ -119,4 +119,16 @@ end end + describe "#discounted_cost" do + it "Returns the total cost of reserving a room in a block" do + expected_cost = (room_to_reserve.rate * 0.8) * (check_out - check_in).to_i + block.discounted_cost(room_to_reserve).must_equal expected_cost + + room_to_reserve.rate = 300 + updated_expected_cost = (room_to_reserve.rate * 0.8) * (check_out - check_in).to_i + block.discounted_cost(room_to_reserve).must_equal updated_expected_cost + + end + end + end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index cffbd69c0..0b3a46325 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -1,16 +1,13 @@ require_relative 'spec_helper' describe "Testing Hotel class" do + let(:hotel) { Hotel::Hotel.new } + describe "#initialize" do - before do - @hotel = Hotel::Hotel.new - end it "Creates a hotel class with a hash of rooms" do - @hotel.must_be_instance_of Hotel::Hotel - - rooms = @hotel.rooms - rooms.must_be_kind_of Hash + hotel.must_be_instance_of Hotel::Hotel + hotel.rooms.must_be_kind_of Hash rooms.each do |room_num, room| room.must_be_instance_of Hotel::Room @@ -18,7 +15,7 @@ end it "Creates a hotel with NUM_ROOMS num of rooms as the default" do - @hotel.rooms.length.must_equal Hotel::Hotel::NUM_ROOMS + hotel.rooms.length.must_equal Hotel::Hotel::NUM_ROOMS end it "Creates a hotel with the specified number of rooms" do @@ -46,10 +43,6 @@ end describe "#reserve" do - # before do - # @hotel = Hotel::Hotel.new - # @room1 = @hotel.rooms[1] - # end let(:hotel) { Hotel::Hotel.new } let(:room1) { hotel.rooms[1] } let(:check_in) { Date.today } @@ -85,40 +78,40 @@ before do @hotel = Hotel::Hotel.new - # res that doesn't conflict with 9/5/17 + # res that doesn't conflict with 9/5/18 5.times do |num| room = @hotel.rooms[1 + num] @hotel.reserve(Date.new(2018,9,1), Date.new(2018,9,4), room) end - # res that does conflict with 9/5/17 + # res that does conflict with 9/5/18 5.times do |num| room = @hotel.rooms[6 + num] @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,9), room) end - # res with start date conflicting with 9/5/17 + # res with start date conflicting with 9/5/18 5.times do |num| room = @hotel.rooms[11 + num] @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,9), room) end - # res with end date not conflicting with 9/5/17 + # res with end date not conflicting with 9/5/18 5.times do |num| room = @hotel.rooms[16 + num] @hotel.reserve(Date.new(2018,9,3), Date.new(2018,9,5), room) end @date_to_check = Date.new(2018,9,5) - @sept5_res = @hotel.find_reservations_by_date(@date_to_check) + @res_list = @hotel.find_reservations_by_date(@date_to_check) end it "Returns a list of reservations for that date" do - @sept5_res.must_be_kind_of Array + @res_list.must_be_kind_of Array end it "Doesn't include reservations w/a check-out date matching date" do - @sept5_res.length.must_equal 10 + @res_list.length.must_equal 10 room3 = @hotel.rooms[2] @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,5), room3) From d03b7a1d282ad96d648039a067c44e167187ab78 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Fri, 8 Sep 2017 22:09:37 -0700 Subject: [PATCH 21/26] Refactored room tests and reservable.rb --- lib/block.rb | 3 +- lib/reservable.rb | 41 +++- lib/reservation.rb | 2 +- lib/room.rb | 6 +- specs/block_spec.rb | 268 ++++++++++++------------- specs/hotel_spec.rb | 408 +++++++++++++++++++------------------- specs/reservation_spec.rb | 150 +++++++------- specs/room_spec.rb | 101 +++++----- 8 files changed, 501 insertions(+), 478 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index c2ad61cb1..ecfeeb3f0 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -13,7 +13,6 @@ class Block def initialize(check_in, check_out, discount, room_block) # check input - # TODO fix discount / rate in room and block raise ArgumentError.new("Can't have more than #{MAX_ROOMS} number of rooms in a block") if room_block.length > MAX_ROOMS raise ArgumentError.new("Can't have unavailable rooms in the block") if room_block.any? { |room| room.unavailable?(check_in, check_out) } @@ -22,7 +21,7 @@ def initialize(check_in, check_out, discount, room_block) @check_in = check_in @check_out = check_out - valid_dates? + valid_dates?(check_in, check_out) @discount = discount # discount as decimal (e.g. 0.8 for 80% of orig rate) @room_block = room_block # array of rooms diff --git a/lib/reservable.rb b/lib/reservable.rb index c751f9aec..3b9a92cec 100644 --- a/lib/reservable.rb +++ b/lib/reservable.rb @@ -1,15 +1,44 @@ require 'date' +require_relative 'room' module Reservable - def valid_dates? - if @check_in >= @check_out - raise ArgumentError.new("Check out must be later than check in") + def valid_dates?(start_date, end_date) + # if @check_in >= @check_out + # raise ArgumentError.new("Check out must be later than check in") + # + # elsif @check_in < Date.today + # raise ArgumentError.new("Can't reserve a room for date that's already passed") + # end + raise TypeError.new("#{start_date} must be of type Date") if start_date.class != Date + raise TypeError.new("#{end_date} must be of type Date") if end_date.class != Date + raise ArgumentError.new("Check out must be later than check in") if start_date >= end_date + raise ArgumentError.new("Can't reserve a room for a date before today") if start_date < Date.today - elsif @check_in < Date.today - raise ArgumentError.new("Can't reserve a room for date that's already passed") - end + end + + def valid_room_num?(num) + raise TypeError.new("#{num} must of type Integer") if num.class != Integer + raise ArgumentError.new("Invalid number of rooms") if num < 1 + end + + def valid_room_block?(room_block, check_in, check_out) + raise TypeError.new("Block of rooms must be an array of Room objects") if room_block.class != Array || room_block[0].class != Hotel::Room + + raise ArgumentError.new("Can't have more than #{Hotel::Block::MAX_ROOMS} number of rooms in a block") if room_block.length > Hotel::Block::MAX_ROOMS + + raise ArgumentError.new("Can't have unavailable rooms in the block") if room_block.any? { |room| room.unavailable?(check_in, check_out) } + end + + def valid_rate?(rate) + raise TypeError.new("#{rate} must be of type Integer") if rate.class != Integer + raise ArgumentError.new("Rate must be greater than 0") if rate < 1 + end + def valid_discount(discount) + # must be decimal representing percentage of full cost (e.g. 0.8 for 80% of orig rate) + raise TypeError.new("#{discount} must be of type Float") if discount.class != Float + raise ArgumentError.new("Not a discounted rate") if discount >= 1 || discount <= 0 end def total_cost(rate = @rate) diff --git a/lib/reservation.rb b/lib/reservation.rb index f4a6d6975..fe5262add 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -25,7 +25,7 @@ def initialize(check_in, check_out, room) @room_num = room.room_num @rate = room.rate - valid_dates? + valid_dates?(check_in, check_out) end diff --git a/lib/room.rb b/lib/room.rb index a2e3e6688..ee1c616e4 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -1,10 +1,12 @@ require_relative 'reservation' +require_relative 'reservable' module Hotel # NUM_ROOMS = 20 class Room + include Reservable include Comparable DEFAULT_RATE = 200 @@ -14,7 +16,9 @@ class Room def initialize(room_num, rate = DEFAULT_RATE) - raise ArgumentError.new("Not a valid room number") if room_num < 1 + #raise ArgumentError.new("Not a valid room number") if room_num < 1 + valid_room_num?(room_num) + valid_rate?(rate) @room_num = room_num @reservations = [] diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 52f60be32..cb25f800e 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -1,134 +1,134 @@ -require_relative 'spec_helper' - -describe "Testing Block class" do - - let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } - let(:check_in) { Date.today } - let(:check_out) { Date.today + 2 } - let(:block) { Hotel::Block.new(Date.today, Date.today + 2, 0.8, rooms)} - let(:room_to_reserve) { rooms[0] } - - describe "#initialize" do - before do - @rooms = [] - 4.times do |num| - @rooms << Hotel::Room.new(num + 1) - end - - @check_in = Date.today - @check_out = Date.today + 2 - - @block = Hotel::Block.new(@check_in, @check_out, 0.8, @rooms) - end - - it "Creates a Block with a check_in and check_out date, an array of rooms, and a discounted rate" do - room1 = @block.room_block[0] - - @block.must_be_instance_of Hotel::Block - @block.check_in.must_equal @check_in - @block.check_out.must_equal @check_out - @block.room_block.must_equal @rooms - (@block.discount * room1.rate).must_be :<, room1.rate - end - - it "Creates a block with no more than MAX_ROOMS num of rooms" do - @rooms << Hotel::Room.new(5) - @rooms << Hotel::Room.new(6) - - proc {Hotel::Block.new(@check_in, @check_out, 0.8, @rooms) }.must_raise ArgumentError - end - - it "Raises an error if it tries to include an unavailable room for the given dates in the block" do - unavail_room = @rooms[0] - unavail_room.reserve(@check_in, @check_out) - - proc { Hotel::Block.new(@check_in, @check_out, 0.8, @rooms) }.must_raise ArgumentError - end - - it "Adds itself to each room's list of blocks" do - @rooms.each do |room| - room.blocks.length.must_equal 1 - room.blocks.must_include @block - end - - new_block = Hotel::Block.new(@check_out, @check_out + 3, 0.8, @rooms) - - @rooms.each do |room| - room.blocks.length.must_equal 2 - room.blocks.must_include new_block - end - - end - end - - describe "#is_available" do - - it "Returns true if a room in the block is available" do - room1 = rooms[0] - block.is_available?(room1).must_equal true - - room1.reserve(check_in, check_out) - block.is_available?(room1).must_equal false - end - - it "Raises an argument error if room isn't in the block" do - wrong_room = Hotel::Room.new(6) - proc { block.is_available?(wrong_room) }.must_raise ArgumentError - end - end - - describe "#find_avail_in_block" do - - it "Returns a list of rooms that are available in the block" do - block.find_avail_in_block.must_equal rooms - - rooms[0].reserve(check_in, check_out) - rooms[1].reserve(check_in, check_out) - - block.find_avail_in_block.must_equal rooms[2..-1] - end - - it "Returns an empty array if no rooms available" do - block.find_avail_in_block.must_equal rooms - - 5.times do |num| - rooms[num].reserve(check_in, check_out) - end - - block.find_avail_in_block.must_equal [] - end - end - - describe "#reserve" do - - it "Reserves a room for the dates of the block" do - block_res = block.reserve(room_to_reserve) - - block_res.check_in.must_equal check_in - block_res.check_out.must_equal check_out - end - - it "Raises an error if it tries to reserve a room not in the block" do - room_outside_block = Hotel::Room.new(20) - proc { block.reserve(room_outside_block) }.must_raise ArgumentError - end - - it "Raises an error if it tries to reserve an room that's already reserved" do - block.reserve(room_to_reserve) - proc {block.reserve(room_to_reserve) }.must_raise ArgumentError - end - end - - describe "#discounted_cost" do - it "Returns the total cost of reserving a room in a block" do - expected_cost = (room_to_reserve.rate * 0.8) * (check_out - check_in).to_i - block.discounted_cost(room_to_reserve).must_equal expected_cost - - room_to_reserve.rate = 300 - updated_expected_cost = (room_to_reserve.rate * 0.8) * (check_out - check_in).to_i - block.discounted_cost(room_to_reserve).must_equal updated_expected_cost - - end - end - -end +# require_relative 'spec_helper' +# +# describe "Testing Block class" do +# +# let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } +# let(:check_in) { Date.today } +# let(:check_out) { Date.today + 2 } +# let(:block) { Hotel::Block.new(Date.today, Date.today + 2, 0.8, rooms)} +# let(:room_to_reserve) { rooms[0] } +# +# describe "#initialize" do +# before do +# @rooms = [] +# 4.times do |num| +# @rooms << Hotel::Room.new(num + 1) +# end +# +# @check_in = Date.today +# @check_out = Date.today + 2 +# +# @block = Hotel::Block.new(@check_in, @check_out, 0.8, @rooms) +# end +# +# it "Creates a Block with a check_in and check_out date, an array of rooms, and a discounted rate" do +# room1 = @block.room_block[0] +# +# @block.must_be_instance_of Hotel::Block +# @block.check_in.must_equal @check_in +# @block.check_out.must_equal @check_out +# @block.room_block.must_equal @rooms +# (@block.discount * room1.rate).must_be :<, room1.rate +# end +# +# it "Creates a block with no more than MAX_ROOMS num of rooms" do +# @rooms << Hotel::Room.new(5) +# @rooms << Hotel::Room.new(6) +# +# proc {Hotel::Block.new(@check_in, @check_out, 0.8, @rooms) }.must_raise ArgumentError +# end +# +# it "Raises an error if it tries to include an unavailable room for the given dates in the block" do +# unavail_room = @rooms[0] +# unavail_room.reserve(@check_in, @check_out) +# +# proc { Hotel::Block.new(@check_in, @check_out, 0.8, @rooms) }.must_raise ArgumentError +# end +# +# it "Adds itself to each room's list of blocks" do +# @rooms.each do |room| +# room.blocks.length.must_equal 1 +# room.blocks.must_include @block +# end +# +# new_block = Hotel::Block.new(@check_out, @check_out + 3, 0.8, @rooms) +# +# @rooms.each do |room| +# room.blocks.length.must_equal 2 +# room.blocks.must_include new_block +# end +# +# end +# end +# +# describe "#is_available" do +# +# it "Returns true if a room in the block is available" do +# room1 = rooms[0] +# block.is_available?(room1).must_equal true +# +# room1.reserve(check_in, check_out) +# block.is_available?(room1).must_equal false +# end +# +# it "Raises an argument error if room isn't in the block" do +# wrong_room = Hotel::Room.new(6) +# proc { block.is_available?(wrong_room) }.must_raise ArgumentError +# end +# end +# +# describe "#find_avail_in_block" do +# +# it "Returns a list of rooms that are available in the block" do +# block.find_avail_in_block.must_equal rooms +# +# rooms[0].reserve(check_in, check_out) +# rooms[1].reserve(check_in, check_out) +# +# block.find_avail_in_block.must_equal rooms[2..-1] +# end +# +# it "Returns an empty array if no rooms available" do +# block.find_avail_in_block.must_equal rooms +# +# 5.times do |num| +# rooms[num].reserve(check_in, check_out) +# end +# +# block.find_avail_in_block.must_equal [] +# end +# end +# +# describe "#reserve" do +# +# it "Reserves a room for the dates of the block" do +# block_res = block.reserve(room_to_reserve) +# +# block_res.check_in.must_equal check_in +# block_res.check_out.must_equal check_out +# end +# +# it "Raises an error if it tries to reserve a room not in the block" do +# room_outside_block = Hotel::Room.new(20) +# proc { block.reserve(room_outside_block) }.must_raise ArgumentError +# end +# +# it "Raises an error if it tries to reserve an room that's already reserved" do +# block.reserve(room_to_reserve) +# proc {block.reserve(room_to_reserve) }.must_raise ArgumentError +# end +# end +# +# describe "#discounted_cost" do +# it "Returns the total cost of reserving a room in a block" do +# expected_cost = (room_to_reserve.rate * 0.8) * (check_out - check_in).to_i +# block.discounted_cost(room_to_reserve).must_equal expected_cost +# +# room_to_reserve.rate = 300 +# updated_expected_cost = (room_to_reserve.rate * 0.8) * (check_out - check_in).to_i +# block.discounted_cost(room_to_reserve).must_equal updated_expected_cost +# +# end +# end +# +# end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 0b3a46325..d23e19560 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -1,204 +1,204 @@ -require_relative 'spec_helper' - -describe "Testing Hotel class" do - let(:hotel) { Hotel::Hotel.new } - - describe "#initialize" do - - it "Creates a hotel class with a hash of rooms" do - hotel.must_be_instance_of Hotel::Hotel - hotel.rooms.must_be_kind_of Hash - - rooms.each do |room_num, room| - room.must_be_instance_of Hotel::Room - end - end - - it "Creates a hotel with NUM_ROOMS num of rooms as the default" do - hotel.rooms.length.must_equal Hotel::Hotel::NUM_ROOMS - end - - it "Creates a hotel with the specified number of rooms" do - num_rooms = 17 - new_hotel = Hotel::Hotel.new(num_rooms) - new_hotel.rooms.length.must_equal num_rooms - end - - it "Raises an error if not passed a valid number for num of rooms" do - proc { Hotel::Hotel.new(-1) }.must_raise ArgumentError - proc { Hotel::Hotel.new(0) }.must_raise ArgumentError - end - - it "Creates rooms with room nums between 1 & specified number of rooms" do - num_rooms = 25 - big_hotel = Hotel::Hotel.new(num_rooms) - num_big_hotel_rooms = big_hotel.rooms.length - - big_hotel.rooms.each do |room_num, room| - room_num.must_be :>=, 1 - room_num.must_be :<=, num_big_hotel_rooms - end - end - - end - - describe "#reserve" do - let(:hotel) { Hotel::Hotel.new } - let(:room1) { hotel.rooms[1] } - let(:check_in) { Date.today } - let(:check_out) { Date.today + 3 } - - it "Reserves the given room for the given dates" do - room1.reservations.must_equal [] - - hotel.reserve(Date.today + 4, Date.today + 6, room1) - new_res = Hotel::Reservation.new(Date.today + 4, Date.today + 6, room1) - room1.reservations[0].must_equal new_res - end - - it "Raises error when it tries to reserve a room that's already reserved" do - - hotel.reserve(check_in, check_out, room1) - - proc { hotel.reserve(check_in + 2, check_out, room1) }.must_raise ArgumentError - - end - - it "Raises error when it tries to reserve a room that's in a block" do - - Hotel::Block.new(check_out, check_out + 3, 0.2, [room1]) - - proc { hotel.reserve(check_out, check_out + 1, room1) }.must_raise ArgumentError - - end - - end - - describe "#find_reservations_by_date" do - before do - @hotel = Hotel::Hotel.new - - # res that doesn't conflict with 9/5/18 - 5.times do |num| - room = @hotel.rooms[1 + num] - @hotel.reserve(Date.new(2018,9,1), Date.new(2018,9,4), room) - end - - # res that does conflict with 9/5/18 - 5.times do |num| - room = @hotel.rooms[6 + num] - @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,9), room) - end - - # res with start date conflicting with 9/5/18 - 5.times do |num| - room = @hotel.rooms[11 + num] - @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,9), room) - end - - # res with end date not conflicting with 9/5/18 - 5.times do |num| - room = @hotel.rooms[16 + num] - @hotel.reserve(Date.new(2018,9,3), Date.new(2018,9,5), room) - end - - @date_to_check = Date.new(2018,9,5) - @res_list = @hotel.find_reservations_by_date(@date_to_check) - end - - it "Returns a list of reservations for that date" do - @res_list.must_be_kind_of Array - end - - it "Doesn't include reservations w/a check-out date matching date" do - @res_list.length.must_equal 10 - - room3 = @hotel.rooms[2] - @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,5), room3) - - updated_res = @hotel.find_reservations_by_date(@date_to_check) - updated_res.length.must_equal 10 - - @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,6), room3) - updated_res = @hotel.find_reservations_by_date(@date_to_check) - updated_res.length.must_equal 11 - end - end - - describe "#find_avail_rooms" do - before do - @hotel = Hotel::Hotel.new - - # res that doesn't conflict with 9/5/18 - 9/7/18 - 5.times do |num| - room = @hotel.rooms[1 + num] - @hotel.reserve(Date.new(2018,9,1), Date.new(2018,9,4), room) - end - - # res that does conflict with 9/5/18-9/7/18 - 5.times do |num| - room = @hotel.rooms[6 + num] - @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,9), room) - end - - # res conflicting with 9/5/18-9/7/18 - 5.times do |num| - room = @hotel.rooms[11 + num] - @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,9), room) - end - - # res not conflicting with 9/5/18-9/7/18 - 5.times do |num| - room = @hotel.rooms[16 + num] - @hotel.reserve(Date.new(2018,9,3), Date.new(2018,9,5), room) - end - - @start_date = Date.new(2018,9,5) - @end_date = Date.new(2018,9,7) - - end - - it "Returns a hash of rooms available for the given date range" do - avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) - avail_rooms.must_be_kind_of Hash - - avail_rooms.each do |room_num, room| - room.must_be_instance_of Hotel::Room - end - end - - it "Counts rooms as available if check_out date equals start_date of another reservation" do - expected_availability = 10 - avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) - avail_rooms.length.must_equal expected_availability - - room1 = @hotel.rooms[1] - @hotel.reserve(Date.new(2018,9,4), @start_date, room1) - @hotel.find_avail_rooms(@start_date, @end_date).must_equal avail_rooms - - @hotel.reserve(@start_date, Date.new(2018,9,6), room1) - updated_avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) - updated_avail_rooms.length.must_equal expected_availability - 1 - updated_avail_rooms.wont_include room1 - - room_block = (@hotel.rooms.select { |room_num, room| room_num > 15 }).values - Hotel::Block.new(@start_date, @end_date, 0.2, room_block) - updated_avail = @hotel.find_avail_rooms(@start_date, @end_date) - - updated_avail.length.must_equal expected_availability - 6 - room_block.each do |room| - updated_avail.wont_include room - end - - end - - it "Raises ArgumentError if start date is later than end date" do - room1 = @hotel.rooms[1] - proc { @hotel.find_avail_rooms(@end_date, @start_date, room1) }.must_raise ArgumentError - - proc { @hotel.find_avail_rooms(@end_date, @end_date, room1) }.must_raise ArgumentError - end - end - - -end +# require_relative 'spec_helper' +# +# describe "Testing Hotel class" do +# let(:hotel) { Hotel::Hotel.new } +# +# describe "#initialize" do +# +# it "Creates a hotel class with a hash of rooms" do +# hotel.must_be_instance_of Hotel::Hotel +# hotel.rooms.must_be_kind_of Hash +# +# rooms.each do |room_num, room| +# room.must_be_instance_of Hotel::Room +# end +# end +# +# it "Creates a hotel with NUM_ROOMS num of rooms as the default" do +# hotel.rooms.length.must_equal Hotel::Hotel::NUM_ROOMS +# end +# +# it "Creates a hotel with the specified number of rooms" do +# num_rooms = 17 +# new_hotel = Hotel::Hotel.new(num_rooms) +# new_hotel.rooms.length.must_equal num_rooms +# end +# +# it "Raises an error if not passed a valid number for num of rooms" do +# proc { Hotel::Hotel.new(-1) }.must_raise ArgumentError +# proc { Hotel::Hotel.new(0) }.must_raise ArgumentError +# end +# +# it "Creates rooms with room nums between 1 & specified number of rooms" do +# num_rooms = 25 +# big_hotel = Hotel::Hotel.new(num_rooms) +# num_big_hotel_rooms = big_hotel.rooms.length +# +# big_hotel.rooms.each do |room_num, room| +# room_num.must_be :>=, 1 +# room_num.must_be :<=, num_big_hotel_rooms +# end +# end +# +# end +# +# describe "#reserve" do +# let(:hotel) { Hotel::Hotel.new } +# let(:room1) { hotel.rooms[1] } +# let(:check_in) { Date.today } +# let(:check_out) { Date.today + 3 } +# +# it "Reserves the given room for the given dates" do +# room1.reservations.must_equal [] +# +# hotel.reserve(Date.today + 4, Date.today + 6, room1) +# new_res = Hotel::Reservation.new(Date.today + 4, Date.today + 6, room1) +# room1.reservations[0].must_equal new_res +# end +# +# it "Raises error when it tries to reserve a room that's already reserved" do +# +# hotel.reserve(check_in, check_out, room1) +# +# proc { hotel.reserve(check_in + 2, check_out, room1) }.must_raise ArgumentError +# +# end +# +# it "Raises error when it tries to reserve a room that's in a block" do +# +# Hotel::Block.new(check_out, check_out + 3, 0.2, [room1]) +# +# proc { hotel.reserve(check_out, check_out + 1, room1) }.must_raise ArgumentError +# +# end +# +# end +# +# describe "#find_reservations_by_date" do +# before do +# @hotel = Hotel::Hotel.new +# +# # res that doesn't conflict with 9/5/18 +# 5.times do |num| +# room = @hotel.rooms[1 + num] +# @hotel.reserve(Date.new(2018,9,1), Date.new(2018,9,4), room) +# end +# +# # res that does conflict with 9/5/18 +# 5.times do |num| +# room = @hotel.rooms[6 + num] +# @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,9), room) +# end +# +# # res with start date conflicting with 9/5/18 +# 5.times do |num| +# room = @hotel.rooms[11 + num] +# @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,9), room) +# end +# +# # res with end date not conflicting with 9/5/18 +# 5.times do |num| +# room = @hotel.rooms[16 + num] +# @hotel.reserve(Date.new(2018,9,3), Date.new(2018,9,5), room) +# end +# +# @date_to_check = Date.new(2018,9,5) +# @res_list = @hotel.find_reservations_by_date(@date_to_check) +# end +# +# it "Returns a list of reservations for that date" do +# @res_list.must_be_kind_of Array +# end +# +# it "Doesn't include reservations w/a check-out date matching date" do +# @res_list.length.must_equal 10 +# +# room3 = @hotel.rooms[2] +# @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,5), room3) +# +# updated_res = @hotel.find_reservations_by_date(@date_to_check) +# updated_res.length.must_equal 10 +# +# @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,6), room3) +# updated_res = @hotel.find_reservations_by_date(@date_to_check) +# updated_res.length.must_equal 11 +# end +# end +# +# describe "#find_avail_rooms" do +# before do +# @hotel = Hotel::Hotel.new +# +# # res that doesn't conflict with 9/5/18 - 9/7/18 +# 5.times do |num| +# room = @hotel.rooms[1 + num] +# @hotel.reserve(Date.new(2018,9,1), Date.new(2018,9,4), room) +# end +# +# # res that does conflict with 9/5/18-9/7/18 +# 5.times do |num| +# room = @hotel.rooms[6 + num] +# @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,9), room) +# end +# +# # res conflicting with 9/5/18-9/7/18 +# 5.times do |num| +# room = @hotel.rooms[11 + num] +# @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,9), room) +# end +# +# # res not conflicting with 9/5/18-9/7/18 +# 5.times do |num| +# room = @hotel.rooms[16 + num] +# @hotel.reserve(Date.new(2018,9,3), Date.new(2018,9,5), room) +# end +# +# @start_date = Date.new(2018,9,5) +# @end_date = Date.new(2018,9,7) +# +# end +# +# it "Returns a hash of rooms available for the given date range" do +# avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) +# avail_rooms.must_be_kind_of Hash +# +# avail_rooms.each do |room_num, room| +# room.must_be_instance_of Hotel::Room +# end +# end +# +# it "Counts rooms as available if check_out date equals start_date of another reservation" do +# expected_availability = 10 +# avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) +# avail_rooms.length.must_equal expected_availability +# +# room1 = @hotel.rooms[1] +# @hotel.reserve(Date.new(2018,9,4), @start_date, room1) +# @hotel.find_avail_rooms(@start_date, @end_date).must_equal avail_rooms +# +# @hotel.reserve(@start_date, Date.new(2018,9,6), room1) +# updated_avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) +# updated_avail_rooms.length.must_equal expected_availability - 1 +# updated_avail_rooms.wont_include room1 +# +# room_block = (@hotel.rooms.select { |room_num, room| room_num > 15 }).values +# Hotel::Block.new(@start_date, @end_date, 0.2, room_block) +# updated_avail = @hotel.find_avail_rooms(@start_date, @end_date) +# +# updated_avail.length.must_equal expected_availability - 6 +# room_block.each do |room| +# updated_avail.wont_include room +# end +# +# end +# +# it "Raises ArgumentError if start date is later than end date" do +# room1 = @hotel.rooms[1] +# proc { @hotel.find_avail_rooms(@end_date, @start_date, room1) }.must_raise ArgumentError +# +# proc { @hotel.find_avail_rooms(@end_date, @end_date, room1) }.must_raise ArgumentError +# end +# end +# +# +# end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 088503ce3..a4a7b29ff 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -1,75 +1,75 @@ -require_relative 'spec_helper' - -describe "Testing Reservation class" do - describe "#initialize" do - before do - @room = Hotel::Room.new(4) - @res = Hotel::Reservation.new(Date.today, Date.today + 3, @room) - end - - it "Creates a Reservation with a date range and room number" do - @res.check_in.must_be_instance_of Date - @res.check_out.must_be_instance_of Date - @res.room_num.must_be_kind_of Integer - end - - describe "Testing Reservable methods" do - - it "Raises an error if check_out date isn't later than check_in date" do - check_in = Date.today - check_out = Date.new(2017,8,5) - - proc { Hotel::Reservation.new(check_in, check_out, @room) }.must_raise ArgumentError - - check_out = Date.today - proc { Hotel::Reservation.new(check_in, check_out, @room) }.must_raise ArgumentError - end - - it "Raises an error if check_in is before today's date" do - proc { Hotel::Reservation.new(Date.today - 1, Date.today, @room) }.must_raise ArgumentError - end - - end - # move this to user interface - # it "Raises an error if check in or check out aren't date objects or can't be parsed as dates" do - # not_dates = ["cat", nil, 0, "", -1] - # valid_date = '2017/9/5' - # - # not_dates.each do |item| - # proc { Hotel::Reservation.new(valid_date, item, 20) }.must_raise ArgumentError - # end - # - # not_dates.each do |item| - # proc {Hotel::Reservation.new(item, valid_date, 18) }.must_raise ArgumentError - # end - # - # end - - end - - describe "total_cost" do - before do - @check_in = Date.today - @check_out = Date.today + 3 - @res = Hotel::Reservation.new(@check_in, @check_out, Hotel::Room.new(4)) - end - - it "Returns the total cost of the reservation" do - num_nights = (@check_out - @check_in).to_i - expected_cost = num_nights * (Hotel::Room::DEFAULT_RATE) - - @res.total_cost.must_equal expected_cost - end - - end - - # describe "#self.find" do - # before do - # date_to_check = Date.new(2017,9,5) - # end - # - # it "Returns a list of Reservations for a given date" do - # - # end - # end -end +# require_relative 'spec_helper' +# +# describe "Testing Reservation class" do +# describe "#initialize" do +# before do +# @room = Hotel::Room.new(4) +# @res = Hotel::Reservation.new(Date.today, Date.today + 3, @room) +# end +# +# it "Creates a Reservation with a date range and room number" do +# @res.check_in.must_be_instance_of Date +# @res.check_out.must_be_instance_of Date +# @res.room_num.must_be_kind_of Integer +# end +# +# describe "Testing Reservable methods" do +# +# it "Raises an error if check_out date isn't later than check_in date" do +# check_in = Date.today +# check_out = Date.new(2017,8,5) +# +# proc { Hotel::Reservation.new(check_in, check_out, @room) }.must_raise ArgumentError +# +# check_out = Date.today +# proc { Hotel::Reservation.new(check_in, check_out, @room) }.must_raise ArgumentError +# end +# +# it "Raises an error if check_in is before today's date" do +# proc { Hotel::Reservation.new(Date.today - 1, Date.today, @room) }.must_raise ArgumentError +# end +# +# end +# # move this to user interface +# # it "Raises an error if check in or check out aren't date objects or can't be parsed as dates" do +# # not_dates = ["cat", nil, 0, "", -1] +# # valid_date = '2017/9/5' +# # +# # not_dates.each do |item| +# # proc { Hotel::Reservation.new(valid_date, item, 20) }.must_raise ArgumentError +# # end +# # +# # not_dates.each do |item| +# # proc {Hotel::Reservation.new(item, valid_date, 18) }.must_raise ArgumentError +# # end +# # +# # end +# +# end +# +# describe "total_cost" do +# before do +# @check_in = Date.today +# @check_out = Date.today + 3 +# @res = Hotel::Reservation.new(@check_in, @check_out, Hotel::Room.new(4)) +# end +# +# it "Returns the total cost of the reservation" do +# num_nights = (@check_out - @check_in).to_i +# expected_cost = num_nights * (Hotel::Room::DEFAULT_RATE) +# +# @res.total_cost.must_equal expected_cost +# end +# +# end +# +# # describe "#self.find" do +# # before do +# # date_to_check = Date.new(2017,9,5) +# # end +# # +# # it "Returns a list of Reservations for a given date" do +# # +# # end +# # end +# end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index f7c63079d..ea5e70935 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -1,126 +1,117 @@ require_relative 'spec_helper' describe "Testing Room class" do + + let(:room) { Hotel::Room.new(4) } + let(:today) { Date.today } + let(:three_days_later) { Date.today + 3 } + describe "#initialize" do - before do - @room = Hotel::Room.new(4) - end - it "Creates a Room object" do - @room.must_be_instance_of Hotel::Room + it "Creates a Room object with the given room number" do + room.must_be_instance_of Hotel::Room + room.room_num.must_equal 4 end it "Sets a default rate if no rate provided" do - @room.rate.must_equal Hotel::Room::DEFAULT_RATE + room.rate.must_equal Hotel::Room::DEFAULT_RATE + + expected_rate = 300 + Hotel::Room.new(4, 300).rate.must_equal expected_rate end it "Raises an error if room number isn't a valid num" do # doesn't test for room num > 20 b/c optional param in Hotel allows for more rooms proc { Hotel::Room.new(-1) }.must_raise ArgumentError proc { Hotel::Room.new(0) }.must_raise ArgumentError + proc { Hotel::Room.new("cat") }.must_raise TypeError + proc { Hotel::Room.new(4.23) }.must_raise TypeError + proc { Hotel::Room.new(nil) }.must_raise TypeError + end it "Creates an empty array of Reservation objects" do - @room.reservations.must_equal [] + room.reservations.must_equal [] end it "Creates an empty array of Block objects" do - @room.blocks.must_equal [] + room.blocks.must_equal [] end - # it "Raises an error if room number isn't between 1 & 20" do - # proc { Hotel::Room.new(0) }.must_raise ArgumentError - # proc { Hotel::Room.new(-2) }.must_raise ArgumentError - # proc { Hotel::Room.new(21) }.must_raise ArgumentError - # end - # - # moving input check to user interface - # it "Raises an error if room number isn't an integer" do - # proc { Hotel::Room.new("cat") }.must_raise ArgumentError - # proc { Hotel::Room.new(4.23) }.must_raise ArgumentError - # proc { Hotel::Room.new(nil) }.must_raise ArgumentError - # end - end describe "#reserve" do before do - @room = Hotel::Room.new(3) - @check_in = Date.new(2018,9,5) - @check_out = Date.new(2018,9,8) - - @room.reserve(@check_in, @check_out) + room.reserve(today, three_days_later) end it "Adds the reservation to the room's reservations array" do - @room.reservations.length.must_equal 1 - @room.reservations[0].must_be_kind_of Hotel::Reservation + room.reservations.length.must_equal 1 + room.reservations[0].must_be_instance_of Hotel::Reservation end it "Reserves the room for the specified start and end dates" do - res = @room.reservations[0] + res = room.reservations[0] - res.check_in.must_equal @check_in - res.check_out.must_equal @check_out + res.check_in.must_equal today + res.check_out.must_equal three_days_later end it "Raises an error if the room isn't available" do - proc { @room.reserve(@check_in, @check_out) }.must_raise ArgumentError + proc { room.reserve(today, three_days_later) }.must_raise ArgumentError end it "Returns the new reservation if the reservation is created" do - new_res = Hotel::Reservation.new(@check_out, @check_out.next_day, @room) + new_res = Hotel::Reservation.new(three_days_later, three_days_later.next_day, room) - @room.reserve(@check_out, @check_out.next_day).must_equal new_res + room.reserve(three_days_later, three_days_later.next_day).must_equal new_res end end describe "#is_booked?" do before do - @room = Hotel::Room.new(3) - @check_in = Date.new(2018,9,5) - @check_out = Date.new(2018,9,8) - @room.reserve(@check_in, @check_out) + room.reserve(today, three_days_later) end - it "Returns true if the room is booked for a given date" do - @room.is_booked?(Date.new(2018,9,6)).must_equal true - @room.is_booked?(Date.new(2018,9,8)).must_equal false + it "Returns true if the room is booked for a given date (one param + optional param)" do + room.is_booked?(today).must_equal true + room.is_booked?(today.next_day).must_equal true + room.is_booked?(three_days_later).must_equal false - @room.reserve(Date.new(2018,9,8), Date.new(2018,9,10)) - @room.is_booked?(Date.new(2018,9,8)).must_equal true + room.reserve(three_days_later, three_days_later + 2) + room.is_booked?(three_days_later).must_equal true end - it "Returns true if room is booked for given date range" do - @room.is_booked?(Date.new(2018,9,6), Date.new(2018,9,8)).must_equal true + it "Returns true if room is booked for given date range (two params)" do + room.is_booked?(today - 2, today).must_equal false + room.is_booked?(today + 1, three_days_later).must_equal true end end describe "#is_blocked?" do + let(:rooms) { [2, 4, 5, 9, 20].map { |num| Hotel::Room.new(num) } } - let(:check_in) { Date.new(2018,9,3) } - let(:check_out) { Date.new(2018,9,5) } - # let(:block) { Hotel::Block.new(Date.new(2017,9,3), Date.new(2017,9,5), 0.2, rooms) } + let(:discount) { 0.8 } it "Returns true if a room is in a block for the given date range (no reservation)" do - Hotel::Block.new(check_in, check_out, 0.2, rooms) + Hotel::Block.new(today, three_days_later, discount, rooms) blocked_room = rooms[0] - blocked_room.is_blocked?(check_in, check_out).must_equal true + blocked_room.is_blocked?(today - 1, today + 1).must_equal true unblocked_room = Hotel::Room.new(15) - unblocked_room.is_blocked?(check_in, check_out).must_equal false + unblocked_room.is_blocked?(today, three_days_later).must_equal false end it "Returns true if a room is in a block for the given date range (with reservation)" do - new_block = Hotel::Block.new(check_in, check_out, 0.2, rooms) + new_block = Hotel::Block.new(today, three_days_later, discount, rooms) reserved_room = rooms[0] new_block.reserve(reserved_room) - reserved_room.is_blocked?(check_in, check_out).must_equal true + reserved_room.is_blocked?(today, three_days_later).must_equal true unblocked_room_with_res = Hotel::Room.new(15) - unblocked_room_with_res.reserve(check_in, check_out) - unblocked_room_with_res.is_blocked?(check_in, check_out).must_equal false + unblocked_room_with_res.reserve(today, three_days_later) + unblocked_room_with_res.is_blocked?(today, three_days_later).must_equal false end end end From 88e38579439f11705e65c2c434772a8b8c65c382 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Sun, 10 Sep 2017 16:46:00 -0700 Subject: [PATCH 22/26] Added self.all and self.find methods to Block, Resv, and Room classes --- lib/block.rb | 44 ++++-- lib/hotel.rb | 9 +- lib/reservable.rb | 19 ++- lib/reservation.rb | 66 ++++---- lib/room.rb | 58 +++++-- specs/block_spec.rb | 311 ++++++++++++++++++++++---------------- specs/reservation_spec.rb | 198 +++++++++++++++--------- specs/room_spec.rb | 117 +++++++++++--- 8 files changed, 517 insertions(+), 305 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index ecfeeb3f0..466c651c1 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -7,21 +7,21 @@ module Hotel class Block include Reservable + @@all_blocks = [] + MAX_ROOMS = 5 - attr_accessor :check_in, :check_out, :discount, :room_block + attr_accessor :check_in, :check_out, :discount, :room_block, :block_id def initialize(check_in, check_out, discount, room_block) # check input - raise ArgumentError.new("Can't have more than #{MAX_ROOMS} number of rooms in a block") if room_block.length > MAX_ROOMS - - raise ArgumentError.new("Can't have unavailable rooms in the block") if room_block.any? { |room| room.unavailable?(check_in, check_out) } - - raise ArgumentError.new("Not a discounted rate") if discount >= 1 || discount <= 0 + valid_dates?(check_in, check_out) + valid_room_block?(room_block, check_in, check_out) + valid_discount?(discount) + @block_id = @@all_blocks.length + 1 @check_in = check_in @check_out = check_out - valid_dates?(check_in, check_out) @discount = discount # discount as decimal (e.g. 0.8 for 80% of orig rate) @room_block = room_block # array of rooms @@ -29,22 +29,24 @@ def initialize(check_in, check_out, discount, room_block) # add block to each room room_block.cycle(1) { |room| room.blocks << self } + @@all_blocks << self + end - def is_available?(room) + def room_available?(room) raise ArgumentError.new("Room #{room.room_num} isn't in the block") if !room_block.include?(room) - return !room.is_booked?(check_in, check_out) + return !room.booked?(check_in, check_out) end def find_avail_in_block - return room_block.select { |room| is_available?(room) } + return room_block.select { |room| room_available?(room) } end def reserve(room) raise ArgumentError.new("Room #{room.room_num} isn't in the block") if !room_block.include?(room) - raise ArgumentError.new("Room #{room.room_num} isn't available for the selected dates") if room.is_booked?(check_in, check_out) + raise ArgumentError.new("Room #{room.room_num} isn't available for the selected dates") if room.booked?(check_in, check_out) return room.reserve(check_in, check_out) end @@ -54,6 +56,26 @@ def discounted_cost(room) return total_cost(rate) end + def self.all + return @@all_blocks + end + + def self.clear + @@all_blocks = [] + end + + def self.find(block_id) + blocks = self.all + + blocks.each do |block| + if block.block_id == block_id + return block + end + end + + return nil + end + end # end of Block class end diff --git a/lib/hotel.rb b/lib/hotel.rb index 9b959e9b6..6ae9ee205 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -55,17 +55,10 @@ def find_avail_rooms(start_date, end_date) # check input raise ArgumentError.new("End date must be after start date") if start_date >= end_date - return rooms.reject { |room_num, room| room.is_booked?(start_date, end_date) || room.is_blocked?(start_date, end_date) } + return rooms.reject { |room_num, room| room.booked?(start_date, end_date) || room.blocked?(start_date, end_date) } end - # private - - # - # def is_valid?(num) move integer check to user input - # return num.is_a?(Integer) && num > 0 - # end - end # end of Hotel class end diff --git a/lib/reservable.rb b/lib/reservable.rb index 3b9a92cec..6878155a3 100644 --- a/lib/reservable.rb +++ b/lib/reservable.rb @@ -4,12 +4,7 @@ module Reservable def valid_dates?(start_date, end_date) - # if @check_in >= @check_out - # raise ArgumentError.new("Check out must be later than check in") - # - # elsif @check_in < Date.today - # raise ArgumentError.new("Can't reserve a room for date that's already passed") - # end + raise TypeError.new("#{start_date} must be of type Date") if start_date.class != Date raise TypeError.new("#{end_date} must be of type Date") if end_date.class != Date raise ArgumentError.new("Check out must be later than check in") if start_date >= end_date @@ -22,6 +17,10 @@ def valid_room_num?(num) raise ArgumentError.new("Invalid number of rooms") if num < 1 end + def valid_room?(room) + raise TypeError.new("#{room} must be of type Hotel::Room") if room.class != Hotel::Room + end + def valid_room_block?(room_block, check_in, check_out) raise TypeError.new("Block of rooms must be an array of Room objects") if room_block.class != Array || room_block[0].class != Hotel::Room @@ -35,7 +34,7 @@ def valid_rate?(rate) raise ArgumentError.new("Rate must be greater than 0") if rate < 1 end - def valid_discount(discount) + def valid_discount?(discount) # must be decimal representing percentage of full cost (e.g. 0.8 for 80% of orig rate) raise TypeError.new("#{discount} must be of type Float") if discount.class != Float raise ArgumentError.new("Not a discounted rate") if discount >= 1 || discount <= 0 @@ -46,6 +45,12 @@ def total_cost(rate = @rate) return (num_nights * rate) end +# TODO finish implementing + # def total_cost(room_num) + # num_nights = (@check_out - @check_in).to_i + # return (num_nights * ) + # end + def include?(date) return date >= @check_in && date < @check_out end diff --git a/lib/reservation.rb b/lib/reservation.rb index fe5262add..49dd1355a 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -8,25 +8,22 @@ class Reservation include Comparable include Reservable - attr_accessor :check_in, :check_out, :room_num, :rate + @@all_reservations = [] + + attr_accessor :check_in, :check_out, :room_num, :rate, :reservation_id def initialize(check_in, check_out, room) - # # check input move check input type != date to user interface - # check_in = check_date(check_in) - # check_out = check_date(check_out) - # - # raise ArgumentError.new("Invalid date(s)") if check_in == nil || check_out == nil + valid_dates?(check_in, check_out) + valid_room?(room) - # raise ArgumentError.new("Check out must be later than check in") if check_in >= check_out - # @reservation_id = rand(100000..999999) + @reservation_id = @@all_reservations.length + 1 @check_in = check_in @check_out = check_out @room_num = room.room_num @rate = room.rate - valid_dates?(check_in, check_out) - + @@all_reservations << self end def ==(other_reservation) @@ -37,13 +34,33 @@ def ==(other_reservation) # return date >= check_in && date < check_out # end - # def total_cost - # num_nights = (check_out - check_in).to_i - # # return num_nights * ::Hotel::Room::DEFAULT_RATE - # return num_nights * rate - # end + def total_cost + num_nights = (check_out - check_in).to_i + # return num_nights * ::Hotel::Room::DEFAULT_RATE + return num_nights * rate + end + + def self.all + return @@all_reservations + end + + def self.find(reservation_id) + reservations = self.all + + reservations.each do |reservation| + if reservation.reservation_id == reservation_id + return reservation + end + end + + return nil + end + + def self.clear + # clears all reservations (for testing) + @@all_reservations = [] + end - #private def to_s # return human readable representation @@ -56,22 +73,5 @@ def to_s end - # private - # move check_date to user interface - # def check_date(date) - # if date.is_a?Date - # return date - # else - # begin date = Date.parse(date) - # rescue ArgumentError - # return nil - # rescue TypeError - # return nil - # else - # return date - # end - # end - # end - end # end of Reservation class end diff --git a/lib/room.rb b/lib/room.rb index ee1c616e4..1e207ec58 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -3,12 +3,12 @@ module Hotel - # NUM_ROOMS = 20 - class Room include Reservable include Comparable + @@all_rooms = [] + DEFAULT_RATE = 200 attr_reader :room_num, :reservations, :blocks @@ -16,15 +16,16 @@ class Room def initialize(room_num, rate = DEFAULT_RATE) - #raise ArgumentError.new("Not a valid room number") if room_num < 1 valid_room_num?(room_num) valid_rate?(rate) @room_num = room_num - @reservations = [] - @blocks = [] + @reservations = [] # array of res_ids + @blocks = [] # array of block_ids @rate = rate + @@all_rooms << self + end def <=>(other_room) @@ -33,29 +34,50 @@ def <=>(other_room) def reserve(start_date, end_date) - raise ArgumentError.new("Room #{room_num} isn't available for the given dates") if is_booked?(start_date, end_date) + raise ArgumentError.new("Room #{room_num} isn't available for the given dates") if booked?(start_date, end_date) new_reservation = ::Hotel::Reservation.new(start_date, end_date, self) - reservations << new_reservation + reservations << new_reservation#.reservation_id return new_reservation end - def is_booked?(start_date, end_date = start_date.next_day) + def booked?(start_date, end_date = start_date.next_day) return array_include_date?(reservations, start_date, end_date) end - def is_blocked?(start_date, end_date = start_date.next_day) + def blocked?(start_date, end_date = start_date.next_day) return array_include_date?(blocks, start_date, end_date) end def unavailable?(start_date, end_date = start_date.next_day) - return is_booked?(start_date, end_date) || is_blocked?(start_date, end_date) + return booked?(start_date, end_date) || blocked?(start_date, end_date) + end + + def self.all + # @all_rooms.sort! + return @@all_rooms + end + + def self.find(room_num) + rooms = self.all + + rooms.each do |room| + if room.room_num == room_num + return room + end + end + + return nil + end + + def self.clear + @@all_rooms = [] end def to_s @@ -65,13 +87,13 @@ def to_s s += "Reservations:\n" reservations.each do |reservation| - s += reservation.to_s + s += Hotel::Reservation.find(reservation).to_s end - s += "Blocks:\n" - blocks.each do |block| - s += block.to_s - end + # s += "Blocks:\n" + # blocks.each do |block| + # s += block.to_s + # end return (s += "\n") @@ -97,3 +119,9 @@ def array_include_date?(array, start_date, end_date) end # end of Room class end + +room = Hotel::Room.new(1) +room2 = Hotel::Room.new(2) + +puts Hotel::Room.all +# puts Hotel::Room.all_rooms diff --git a/specs/block_spec.rb b/specs/block_spec.rb index cb25f800e..146610afe 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -1,134 +1,177 @@ -# require_relative 'spec_helper' -# -# describe "Testing Block class" do -# -# let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } -# let(:check_in) { Date.today } -# let(:check_out) { Date.today + 2 } -# let(:block) { Hotel::Block.new(Date.today, Date.today + 2, 0.8, rooms)} -# let(:room_to_reserve) { rooms[0] } -# -# describe "#initialize" do -# before do -# @rooms = [] -# 4.times do |num| -# @rooms << Hotel::Room.new(num + 1) -# end -# -# @check_in = Date.today -# @check_out = Date.today + 2 -# -# @block = Hotel::Block.new(@check_in, @check_out, 0.8, @rooms) -# end -# -# it "Creates a Block with a check_in and check_out date, an array of rooms, and a discounted rate" do -# room1 = @block.room_block[0] -# -# @block.must_be_instance_of Hotel::Block -# @block.check_in.must_equal @check_in -# @block.check_out.must_equal @check_out -# @block.room_block.must_equal @rooms -# (@block.discount * room1.rate).must_be :<, room1.rate -# end -# -# it "Creates a block with no more than MAX_ROOMS num of rooms" do -# @rooms << Hotel::Room.new(5) -# @rooms << Hotel::Room.new(6) -# -# proc {Hotel::Block.new(@check_in, @check_out, 0.8, @rooms) }.must_raise ArgumentError -# end -# -# it "Raises an error if it tries to include an unavailable room for the given dates in the block" do -# unavail_room = @rooms[0] -# unavail_room.reserve(@check_in, @check_out) -# -# proc { Hotel::Block.new(@check_in, @check_out, 0.8, @rooms) }.must_raise ArgumentError -# end -# -# it "Adds itself to each room's list of blocks" do -# @rooms.each do |room| -# room.blocks.length.must_equal 1 -# room.blocks.must_include @block -# end -# -# new_block = Hotel::Block.new(@check_out, @check_out + 3, 0.8, @rooms) -# -# @rooms.each do |room| -# room.blocks.length.must_equal 2 -# room.blocks.must_include new_block -# end -# -# end -# end -# -# describe "#is_available" do -# -# it "Returns true if a room in the block is available" do -# room1 = rooms[0] -# block.is_available?(room1).must_equal true -# -# room1.reserve(check_in, check_out) -# block.is_available?(room1).must_equal false -# end -# -# it "Raises an argument error if room isn't in the block" do -# wrong_room = Hotel::Room.new(6) -# proc { block.is_available?(wrong_room) }.must_raise ArgumentError -# end -# end -# -# describe "#find_avail_in_block" do -# -# it "Returns a list of rooms that are available in the block" do -# block.find_avail_in_block.must_equal rooms -# -# rooms[0].reserve(check_in, check_out) -# rooms[1].reserve(check_in, check_out) -# -# block.find_avail_in_block.must_equal rooms[2..-1] -# end -# -# it "Returns an empty array if no rooms available" do -# block.find_avail_in_block.must_equal rooms -# -# 5.times do |num| -# rooms[num].reserve(check_in, check_out) -# end -# -# block.find_avail_in_block.must_equal [] -# end -# end -# -# describe "#reserve" do -# -# it "Reserves a room for the dates of the block" do -# block_res = block.reserve(room_to_reserve) -# -# block_res.check_in.must_equal check_in -# block_res.check_out.must_equal check_out -# end -# -# it "Raises an error if it tries to reserve a room not in the block" do -# room_outside_block = Hotel::Room.new(20) -# proc { block.reserve(room_outside_block) }.must_raise ArgumentError -# end -# -# it "Raises an error if it tries to reserve an room that's already reserved" do -# block.reserve(room_to_reserve) -# proc {block.reserve(room_to_reserve) }.must_raise ArgumentError -# end -# end -# -# describe "#discounted_cost" do -# it "Returns the total cost of reserving a room in a block" do -# expected_cost = (room_to_reserve.rate * 0.8) * (check_out - check_in).to_i -# block.discounted_cost(room_to_reserve).must_equal expected_cost -# -# room_to_reserve.rate = 300 -# updated_expected_cost = (room_to_reserve.rate * 0.8) * (check_out - check_in).to_i -# block.discounted_cost(room_to_reserve).must_equal updated_expected_cost -# -# end -# end -# -# end +require_relative 'spec_helper' + +describe "Testing Block class" do + + let(:rooms) { (1..5).to_a.map { |num| Hotel::Room.new(num) } } + let(:today) { Date.today } + let(:two_days_later) { Date.today + 2 } + let(:block) { Hotel::Block.new(Date.today, Date.today + 2, 0.8, rooms)} + let(:room_to_reserve) { rooms[0] } + + describe "#initialize" do + + it "Creates a Block with a check_in and check_out date, an array of rooms, and a discounted rate" do + room1 = block.room_block[0] + + block.must_be_instance_of Hotel::Block + block.check_in.must_equal today + block.check_out.must_equal two_days_later + block.room_block.must_equal rooms + (block.discount * room1.rate).must_be :<, room1.rate + end + + it "Creates a block id based that auto-increments based on length of @@all_blocks" do + Hotel::Block.clear + + block1 = Hotel::Block.new(today, two_days_later, 0.8, rooms) + block1.block_id.must_equal 1 + + block2 = Hotel::Block.new(two_days_later, two_days_later + 1, 0.8, rooms) + block2.block_id.must_equal 2 + end + + it "Creates a block with no more than MAX_ROOMS num of rooms" do + rooms << Hotel::Room.new(6) + + proc {Hotel::Block.new(today, two_days_later, 0.8, rooms) }.must_raise ArgumentError + end + + it "Raises an error if it tries to include an unavailable room for the given dates in the block" do + unavail_room = rooms[0] + unavail_room.reserve(today, two_days_later) + + proc { Hotel::Block.new(today, two_days_later, 0.8, rooms) }.must_raise ArgumentError + end + + it "Adds itself to each room's list of blocks" do + block1 = Hotel::Block.new(today, two_days_later, 0.8, rooms) + + rooms.each do |room| + room.blocks.length.must_equal 1 + room.blocks.must_include block1 + end + + block2 = Hotel::Block.new(two_days_later, two_days_later + 3, 0.8, rooms) + + rooms.each do |room| + room.blocks.length.must_equal 2 + room.blocks.must_include block2 + end + + end + end + + describe "#self.clear" do + it "Clears all Block instances from the @@all_blocks array" do + Hotel::Block.clear + Hotel::Block.all.must_equal [] + + new_block = Hotel::Block.new(today, two_days_later, 0.8, rooms) + Hotel::Block.all.must_equal [new_block] + + Hotel::Block.clear + Hotel::Block.all.must_equal [] + + end + end + + describe "#self.all" do + it "Returns an array of all Block instances" do + Hotel::Block.clear + + block1 = Hotel::Block.new(today, two_days_later, 0.8, rooms) + Hotel::Block.all.must_equal [block1] + + block2 = Hotel::Block.new(two_days_later, two_days_later + 1, 0.8, rooms) + Hotel::Block.all.must_equal [block1, block2] + end + end + + describe "#self.find" do + + before do + Hotel::Block.clear + + @block_to_find = Hotel::Block.new(today, two_days_later, 0.8, rooms) + Hotel::Block.new(two_days_later, two_days_later + 1, 0.8, rooms) + end + + it "Returns a block matching the given block_id" do + Hotel::Block.find(1).must_equal @block_to_find + end + + it "Returns nil if no such block found" do + Hotel::Block.find(5).must_be_nil + end + end + + describe "#is_available" do + + it "Returns true if a room in the block is available" do + block.room_available?(room_to_reserve).must_equal true + + room_to_reserve.reserve(today, two_days_later) + block.room_available?(room_to_reserve).must_equal false + end + + it "Raises an argument error if room isn't in the block" do + wrong_room = Hotel::Room.new(6) + proc { block.room_available?(wrong_room) }.must_raise ArgumentError + end + end + + describe "#find_avail_in_block" do + + it "Returns a list of rooms that are available in the block" do + block.find_avail_in_block.must_equal rooms + + rooms[0].reserve(today, two_days_later) + rooms[1].reserve(today, two_days_later) + + block.find_avail_in_block.must_equal rooms[2..-1] + end + + it "Returns an empty array if no rooms available" do + block.find_avail_in_block.must_equal rooms + + 5.times do |num| + rooms[num].reserve(today, two_days_later) + end + + block.find_avail_in_block.must_equal [] + end + end + + describe "#reserve" do + + it "Reserves a room for the dates of the block" do + block_res = block.reserve(room_to_reserve) + + block_res.check_in.must_equal today + block_res.check_out.must_equal two_days_later + end + + it "Raises an error if it tries to reserve a room not in the block" do + room_outside_block = Hotel::Room.new(20) + proc { block.reserve(room_outside_block) }.must_raise ArgumentError + end + + it "Raises an error if it tries to reserve an room that's already reserved" do + block.reserve(room_to_reserve) + proc {block.reserve(room_to_reserve) }.must_raise ArgumentError + end + end + + xdescribe "#discounted_cost" do + it "Returns the total cost of reserving a room in a block" do + expected_cost = (room_to_reserve.rate * 0.8) * (check_out - check_in).to_i + block.discounted_cost(room_to_reserve).must_equal expected_cost + + room_to_reserve.rate = 300 + updated_expected_cost = (room_to_reserve.rate * 0.8) * (check_out - check_in).to_i + block.discounted_cost(room_to_reserve).must_equal updated_expected_cost + + end + end + +end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index a4a7b29ff..ebeb2c5ac 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -1,75 +1,123 @@ -# require_relative 'spec_helper' -# -# describe "Testing Reservation class" do -# describe "#initialize" do -# before do -# @room = Hotel::Room.new(4) -# @res = Hotel::Reservation.new(Date.today, Date.today + 3, @room) -# end -# -# it "Creates a Reservation with a date range and room number" do -# @res.check_in.must_be_instance_of Date -# @res.check_out.must_be_instance_of Date -# @res.room_num.must_be_kind_of Integer -# end -# -# describe "Testing Reservable methods" do -# -# it "Raises an error if check_out date isn't later than check_in date" do -# check_in = Date.today -# check_out = Date.new(2017,8,5) -# -# proc { Hotel::Reservation.new(check_in, check_out, @room) }.must_raise ArgumentError -# -# check_out = Date.today -# proc { Hotel::Reservation.new(check_in, check_out, @room) }.must_raise ArgumentError -# end -# -# it "Raises an error if check_in is before today's date" do -# proc { Hotel::Reservation.new(Date.today - 1, Date.today, @room) }.must_raise ArgumentError -# end -# -# end -# # move this to user interface -# # it "Raises an error if check in or check out aren't date objects or can't be parsed as dates" do -# # not_dates = ["cat", nil, 0, "", -1] -# # valid_date = '2017/9/5' -# # -# # not_dates.each do |item| -# # proc { Hotel::Reservation.new(valid_date, item, 20) }.must_raise ArgumentError -# # end -# # -# # not_dates.each do |item| -# # proc {Hotel::Reservation.new(item, valid_date, 18) }.must_raise ArgumentError -# # end -# # -# # end -# -# end -# -# describe "total_cost" do -# before do -# @check_in = Date.today -# @check_out = Date.today + 3 -# @res = Hotel::Reservation.new(@check_in, @check_out, Hotel::Room.new(4)) -# end -# -# it "Returns the total cost of the reservation" do -# num_nights = (@check_out - @check_in).to_i -# expected_cost = num_nights * (Hotel::Room::DEFAULT_RATE) -# -# @res.total_cost.must_equal expected_cost -# end -# -# end -# -# # describe "#self.find" do -# # before do -# # date_to_check = Date.new(2017,9,5) -# # end -# # -# # it "Returns a list of Reservations for a given date" do -# # -# # end -# # end -# end +require_relative 'spec_helper' + +describe "Testing Reservation class" do + + let(:room) { Hotel::Room.new(4) } + let(:res) { Hotel::Reservation.new(Date.today, Date.today + 2, Hotel::Room.new(5)) } + let(:today) { Date.today } + let(:two_days_later) { Date.today + 2 } + + describe "#initialize" do + + it "Creates a Reservation with a date range and room number" do + + res.check_in.must_equal today + res.check_out.must_equal two_days_later + res.room_num.must_equal 5 + + end + + it "Creates a reservation_id that auto-increments based on length of @@all_reservations" do + Hotel::Reservation.clear + + res1 = Hotel::Reservation.new(today, two_days_later, room) + res1.reservation_id.must_equal 1 + + res2 = Hotel::Reservation.new(today, two_days_later, Hotel::Room.new(1)) + res2.reservation_id.must_equal 2 + end + + describe "Testing Reservable mixin" do + + it "Raises an error if check in or check out aren't dates" do + + not_dates = ["cat", nil, 0, -3.14] + + not_dates.each do |invalid_input| + proc { Hotel::Reservation.new(invalid_input, two_days_later, room) }.must_raise TypeError + end + + not_dates.each do |invalid_input| + proc { Hotel::Reservation.new(today, invalid_input, room) }.must_raise TypeError + end + + end + + it "Raises an error if check in is before today's date" do + proc { Hotel::Reservation.new(today.prev_day, today, room) }.must_raise ArgumentError + end + + it "Raises an error if check out isn't later than check in " do + proc { Hotel::Reservation.new(two_days_later, today) }.must_raise ArgumentError + + proc { Hotel::Reservation.new(today, today) }.must_raise ArgumentError + end + + end + + end + + describe "#self.clear" do + it "Clears all Reservation instances from the all_reservations array" do + Hotel::Reservation.clear + Hotel::Reservation.all.must_equal [] + + new_res = Hotel::Reservation.new(today, two_days_later, room) + Hotel::Reservation.all.must_equal [new_res] + + Hotel::Reservation.clear + Hotel::Reservation.all.must_equal [] + end + end + + describe "#self.all" do + it "Returns a list of all Reservation instances" do + Hotel::Reservation.clear + + res1 = Hotel::Reservation.new(today, two_days_later, room) + Hotel::Reservation.all.must_equal [res1] + + res2 = Hotel::Reservation.new(today, two_days_later, Hotel::Room.new(1)) + Hotel::Reservation.all.must_equal [res1, res2] + end + end + + describe "#self.find" do + it "Returns a reservation matching the given reservation_id" do + + end + end + + describe "total_cost (in Reservable)" do + # before do + # @check_in = Date.today + # @check_out = Date.today + 3 + # @res = Hotel::Reservation.new(@check_in, @check_out, Hotel::Room.new(4)) + # end + + xit "Returns the total cost of the reservation" do + + res = Hotel::Reservation.new(today, two_days_later, room) + num_nights = (two_days_later - today).to_i + expected_cost = num_nights * room.rate + res.total_cost.must_equal expected_cost + + new_rate = 300 + room.rate = new_rate + # binding.pry + res.total_cost.must_equal (num_nights * new_rate) + + end + + end + + # describe "#self.find" do + # before do + # date_to_check = Date.new(2017,9,5) + # end + # + # it "Returns a list of Reservations for a given date" do + # + # end + # end +end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index ea5e70935..028339813 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -20,16 +20,6 @@ Hotel::Room.new(4, 300).rate.must_equal expected_rate end - it "Raises an error if room number isn't a valid num" do - # doesn't test for room num > 20 b/c optional param in Hotel allows for more rooms - proc { Hotel::Room.new(-1) }.must_raise ArgumentError - proc { Hotel::Room.new(0) }.must_raise ArgumentError - proc { Hotel::Room.new("cat") }.must_raise TypeError - proc { Hotel::Room.new(4.23) }.must_raise TypeError - proc { Hotel::Room.new(nil) }.must_raise TypeError - - end - it "Creates an empty array of Reservation objects" do room.reservations.must_equal [] end @@ -38,23 +28,96 @@ room.blocks.must_equal [] end + describe "Testing Reservable mixin" do + + it "Raises an error if room number isn't a valid num" do + # doesn't test for room num > 20 b/c optional param in Hotel allows for more rooms + proc { Hotel::Room.new(-1) }.must_raise ArgumentError + proc { Hotel::Room.new(0) }.must_raise ArgumentError + proc { Hotel::Room.new("cat") }.must_raise TypeError + proc { Hotel::Room.new(4.23) }.must_raise TypeError + proc { Hotel::Room.new(nil) }.must_raise TypeError + + end + + it "Raises an error if rate isn't a valid num" do + proc { Hotel::Room.new(4, -1) }.must_raise ArgumentError + proc { Hotel::Room.new(4, 0) }.must_raise ArgumentError + proc { Hotel::Room.new(4, "cat") }.must_raise TypeError + proc { Hotel::Room.new(4, 4.23) }.must_raise TypeError + proc { Hotel::Room.new(4, nil) }.must_raise TypeError + + end + end + + end + + describe "#self.clear" do + it "Clears all room instances from class array of all_rooms" do + Hotel::Room.clear + Hotel::Room.all.must_equal [] + + Hotel::Room.new(2) + Hotel::Room.all.length.must_equal 1 + + Hotel::Room.clear + Hotel::Room.all.must_equal [] + end + + end + + describe "#self.all" do + it "Returns a list of all Room instances" do + Hotel::Room.clear + + room1 = Hotel::Room.new(1) + Hotel::Room.all.must_equal [room1] + + room2 = Hotel::Room.new(2) + Hotel::Room.all.must_equal [room1, room2] + end + end + + describe "#self.find" do + before do + Hotel::Room.clear + + 5.times do |num| + Hotel::Room.new(num + 1) + end + end + + it "Returns a room object matching the given room number" do + room = Hotel::Room.new(1) + + Hotel::Room.find(1).must_equal room + end + + it "Returns nil if no such room is found" do + Hotel::Room.find(6).must_be_nil + end end describe "#reserve" do + before do room.reserve(today, three_days_later) end it "Adds the reservation to the room's reservations array" do + room.reservations.length.must_equal 1 room.reservations[0].must_be_instance_of Hotel::Reservation + end it "Reserves the room for the specified start and end dates" do + res = room.reservations[0] res.check_in.must_equal today res.check_out.must_equal three_days_later + end it "Raises an error if the room isn't available" do @@ -62,56 +125,66 @@ end it "Returns the new reservation if the reservation is created" do + new_res = Hotel::Reservation.new(three_days_later, three_days_later.next_day, room) room.reserve(three_days_later, three_days_later.next_day).must_equal new_res + end end - describe "#is_booked?" do + describe "#booked?" do before do room.reserve(today, three_days_later) end it "Returns true if the room is booked for a given date (one param + optional param)" do - room.is_booked?(today).must_equal true - room.is_booked?(today.next_day).must_equal true - room.is_booked?(three_days_later).must_equal false + + room.booked?(today).must_equal true + room.booked?(today.next_day).must_equal true + room.booked?(three_days_later).must_equal false room.reserve(three_days_later, three_days_later + 2) - room.is_booked?(three_days_later).must_equal true + room.booked?(three_days_later).must_equal true + end it "Returns true if room is booked for given date range (two params)" do - room.is_booked?(today - 2, today).must_equal false - room.is_booked?(today + 1, three_days_later).must_equal true + + room.booked?(today - 2, today).must_equal false + room.booked?(today + 1, three_days_later).must_equal true + end end - describe "#is_blocked?" do + describe "#blocked?" do let(:rooms) { [2, 4, 5, 9, 20].map { |num| Hotel::Room.new(num) } } let(:discount) { 0.8 } it "Returns true if a room is in a block for the given date range (no reservation)" do + Hotel::Block.new(today, three_days_later, discount, rooms) blocked_room = rooms[0] - blocked_room.is_blocked?(today - 1, today + 1).must_equal true + blocked_room.blocked?(today - 1, today + 1).must_equal true unblocked_room = Hotel::Room.new(15) - unblocked_room.is_blocked?(today, three_days_later).must_equal false + unblocked_room.blocked?(today, three_days_later).must_equal false + end it "Returns true if a room is in a block for the given date range (with reservation)" do + new_block = Hotel::Block.new(today, three_days_later, discount, rooms) reserved_room = rooms[0] new_block.reserve(reserved_room) - reserved_room.is_blocked?(today, three_days_later).must_equal true + reserved_room.blocked?(today, three_days_later).must_equal true unblocked_room_with_res = Hotel::Room.new(15) unblocked_room_with_res.reserve(today, three_days_later) - unblocked_room_with_res.is_blocked?(today, three_days_later).must_equal false + unblocked_room_with_res.blocked?(today, three_days_later).must_equal false + end end end From 815ac804f881b64c3995141c951853bfbc35512d Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Sun, 10 Sep 2017 23:20:41 -0700 Subject: [PATCH 23/26] Refactored to use self methods and class vars --- lib/block.rb | 14 +- lib/hotel.rb | 23 +-- lib/reservable.rb | 27 +--- lib/reservation.rb | 16 +- lib/room.rb | 24 +-- specs/hotel_spec.rb | 331 +++++++++++++++----------------------- specs/reservation_spec.rb | 78 ++++++--- specs/room_spec.rb | 10 +- 8 files changed, 225 insertions(+), 298 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index 466c651c1..b2af4aeb5 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -15,9 +15,9 @@ class Block def initialize(check_in, check_out, discount, room_block) # check input - valid_dates?(check_in, check_out) - valid_room_block?(room_block, check_in, check_out) - valid_discount?(discount) + check_dates(check_in, check_out) + check_room_block(room_block, check_in, check_out) + check_discount(discount) @block_id = @@all_blocks.length + 1 @check_in = check_in @@ -48,12 +48,8 @@ def reserve(room) raise ArgumentError.new("Room #{room.room_num} isn't available for the selected dates") if room.booked?(check_in, check_out) - return room.reserve(check_in, check_out) - end - - def discounted_cost(room) - rate = room.rate * discount - return total_cost(rate) + discounted_rate = discount * room.rate + return room.reserve(check_in, check_out, discounted_rate) end def self.all diff --git a/lib/hotel.rb b/lib/hotel.rb index 6ae9ee205..69f72414c 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -4,6 +4,7 @@ module Hotel class Hotel + include Reservable NUM_ROOMS = 20 @@ -11,7 +12,7 @@ class Hotel def initialize(num_rooms = NUM_ROOMS) # check input - raise ArgumentError.new("Not a valid number of rooms") if num_rooms < 1 + check_room_num(num_rooms) @rooms = {} @@ -23,37 +24,29 @@ def initialize(num_rooms = NUM_ROOMS) end def reserve(start_date, end_date, room) - raise ArgumentError.new("Room #{room.room_num} isn't available for the selected dates") if room.unavailable?(start_date, end_date) + check_dates(start_date, end_date) + + raise ArgumentError.new("Room #{room.room_num} isn't available for the selected dates") if room.booked?(start_date, end_date) || room.blocked?(start_date, end_date) return room.reserve(start_date, end_date) end def block(start_date, end_date, discount, rooms) - raise ArgumentError.new("One or more rooms is unavailable for the selected dates") if rooms.any? { |room| room.unavailable?(start_date, end_date) } + raise ArgumentError.new("One or more rooms is unavailable for the selected dates") if rooms.any? { |room| room.booked?(start_date, end_date) || room.blocked?(start_date, end_date) } return Hotel::Block.new(start_date, end_date, discount, rooms) end def find_reservations_by_date(date) - # returns a list of all reservations for the given date - # doesn't include rooms where check-out date == date - reservations = [] - - rooms.each do |room_num, room| - reservations.concat(room.reservations.select { |reservation| reservation.include? date }) - end - - # organize using group_by? (room_num) - return reservations - + return ::Hotel::Reservation.find_by_date(date) end def find_avail_rooms(start_date, end_date) # returns a hash of rooms available in the date range # check input - raise ArgumentError.new("End date must be after start date") if start_date >= end_date + check_dates(start_date, end_date) return rooms.reject { |room_num, room| room.booked?(start_date, end_date) || room.blocked?(start_date, end_date) } diff --git a/lib/reservable.rb b/lib/reservable.rb index 6878155a3..00b35d235 100644 --- a/lib/reservable.rb +++ b/lib/reservable.rb @@ -3,7 +3,7 @@ module Reservable - def valid_dates?(start_date, end_date) + def check_dates(start_date, end_date) raise TypeError.new("#{start_date} must be of type Date") if start_date.class != Date raise TypeError.new("#{end_date} must be of type Date") if end_date.class != Date @@ -12,45 +12,34 @@ def valid_dates?(start_date, end_date) end - def valid_room_num?(num) + def check_room_num(num) raise TypeError.new("#{num} must of type Integer") if num.class != Integer raise ArgumentError.new("Invalid number of rooms") if num < 1 end - def valid_room?(room) + def check_room(room) raise TypeError.new("#{room} must be of type Hotel::Room") if room.class != Hotel::Room end - def valid_room_block?(room_block, check_in, check_out) + def check_room_block(room_block, check_in, check_out) raise TypeError.new("Block of rooms must be an array of Room objects") if room_block.class != Array || room_block[0].class != Hotel::Room - raise ArgumentError.new("Can't have more than #{Hotel::Block::MAX_ROOMS} number of rooms in a block") if room_block.length > Hotel::Block::MAX_ROOMS + raise ArgumentError.new("Invalid number of rooms in block") if room_block.length > Hotel::Block::MAX_ROOMS || room_block.length < 1 - raise ArgumentError.new("Can't have unavailable rooms in the block") if room_block.any? { |room| room.unavailable?(check_in, check_out) } + raise ArgumentError.new("Can't have unavailable rooms in the block") if room_block.any? { |room| room.booked?(check_in, check_out) || room.blocked?(check_in, check_out) } end - def valid_rate?(rate) + def check_rate(rate) raise TypeError.new("#{rate} must be of type Integer") if rate.class != Integer raise ArgumentError.new("Rate must be greater than 0") if rate < 1 end - def valid_discount?(discount) + def check_discount(discount) # must be decimal representing percentage of full cost (e.g. 0.8 for 80% of orig rate) raise TypeError.new("#{discount} must be of type Float") if discount.class != Float raise ArgumentError.new("Not a discounted rate") if discount >= 1 || discount <= 0 end - def total_cost(rate = @rate) - num_nights = (@check_out - @check_in).to_i - return (num_nights * rate) - end - -# TODO finish implementing - # def total_cost(room_num) - # num_nights = (@check_out - @check_in).to_i - # return (num_nights * ) - # end - def include?(date) return date >= @check_in && date < @check_out end diff --git a/lib/reservation.rb b/lib/reservation.rb index 49dd1355a..b2c6ec1ae 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -12,16 +12,16 @@ class Reservation attr_accessor :check_in, :check_out, :room_num, :rate, :reservation_id - def initialize(check_in, check_out, room) + def initialize(check_in, check_out, room, rate = room.rate) - valid_dates?(check_in, check_out) - valid_room?(room) + check_dates(check_in, check_out) + check_room(room) @reservation_id = @@all_reservations.length + 1 @check_in = check_in @check_out = check_out @room_num = room.room_num - @rate = room.rate + @rate = rate @@all_reservations << self end @@ -36,7 +36,6 @@ def ==(other_reservation) def total_cost num_nights = (check_out - check_in).to_i - # return num_nights * ::Hotel::Room::DEFAULT_RATE return num_nights * rate end @@ -61,6 +60,12 @@ def self.clear @@all_reservations = [] end + def self.find_by_date(date) + raise TypeError.new("#{date} must be of type Date") if date.class != Date + + return @@all_reservations.select { |reservation| reservation.include?(date)} + + end def to_s # return human readable representation @@ -68,6 +73,7 @@ def to_s s += "Room number: #{room_num}\n" s += "Check-in: #{check_in}\n" s += "Check-out: #{check_out}\n" + s += "Total cost: #{total_cost}\n" return s diff --git a/lib/room.rb b/lib/room.rb index 1e207ec58..bfa3b7e46 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -16,12 +16,12 @@ class Room def initialize(room_num, rate = DEFAULT_RATE) - valid_room_num?(room_num) - valid_rate?(rate) + check_room_num(room_num) + check_rate(rate) @room_num = room_num - @reservations = [] # array of res_ids - @blocks = [] # array of block_ids + @reservations = [] + @blocks = [] @rate = rate @@all_rooms << self @@ -32,11 +32,11 @@ def <=>(other_room) room_num <=> other_room.room_num end - def reserve(start_date, end_date) + def reserve(start_date, end_date, rate_to_charge = rate) raise ArgumentError.new("Room #{room_num} isn't available for the given dates") if booked?(start_date, end_date) - new_reservation = ::Hotel::Reservation.new(start_date, end_date, self) + new_reservation = ::Hotel::Reservation.new(start_date, end_date, self, rate_to_charge) reservations << new_reservation#.reservation_id return new_reservation @@ -55,10 +55,6 @@ def blocked?(start_date, end_date = start_date.next_day) end - def unavailable?(start_date, end_date = start_date.next_day) - return booked?(start_date, end_date) || blocked?(start_date, end_date) - end - def self.all # @all_rooms.sort! return @@all_rooms @@ -87,7 +83,7 @@ def to_s s += "Reservations:\n" reservations.each do |reservation| - s += Hotel::Reservation.find(reservation).to_s + s += reservation.to_s end # s += "Blocks:\n" @@ -119,9 +115,3 @@ def array_include_date?(array, start_date, end_date) end # end of Room class end - -room = Hotel::Room.new(1) -room2 = Hotel::Room.new(2) - -puts Hotel::Room.all -# puts Hotel::Room.all_rooms diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index d23e19560..002dc90f8 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -1,204 +1,127 @@ -# require_relative 'spec_helper' -# -# describe "Testing Hotel class" do -# let(:hotel) { Hotel::Hotel.new } -# -# describe "#initialize" do -# -# it "Creates a hotel class with a hash of rooms" do -# hotel.must_be_instance_of Hotel::Hotel -# hotel.rooms.must_be_kind_of Hash -# -# rooms.each do |room_num, room| -# room.must_be_instance_of Hotel::Room -# end -# end -# -# it "Creates a hotel with NUM_ROOMS num of rooms as the default" do -# hotel.rooms.length.must_equal Hotel::Hotel::NUM_ROOMS -# end -# -# it "Creates a hotel with the specified number of rooms" do -# num_rooms = 17 -# new_hotel = Hotel::Hotel.new(num_rooms) -# new_hotel.rooms.length.must_equal num_rooms -# end -# -# it "Raises an error if not passed a valid number for num of rooms" do -# proc { Hotel::Hotel.new(-1) }.must_raise ArgumentError -# proc { Hotel::Hotel.new(0) }.must_raise ArgumentError -# end -# -# it "Creates rooms with room nums between 1 & specified number of rooms" do -# num_rooms = 25 -# big_hotel = Hotel::Hotel.new(num_rooms) -# num_big_hotel_rooms = big_hotel.rooms.length -# -# big_hotel.rooms.each do |room_num, room| -# room_num.must_be :>=, 1 -# room_num.must_be :<=, num_big_hotel_rooms -# end -# end -# -# end -# -# describe "#reserve" do -# let(:hotel) { Hotel::Hotel.new } -# let(:room1) { hotel.rooms[1] } -# let(:check_in) { Date.today } -# let(:check_out) { Date.today + 3 } -# -# it "Reserves the given room for the given dates" do -# room1.reservations.must_equal [] -# -# hotel.reserve(Date.today + 4, Date.today + 6, room1) -# new_res = Hotel::Reservation.new(Date.today + 4, Date.today + 6, room1) -# room1.reservations[0].must_equal new_res -# end -# -# it "Raises error when it tries to reserve a room that's already reserved" do -# -# hotel.reserve(check_in, check_out, room1) -# -# proc { hotel.reserve(check_in + 2, check_out, room1) }.must_raise ArgumentError -# -# end -# -# it "Raises error when it tries to reserve a room that's in a block" do -# -# Hotel::Block.new(check_out, check_out + 3, 0.2, [room1]) -# -# proc { hotel.reserve(check_out, check_out + 1, room1) }.must_raise ArgumentError -# -# end -# -# end -# -# describe "#find_reservations_by_date" do -# before do -# @hotel = Hotel::Hotel.new -# -# # res that doesn't conflict with 9/5/18 -# 5.times do |num| -# room = @hotel.rooms[1 + num] -# @hotel.reserve(Date.new(2018,9,1), Date.new(2018,9,4), room) -# end -# -# # res that does conflict with 9/5/18 -# 5.times do |num| -# room = @hotel.rooms[6 + num] -# @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,9), room) -# end -# -# # res with start date conflicting with 9/5/18 -# 5.times do |num| -# room = @hotel.rooms[11 + num] -# @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,9), room) -# end -# -# # res with end date not conflicting with 9/5/18 -# 5.times do |num| -# room = @hotel.rooms[16 + num] -# @hotel.reserve(Date.new(2018,9,3), Date.new(2018,9,5), room) -# end -# -# @date_to_check = Date.new(2018,9,5) -# @res_list = @hotel.find_reservations_by_date(@date_to_check) -# end -# -# it "Returns a list of reservations for that date" do -# @res_list.must_be_kind_of Array -# end -# -# it "Doesn't include reservations w/a check-out date matching date" do -# @res_list.length.must_equal 10 -# -# room3 = @hotel.rooms[2] -# @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,5), room3) -# -# updated_res = @hotel.find_reservations_by_date(@date_to_check) -# updated_res.length.must_equal 10 -# -# @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,6), room3) -# updated_res = @hotel.find_reservations_by_date(@date_to_check) -# updated_res.length.must_equal 11 -# end -# end -# -# describe "#find_avail_rooms" do -# before do -# @hotel = Hotel::Hotel.new -# -# # res that doesn't conflict with 9/5/18 - 9/7/18 -# 5.times do |num| -# room = @hotel.rooms[1 + num] -# @hotel.reserve(Date.new(2018,9,1), Date.new(2018,9,4), room) -# end -# -# # res that does conflict with 9/5/18-9/7/18 -# 5.times do |num| -# room = @hotel.rooms[6 + num] -# @hotel.reserve(Date.new(2018,9,4), Date.new(2018,9,9), room) -# end -# -# # res conflicting with 9/5/18-9/7/18 -# 5.times do |num| -# room = @hotel.rooms[11 + num] -# @hotel.reserve(Date.new(2018,9,5), Date.new(2018,9,9), room) -# end -# -# # res not conflicting with 9/5/18-9/7/18 -# 5.times do |num| -# room = @hotel.rooms[16 + num] -# @hotel.reserve(Date.new(2018,9,3), Date.new(2018,9,5), room) -# end -# -# @start_date = Date.new(2018,9,5) -# @end_date = Date.new(2018,9,7) -# -# end -# -# it "Returns a hash of rooms available for the given date range" do -# avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) -# avail_rooms.must_be_kind_of Hash -# -# avail_rooms.each do |room_num, room| -# room.must_be_instance_of Hotel::Room -# end -# end -# -# it "Counts rooms as available if check_out date equals start_date of another reservation" do -# expected_availability = 10 -# avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) -# avail_rooms.length.must_equal expected_availability -# -# room1 = @hotel.rooms[1] -# @hotel.reserve(Date.new(2018,9,4), @start_date, room1) -# @hotel.find_avail_rooms(@start_date, @end_date).must_equal avail_rooms -# -# @hotel.reserve(@start_date, Date.new(2018,9,6), room1) -# updated_avail_rooms = @hotel.find_avail_rooms(@start_date, @end_date) -# updated_avail_rooms.length.must_equal expected_availability - 1 -# updated_avail_rooms.wont_include room1 -# -# room_block = (@hotel.rooms.select { |room_num, room| room_num > 15 }).values -# Hotel::Block.new(@start_date, @end_date, 0.2, room_block) -# updated_avail = @hotel.find_avail_rooms(@start_date, @end_date) -# -# updated_avail.length.must_equal expected_availability - 6 -# room_block.each do |room| -# updated_avail.wont_include room -# end -# -# end -# -# it "Raises ArgumentError if start date is later than end date" do -# room1 = @hotel.rooms[1] -# proc { @hotel.find_avail_rooms(@end_date, @start_date, room1) }.must_raise ArgumentError -# -# proc { @hotel.find_avail_rooms(@end_date, @end_date, room1) }.must_raise ArgumentError -# end -# end -# -# -# end +require_relative 'spec_helper' + +describe "Testing Hotel class" do + let(:hotel) { Hotel::Hotel.new } + let(:today) { Date.today } + let(:three_days_later) { Date.today + 3} + + describe "#initialize" do + + it "Creates a hotel class with a hash of rooms" do + hotel.must_be_instance_of Hotel::Hotel + hotel.rooms.must_be_kind_of Hash + + hotel.rooms.each do |room_num, room| + room.must_be_instance_of Hotel::Room + end + end + + it "Creates a hotel with NUM_ROOMS num of rooms as the default" do + hotel.rooms.length.must_equal Hotel::Hotel::NUM_ROOMS + end + + it "Creates a hotel with the specified number of rooms" do + num_rooms = 17 + new_hotel = Hotel::Hotel.new(num_rooms) + new_hotel.rooms.length.must_equal num_rooms + end + + it "Raises an error if not passed a valid number for num of rooms" do + proc { Hotel::Hotel.new(-1) }.must_raise ArgumentError + proc { Hotel::Hotel.new(0) }.must_raise ArgumentError + proc { Hotel::Hotel.new(nil) }.must_raise TypeError + proc { Hotel::Hotel.new("cat") }.must_raise TypeError + proc { Hotel::Hotel.new(3.14) }.must_raise TypeError + + end + + it "Creates rooms with room nums between 1 & specified number of rooms" do + num_rooms = 25 + big_hotel = Hotel::Hotel.new(num_rooms) + num_big_hotel_rooms = big_hotel.rooms.length + + big_hotel.rooms.each do |room_num, room| + room.room_num.must_be :>=, 1 + room.room_num.must_be :<=, num_big_hotel_rooms + end + end + + end + + describe "#reserve" do + before do + Hotel::Reservation.clear + @room1 = hotel.rooms[1] + end + + it "Reserves the given room for the given dates" do + @room1.reservations.must_equal [] + + new_res = hotel.reserve(today, three_days_later, @room1) + @room1.reservations.must_include new_res + end + + it "Raises error when it tries to reserve a room that's already reserved" do + + hotel.reserve(today, three_days_later, @room1) + + proc { hotel.reserve(today + 1, three_days_later, @room1) }.must_raise ArgumentError + + end + + it "Raises error when it tries to reserve a room that's in a block" do + + Hotel::Block.new(today, three_days_later, 0.85, [@room1]) + + proc { hotel.reserve(today, today + 2, @room1) }.must_raise ArgumentError + + end + + end + + describe "#find_reservations_by_date" do + before do + Hotel::Reservation.clear + end + + it "Returns a list of reservations for that date" do + hotel.find_reservations_by_date(today).must_equal [] + + res1 = hotel.reserve(today, three_days_later, hotel.rooms[1]) + hotel.find_reservations_by_date(today).must_equal [res1] + hotel.find_reservations_by_date(three_days_later).must_equal [] + + res2 = hotel.reserve(today + 1, three_days_later, hotel.rooms[2]) + hotel.find_reservations_by_date(today).must_equal [res1] + hotel.find_reservations_by_date(today + 1).must_equal [res1, res2] + end + + end + + describe "#find_avail_rooms" do + before do + Hotel::Reservation.clear + end + + it "Returns hash of rooms available for date range (doesn't count check-out date as unavail)" do + hotel.find_avail_rooms(today, three_days_later).must_equal hotel.rooms + + hotel.reserve(today, three_days_later, hotel.rooms[1]) + hotel.reserve(today, three_days_later + 1, hotel.rooms[2]) + + hotel.find_avail_rooms(today, three_days_later).wont_include hotel.rooms[2] + hotel.find_avail_rooms(today, three_days_later - 1).wont_include hotel.rooms[1] + hotel.find_avail_rooms(today, three_days_later - 1).length.must_equal 18 + + end + + it "Raises ArgumentError if start date is later than end date" do + room1 = hotel.rooms[1] + proc { hotel.find_avail_rooms(today, three_days_later, room1) }.must_raise ArgumentError + + proc { hotel.find_avail_rooms(hotel, three_days_later, room1) }.must_raise ArgumentError + end + end + + +end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index ebeb2c5ac..781a3abf2 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -82,42 +82,72 @@ end end - describe "#self.find" do - it "Returns a reservation matching the given reservation_id" do + describe "#self.find(id)" do + before do + Hotel::Reservation.clear + + @res_to_find = Hotel::Reservation.new(today, two_days_later, room) + Hotel::Reservation.new(today, two_days_later, Hotel::Room.new(1)) + + end + + it "Returns a reservation matching the given reservation id" do + Hotel::Reservation.find(1).must_equal @res_to_find + end + + it "Returns nil if no reservation found with given id" do + Hotel::Reservation.find(3).must_be_nil + end + end + + describe "#self.find_by_date" do + it "Returns a list of reservations for a specific date (doesn't include checkout date)" do + Hotel::Reservation.clear + + res1 = Hotel::Reservation.new(today, two_days_later, room) + res2 = Hotel::Reservation.new(today, two_days_later + 1, Hotel::Room.new(1)) + + Hotel::Reservation.find_by_date(today).must_equal [res1, res2] + Hotel::Reservation.find_by_date(two_days_later).must_equal [res2] + Hotel::Reservation.find_by_date(today + 4).must_equal [] + end + it "Raises an error if date isn't a Date object" do + invalid_dates = ["cat", [], nil, 4] + + invalid_dates.each do |invalid_date| + proc { Hotel::Reservation.find_by_date(invalid_date) }.must_raise TypeError + end end end - describe "total_cost (in Reservable)" do - # before do - # @check_in = Date.today - # @check_out = Date.today + 3 - # @res = Hotel::Reservation.new(@check_in, @check_out, Hotel::Room.new(4)) - # end + describe "#total_cost" do - xit "Returns the total cost of the reservation" do + it "Returns the total cost of the reservation" do res = Hotel::Reservation.new(today, two_days_later, room) - num_nights = (two_days_later - today).to_i - expected_cost = num_nights * room.rate + expected_cost = 400 # 2 nights @ 200/night res.total_cost.must_equal expected_cost - new_rate = 300 - room.rate = new_rate - # binding.pry - res.total_cost.must_equal (num_nights * new_rate) + room.rate = 300 + more_expensive_res = Hotel::Reservation.new(two_days_later, two_days_later + 2, room) + higher_cost = 600 # 2 nights @ 300/night + more_expensive_res.total_cost.must_equal higher_cost + + end + + it "Returns the total discounted cost of the reservation if the room is in a block" do + block = Hotel::Block.new(today, two_days_later, 0.8, [room]) + block_res = block.reserve(room) + expected_cost = 320 # 0.8 * 200/night * 2 nights + block_res.total_cost.must_equal expected_cost + new_block = Hotel::Block.new(two_days_later, two_days_later + 1, 0.7, [room]) + new_block_res = new_block.reserve(room) + new_cost = 140 #0.7 * 200/night * 1 night + new_block_res.total_cost.must_equal new_cost end end - # describe "#self.find" do - # before do - # date_to_check = Date.new(2017,9,5) - # end - # - # it "Returns a list of Reservations for a given date" do - # - # end - # end end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index 028339813..5b09fbc7d 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -20,11 +20,11 @@ Hotel::Room.new(4, 300).rate.must_equal expected_rate end - it "Creates an empty array of Reservation objects" do + it "Creates an empty array of Reservation ids" do room.reservations.must_equal [] end - it "Creates an empty array of Block objects" do + it "Creates an empty array of Block ids" do room.blocks.must_equal [] end @@ -161,11 +161,10 @@ describe "#blocked?" do let(:rooms) { [2, 4, 5, 9, 20].map { |num| Hotel::Room.new(num) } } - let(:discount) { 0.8 } it "Returns true if a room is in a block for the given date range (no reservation)" do - Hotel::Block.new(today, three_days_later, discount, rooms) + Hotel::Block.new(today, three_days_later, 0.8, rooms) blocked_room = rooms[0] blocked_room.blocked?(today - 1, today + 1).must_equal true @@ -176,7 +175,7 @@ it "Returns true if a room is in a block for the given date range (with reservation)" do - new_block = Hotel::Block.new(today, three_days_later, discount, rooms) + new_block = Hotel::Block.new(today, three_days_later, 0.8, rooms) reserved_room = rooms[0] new_block.reserve(reserved_room) reserved_room.blocked?(today, three_days_later).must_equal true @@ -187,4 +186,5 @@ end end + end From dcc4b0693aed66788d997f6bb3a82df8f0500039 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Sun, 10 Sep 2017 23:45:52 -0700 Subject: [PATCH 24/26] Added edge case to reserve test --- specs/block_spec.rb | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 146610afe..f89c85d43 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -158,19 +158,8 @@ it "Raises an error if it tries to reserve an room that's already reserved" do block.reserve(room_to_reserve) - proc {block.reserve(room_to_reserve) }.must_raise ArgumentError - end - end - - xdescribe "#discounted_cost" do - it "Returns the total cost of reserving a room in a block" do - expected_cost = (room_to_reserve.rate * 0.8) * (check_out - check_in).to_i - block.discounted_cost(room_to_reserve).must_equal expected_cost - - room_to_reserve.rate = 300 - updated_expected_cost = (room_to_reserve.rate * 0.8) * (check_out - check_in).to_i - block.discounted_cost(room_to_reserve).must_equal updated_expected_cost - + proc { block.reserve(room_to_reserve) }.must_raise ArgumentError + proc { room_to_reserve.reserve(today, two_days_later) }.must_raise ArgumentError end end From e7c017add57630b76d6fcca924225cbb7821a646 Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Sat, 30 Sep 2017 16:19:22 -0700 Subject: [PATCH 25/26] Added design activity questions --- design-activity.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 design-activity.md diff --git a/design-activity.md b/design-activity.md new file mode 100644 index 000000000..d6f1b3830 --- /dev/null +++ b/design-activity.md @@ -0,0 +1,48 @@ +## Prompts + +1. **What classes does each implementation include? Are the lists the same?** + + Each implementation includes the same classes: + + a CartEntry class + + a ShoppingCart class + + an Order class + +2. **Write down a sentence to describe each class.** + + + `CartEntry`: This is a single kind of item in the online shopping cart, and it tracks the unit price of the item, and the quantity of that item ordered. + + `ShoppingCart`: This is an object representing the actual shopping cart, and it consists of an array of entries (items in the shopping cart). + + `Order`: This is the online order, which contains a shopping cart, and it uses sales tax to calculate the total price of the cart contents. + +3. **How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper.** + + A `ShoppingCart` has a `CartEntry`, and an `Order` has a `ShoppingCart`--i.e. `Order` depends on `ShoppingCart`, which depends on `CartEntry`. + +4. **What _data_ does each class store? How (if at all) does this differ between the two implementations?** + + The classes in each implementation store the exact same data. `CartEntry` stores `unit_price` and `quantity`, `ShoppingCart` stores `entries` (which are cart entries), and `Order` stores `SALES_TAX` (a constant) and a cart, which is a `ShoppingCart` object. + +5. **What _methods_ does each class have? How (if at all) does this differ between the two implementations?** + + Aside from the accessor methods, Implementation A only has one defined method, which calculates the total price of an order, which means it's more tightly coupled to both the `ShoppingCart` and `CartEntry` classes, because it depends on `ShoppingCart` being an array of CartEntries, and each `CartEntry` having a `unit_price` and `quantity`. + + Implementation B, on the other hand, uses methods in both the `CartEntry` and `ShoppingCart` classes to calculate the price of each `CartEntry` object and the price of each `ShoppingCart` object. This decouples `ShoppingCart` from `CartEntry` (it calls `CartEntry`'s price method rather than manipulating `CartEntry`'s variables directly), as well as decoupling `Order` from both `ShoppingCart` and `CartEntry`. + +6. **Consider the `Order#total_price` method. In each implementation:** + + Is logic to compute the price delegated to "lower level" classes like `ShoppingCart` and `CartEntry`, or is it retained in `Order`? + + Does `total_price` directly manipulate the instance variables of other classes? + + + Implementation A: (see above) No, the logic to compute the price isn't delegated to the lower-level classes. Instead, `total_price` directly manipulates the instance variables of both `ShoppingCart` (it gets `@entries` from `ShoppingCart`) and `CartEntry` (for each `CartEntry`, it gets `@unit_price` and `@quantity`). + + + Implementation B: (see above) Yes, the logic is delegated to the lower-level classes. `CartEntry` is responsible for calculating its own price, and `ShoppingCart` is responsible for calculating the total price of its contents. `Order` then simply calls the price method for `ShoppingCart` and adds sales tax to calculate the total price. + +7. **If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify?** + + This would mean changing the `CartEntry` class so that if quantity exceeds a particular amount, `unit_price` is then set to a discounted rate. Implementation B is easier to modify, because it already has a `price` method, so it simply means modifying that `price` method to account for bulk orders. However, Implementation A has no such method—all the calculations are taken care of in the `Order` class, which means the `total_price` method will become more complex. + +8. **Which implementation better adheres to the single responsibility principle?** + + Implementation B because each class calculates its own price using its own instance variables. + +9. **Bonus question: Which implementation is more loosely coupled?** + + Implementation B From 92ab683e6ed60a0178be8643d5e67939c5ed671c Mon Sep 17 00:00:00 2001 From: IsabelDePapel Date: Sun, 1 Oct 2017 14:44:57 -0700 Subject: [PATCH 26/26] Loosened coupling between Hotel & Room classes --- design-activity.md | 7 ++++++ lib/hotel.rb | 32 ++++++++++++++++++++++---- lib/room.rb | 8 +++---- specs/hotel_spec.rb | 56 ++++++++++++++++++++++++++++++++++++++------- 4 files changed, 86 insertions(+), 17 deletions(-) diff --git a/design-activity.md b/design-activity.md index d6f1b3830..1aeda5e66 100644 --- a/design-activity.md +++ b/design-activity.md @@ -46,3 +46,10 @@ 9. **Bonus question: Which implementation is more loosely coupled?** Implementation B + + +## Refactoring Hotel + +My `Hotel` class is pretty tightly coupled to the `Room` class, because it requires the user to pass `Room` objects (as opposed to a room number) to reserve or block rooms. To change this, I would make use of the hash I set up when initializing my `Hotel` class with rooms where the room number is the key and `Room` object is the value. Then, given a room number, I could first retrieve the `Room` object and then reserve it. This would be an improvement because it's much more user friendly (what user is going to want to find a room object before reserving it? No one, that's who). + +Also, while the `Block` class can reserve rooms from within a block, that functionality isn't in the `Hotel` class itself, and it seems like it would make more sense to have all the blocking/reserving functionality of a hotel available in one class (provided that it delegates the appropriate tasks to lower-level classes), especially since you can reserve a room in the `Hotel` class so it doesn't make sense that you can't reserve a blocked room, as well. So I could have a method that calls the appropriate method(s) in the `Block` class to reserve a room in a given block. This is an improvement b/c it's also more user friendly and puts all the user interface methods (i.e. what the CLI would draw from) in one place rather than having them scattered around different classes. diff --git a/lib/hotel.rb b/lib/hotel.rb index 69f72414c..8ba83b553 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -1,5 +1,6 @@ require_relative 'room' require_relative 'reservation' +require_relative 'block' module Hotel @@ -23,19 +24,40 @@ def initialize(num_rooms = NUM_ROOMS) end - def reserve(start_date, end_date, room) + def reserve(start_date, end_date, room_num) check_dates(start_date, end_date) + room = @rooms[room_num] - raise ArgumentError.new("Room #{room.room_num} isn't available for the selected dates") if room.booked?(start_date, end_date) || room.blocked?(start_date, end_date) + raise ArgumentError.new("Room #{room_num} isn't available for the selected dates") if room.booked?(start_date, end_date) || room.blocked?(start_date, end_date) return room.reserve(start_date, end_date) end - def block(start_date, end_date, discount, rooms) - raise ArgumentError.new("One or more rooms is unavailable for the selected dates") if rooms.any? { |room| room.booked?(start_date, end_date) || room.blocked?(start_date, end_date) } + def block(start_date, end_date, discount, room_nums) + block_rooms = room_nums.map { |room_num| rooms[room_num] } - return Hotel::Block.new(start_date, end_date, discount, rooms) + raise ArgumentError.new("One or more rooms is unavailable for the selected dates") if block_rooms.any? { |room| room.booked?(start_date, end_date) || room.blocked?(start_date, end_date) } + + return ::Hotel::Block.new(start_date, end_date, discount, block_rooms) + end + + def reserve_blocked_room(block, room_num = nil) + # allows user to specify a room number; else system automatically + # choose a room from the block + avail_rooms = block.find_avail_in_block + + raise ArgumentError.new("No more rooms available in block") if avail_rooms.length < 1 + + # assign room num if not provided + room = room_num == nil ? avail_rooms.pop : rooms[room_num] + + # if room num provided, check if available + if room_num && !block.room_available?(room) + raise ArgumentError.new("Room #{room_num} is already booked") + else + block.reserve(room) + end end def find_reservations_by_date(date) diff --git a/lib/room.rb b/lib/room.rb index bfa3b7e46..0e549d6e2 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -45,13 +45,13 @@ def reserve(start_date, end_date, rate_to_charge = rate) def booked?(start_date, end_date = start_date.next_day) - return array_include_date?(reservations, start_date, end_date) + return includes_date?(reservations, start_date, end_date) end def blocked?(start_date, end_date = start_date.next_day) - return array_include_date?(blocks, start_date, end_date) + return includes_date?(blocks, start_date, end_date) end @@ -97,11 +97,11 @@ def to_s private - def array_include_date?(array, start_date, end_date) + def includes_date?(blocks_or_res_array, start_date, end_date) # don't include final date since check-out doesn't conflict with check-in of a new reservation date_range = (start_date...end_date).to_a - array.each do |item| + blocks_or_res_array.each do |item| date_range.each do |date| if item.include?(date) return true diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 002dc90f8..179286181 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -57,15 +57,15 @@ it "Reserves the given room for the given dates" do @room1.reservations.must_equal [] - new_res = hotel.reserve(today, three_days_later, @room1) + new_res = hotel.reserve(today, three_days_later, 1) @room1.reservations.must_include new_res end it "Raises error when it tries to reserve a room that's already reserved" do - hotel.reserve(today, three_days_later, @room1) + hotel.reserve(today, three_days_later, 1) - proc { hotel.reserve(today + 1, three_days_later, @room1) }.must_raise ArgumentError + proc { hotel.reserve(today + 1, three_days_later, 1) }.must_raise ArgumentError end @@ -73,7 +73,7 @@ Hotel::Block.new(today, three_days_later, 0.85, [@room1]) - proc { hotel.reserve(today, today + 2, @room1) }.must_raise ArgumentError + proc { hotel.reserve(today, today + 2, 1) }.must_raise ArgumentError end @@ -87,11 +87,11 @@ it "Returns a list of reservations for that date" do hotel.find_reservations_by_date(today).must_equal [] - res1 = hotel.reserve(today, three_days_later, hotel.rooms[1]) + res1 = hotel.reserve(today, three_days_later, 1) hotel.find_reservations_by_date(today).must_equal [res1] hotel.find_reservations_by_date(three_days_later).must_equal [] - res2 = hotel.reserve(today + 1, three_days_later, hotel.rooms[2]) + res2 = hotel.reserve(today + 1, three_days_later, 2) hotel.find_reservations_by_date(today).must_equal [res1] hotel.find_reservations_by_date(today + 1).must_equal [res1, res2] end @@ -106,8 +106,8 @@ it "Returns hash of rooms available for date range (doesn't count check-out date as unavail)" do hotel.find_avail_rooms(today, three_days_later).must_equal hotel.rooms - hotel.reserve(today, three_days_later, hotel.rooms[1]) - hotel.reserve(today, three_days_later + 1, hotel.rooms[2]) + hotel.reserve(today, three_days_later, 1) + hotel.reserve(today, three_days_later + 1, 2) hotel.find_avail_rooms(today, three_days_later).wont_include hotel.rooms[2] hotel.find_avail_rooms(today, three_days_later - 1).wont_include hotel.rooms[1] @@ -123,5 +123,45 @@ end end + describe "#reserve_blocked_room" do + before do + Hotel::Reservation.clear + @block = hotel.block(today, three_days_later, 0.8, [1, 2, 3]) + @room1 = hotel.rooms[1] + end + + it "Raises ArgumentError if all rooms already booked" do + @block.reserve(@room1) + @block.reserve(hotel.rooms[2]) + @block.reserve(hotel.rooms[3]) + + proc { hotel.reserve_blocked_room(@block) }.must_raise ArgumentError + end + + it "Raises ArgumentError if specified room is already booked" do + @block.reserve(@room1) + proc { hotel.reserve_blocked_room(@block, 1) }.must_raise ArgumentError + end + + it "Reserves the specified room in the block" do + hotel.reserve_blocked_room(@block, 1) + + res = Hotel::Reservation.new(today, three_days_later, @room1) + @room1.reservations.must_include res + hotel.find_avail_rooms(today, three_days_later).wont_include(1) + end + + it "Reserves any available room in block if room num isn't specified" do + @block.reserve(@room1) + + hotel.reserve_blocked_room(@block) + hotel.find_avail_rooms(today, three_days_later).wont_include(2 || 3) + + hotel.reserve_blocked_room(@block) + hotel.find_avail_rooms(today, three_days_later).wont_include(2 && 3) + end + + end + end