From bdc1eab1c40707a083de23579b2b740c52772e62 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 12:27:28 -0700 Subject: [PATCH 001/131] add rakefile --- Rakefile | 9 +++++++++ specs/spec_helper.rb | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 Rakefile create mode 100644 specs/spec_helper.rb diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..902fe3b61 --- /dev/null +++ b/Rakefile @@ -0,0 +1,9 @@ +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.libs = ['lib'] + t.warning = true + t.test_files = FileList['./specs/*_spec.rb'] +end + +task default: :test diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 000000000..db4bbecba --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,8 @@ +require 'simplecov' +SimpleCov.start + +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/skip_dsl' + +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new From 0f80e82fc2a01d0cc7d2df06a54172a29f9a85ae Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 16:14:01 -0700 Subject: [PATCH 002/131] create files for classes & specs --- lib/block.rb | 0 lib/date_range.rb | 0 lib/hotel.rb | 0 lib/reservation.rb | 0 lib/room.rb | 0 specs/block_spec.rb | 0 specs/date_range_spec.rb | 0 specs/design.md | 49 +++++++++++++++++++++++++++++++++++++++ specs/hotel_spec.rb | 0 specs/reservation_spec.rb | 0 specs/room_spec.rb | 0 11 files changed, 49 insertions(+) create mode 100644 lib/block.rb create mode 100644 lib/date_range.rb create mode 100644 lib/hotel.rb create mode 100644 lib/reservation.rb create mode 100644 lib/room.rb create mode 100644 specs/block_spec.rb create mode 100644 specs/date_range_spec.rb create mode 100644 specs/design.md create mode 100644 specs/hotel_spec.rb create mode 100644 specs/reservation_spec.rb create mode 100644 specs/room_spec.rb diff --git a/lib/block.rb b/lib/block.rb new file mode 100644 index 000000000..e69de29bb diff --git a/lib/date_range.rb b/lib/date_range.rb new file mode 100644 index 000000000..e69de29bb diff --git a/lib/hotel.rb b/lib/hotel.rb new file mode 100644 index 000000000..e69de29bb 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/block_spec.rb b/specs/block_spec.rb new file mode 100644 index 000000000..e69de29bb diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb new file mode 100644 index 000000000..e69de29bb diff --git a/specs/design.md b/specs/design.md new file mode 100644 index 000000000..1c989d0a9 --- /dev/null +++ b/specs/design.md @@ -0,0 +1,49 @@ +WAVE 1 +As an administrator, I can access the list of all of the rooms in the hotel +As an administrator, I can reserve a room for a given date range +As an administrator, I can access the list of reservations for a specific date +As an administrator, I can get the total cost for a given reservation + +The hotel has 20 rooms, and they are numbered 1 through 20 +Every room is identical, and a room always costs $200/night +The last day of a reservation is the checkout day, so the guest should not be charged for that night +For this wave, any room can be reserved at any time, and you don't need to check whether reservations conflict with each other (this will come in wave 2!) + +WAVE 2 +As an administrator, I can view a list of rooms that are not reserved for a given date range +As an administrator, I can reserve an available room for a given date range + +A reservation is allowed start on the same day that another reservation for the same room ends +Your code should raise an exception when asked to reserve a room that is not available + +WAVE 3 +As an administrator, I can create a block of rooms +To create a block you need a date range, collection of rooms and a discounted room rate +The collection of rooms should only include rooms that are available for the given date range +If a room is set aside in a block, it is not available for reservation by the general public, nor can it be included in another block +As an administrator, I can check whether a given block has any rooms available +As an administrator, I can reserve a room from within a block of rooms +Constraints + +A block can contain a maximum of 5 rooms +When a room is reserved from a block of rooms, the reservation dates will always match the date range of the block +All of the availability checking logic from Wave 2 should now respect room blocks as well as individual reservations + +**Nouns:** +* administrator +* room(s) +* hotel +* date +* date range +* reservation(s) +* list (of rooms) +* list (of reservations) +* cost +* room number +* guest + + +**Verbs:** +* access (lists) +* reserve (room) +* get (cost) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.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..e69de29bb diff --git a/specs/room_spec.rb b/specs/room_spec.rb new file mode 100644 index 000000000..e69de29bb From 5b5b85b7763bbb7cb48b2354b07a30097963f888 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 16:15:49 -0700 Subject: [PATCH 003/131] comments basic method/variable names --- lib/block.rb | 7 +++++++ lib/date_range.rb | 3 +++ lib/hotel.rb | 10 ++++++++++ lib/reservation.rb | 9 +++++++++ lib/room.rb | 7 +++++++ 5 files changed, 36 insertions(+) diff --git a/lib/block.rb b/lib/block.rb index e69de29bb..86c9e0d94 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -0,0 +1,7 @@ +module Hotel + class Block + # @rooms + # @dates + # @discount_rate + end +end diff --git a/lib/date_range.rb b/lib/date_range.rb index e69de29bb..97a2e1845 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -0,0 +1,3 @@ +module DateRange + # ? ? ? +end diff --git a/lib/hotel.rb b/lib/hotel.rb index e69de29bb..db8935879 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -0,0 +1,10 @@ +module Hotel + class Hotel + # @rooms + # @reservations + # #view_avail() + # #view_booked() + # #is_available?() + # #make_reservation() + end +end diff --git a/lib/reservation.rb b/lib/reservation.rb index e69de29bb..c99dbcad0 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -0,0 +1,9 @@ +module Hotel + class Reservation + # @total_cost + # @dates + # @room + # @reservation_id + # #get_total() + end +end diff --git a/lib/room.rb b/lib/room.rb index e69de29bb..de9865257 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -0,0 +1,7 @@ +module Hotel + class Room + # @number + # @cost + # #is_available?() + end +end From 936ce0098200e9dc75730739caf26a3dcb400cef Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 16:28:45 -0700 Subject: [PATCH 004/131] add files to spec_helper require list --- specs/spec_helper.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb index db4bbecba..9aed63107 100644 --- a/specs/spec_helper.rb +++ b/specs/spec_helper.rb @@ -4,5 +4,10 @@ require 'minitest/autorun' require 'minitest/reporters' require 'minitest/skip_dsl' +require_relative '../lib/block.rb' +require_relative '../lib/date_range.rb' +require_relative '../lib/hotel.rb' +require_relative '../lib/reservation.rb' +require_relative '../lib/room.rb' Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new From ddbe4ed143d734b7e44dbc5087502263e59407e9 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 16:30:29 -0700 Subject: [PATCH 005/131] add initialize method --- lib/hotel.rb | 9 ++++++++- specs/hotel_spec.rb | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index db8935879..242447813 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -1,7 +1,14 @@ module Hotel class Hotel - # @rooms + attr_reader :rooms # @reservations + + def initialize(num_rooms) + @rooms = [] + num_rooms.times do |i| + @rooms << Room.new(i) + end + end # #view_avail() # #view_booked() # #is_available?() diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index e69de29bb..555e4ff2c 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -0,0 +1,16 @@ +require_relative 'spec_helper' + +describe "Hotel" do + describe "Initialize" do + it "Can be instantiated" do + Hotel::Hotel.new(20).must_be_kind_of Hotel::Hotel + end + + it "Creates an array of rooms" do + hotel = Hotel::Hotel.new(20) + + hotel.rooms.must_be_kind_of Array + hotel.rooms.length.must_equal 20 + end + end +end From 6cdb1ff61e7fc9ee0f47471d7e7d1525ae0f9915 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 16:42:26 -0700 Subject: [PATCH 006/131] initialize --- lib/room.rb | 9 +++++++-- specs/room_spec.rb | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/room.rb b/lib/room.rb index de9865257..f2dee260d 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -1,7 +1,12 @@ module Hotel class Room - # @number - # @cost + attr_reader :number, :cost + + def initialize(number) + @number = number + @cost = 200 + end + # #is_available?() end end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index e69de29bb..d030a294b 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -0,0 +1,17 @@ +require_relative 'spec_helper' + +describe "Room" do + describe "initialize" do + it "can be instantiated" do + Hotel::Room.new(1).must_be_kind_of Hotel::Room + end + + it "has a room number" do + Hotel::Room.new(5).number.must_equal 5 + end + + it "has a cost" do + Hotel::Room.new(5).cost.must_equal 200 + end + end +end From 387c25684f51f6aaf5d3d3b1d74690e226096a98 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 16:42:48 -0700 Subject: [PATCH 007/131] add #all_rooms --- lib/hotel.rb | 13 ++++++++++--- specs/hotel_spec.rb | 39 ++++++++++++++++++++++++++++++++------- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 242447813..9708ba799 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -1,14 +1,21 @@ module Hotel class Hotel - attr_reader :rooms - # @reservations + attr_reader :rooms, :reservations def initialize(num_rooms) @rooms = [] num_rooms.times do |i| - @rooms << Room.new(i) + @rooms << Room.new(i+1) end + @reservations = [] end + + def all_rooms + list = [] + @rooms.each { |room| list << room.number } + list + end + # #view_avail() # #view_booked() # #is_available?() diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 555e4ff2c..50f7304d9 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -1,16 +1,41 @@ require_relative 'spec_helper' -describe "Hotel" do - describe "Initialize" do + +describe 'Hotel' do + before do + @hotel = Hotel::Hotel.new(20) + end + + describe '#initialize' do it "Can be instantiated" do - Hotel::Hotel.new(20).must_be_kind_of Hotel::Hotel + @hotel.must_be_kind_of Hotel::Hotel end - it "Creates an array of rooms" do - hotel = Hotel::Hotel.new(20) + it 'Creates an array of rooms' do + @hotel.rooms.must_be_kind_of Array + @hotel.rooms.length.must_equal 20 + end + + it 'Creates array of reservations' do + @hotel.reservations.must_equal [] + end + end - hotel.rooms.must_be_kind_of Array - hotel.rooms.length.must_equal 20 + describe '#all_rooms' do + # As an administrator, I can access the list of all of the rooms in the hotel + it 'Returns an array of all room numbers' do + @hotel.all_rooms.must_equal (1..20).to_a end end + + describe '#make_reservation' do + @hotel.make_reservation('2017-09-05', '2017-09-08') + + @hotel.reservations[0].must_be_kind_of Hotel::Reservation + end + # As an administrator, I can reserve a room for a given date range + + # As an administrator, I can access the list of reservations for a specific date + + # As an administrator, I can get the total cost for a given reservation end From b150d60963a8aadb70f4d949ea3b1a4710689458 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 16:54:31 -0700 Subject: [PATCH 008/131] add #initialize --- lib/reservation.rb | 6 ++++++ specs/reservation_spec.rb | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/lib/reservation.rb b/lib/reservation.rb index c99dbcad0..5bff002c9 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -4,6 +4,12 @@ class Reservation # @dates # @room # @reservation_id + + def initialize(checkin, checkout) + @checkin = Date.parse(checkin) + @checkout = Date.parse(checkout) + # @num_nights = (@checkout - @checkin).to_i + end # #get_total() end end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index e69de29bb..01319425d 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -0,0 +1,15 @@ +require_relative 'spec_helper' + +describe 'Reservation' do + before do + @reservation = Hotel::Reservation.new('2017-09-05', '2017-09-07') + end + + describe '#initialize' do + it 'can be instantiated' do + @reservation.must_be_kind_of Hotel::Reservation + end + + + end +end From 6c38487174450268a2ff0fa548f324bf69e208aa Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 21:47:38 -0700 Subject: [PATCH 009/131] pseudocode remaining methods --- lib/hotel.rb | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 9708ba799..2de1a0350 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -16,9 +16,44 @@ def all_rooms list end - # #view_avail() - # #view_booked() - # #is_available?() - # #make_reservation() + def make_reservation(checkin, checkout) + @reservations << Reservation.new(checkin, checkout) + end + + # def view_avail(checkin, checkout) + # available_rooms = [] + # @rooms.each do |room| + # available_rooms << room.number if room.is_avail?(checkin, checkout) + # available_rooms + # end + # end + + # def view_reservations(date) + # reservations = [] + # @reservations.each do |reservation| + # reservations << reservation if reservation.dates.include?(date) + # end + # reservations + # end + + # def find_available_rooms(checkin, checkout) + # booked_rooms, available_rooms = [], [] + # @reservations.each do |reservation| + # if reservation.room is not in booked_room && !(reservation.includes_dates?(checkin,checkout)) + # booked_rooms << reservation.number + # end + # end + # @rooms.each do |room| + # available_rooms << room unless booked_rooms.include?room.number + # end + # available_rooms + # end + + + # def make_reservation(checkin, checkout) + # room_num = find_available_rooms(checkin, checkout).first + # @reservations << Reservation.new(room_num, checkin, checkout) + # end + end end From 43d7f68b1c7fd291c93466ca01c750ea57a71fdb Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 21:47:55 -0700 Subject: [PATCH 010/131] add room_num parameter to initialize method --- lib/reservation.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 5bff002c9..5aedf688d 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -4,12 +4,21 @@ class Reservation # @dates # @room # @reservation_id + attr_reader :total_cost - def initialize(checkin, checkout) + def initialize(room, checkin, checkout) + @room = room @checkin = Date.parse(checkin) @checkout = Date.parse(checkout) - # @num_nights = (@checkout - @checkin).to_i + get_total end - # #get_total() + + def get_total + num_nights = (@checkout - @checkin).to_i + @total_cost = num_nights * @room.cost + end + + # def includes_dates?(checkin, checkout) + # end end end From 0f42fcaea56ea997772dac91495916cd4098f940 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 21:52:18 -0700 Subject: [PATCH 011/131] pseudocode #includes_dates? method --- lib/reservation.rb | 7 +++++++ lib/room.rb | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 5aedf688d..a139b20b1 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -1,5 +1,6 @@ module Hotel class Reservation + # require_relative 'date_range' # @total_cost # @dates # @room @@ -10,6 +11,7 @@ def initialize(room, checkin, checkout) @room = room @checkin = Date.parse(checkin) @checkout = Date.parse(checkout) + # @dates = DateRange::range(@checkin, @checkout) get_total end @@ -19,6 +21,11 @@ def get_total end # def includes_dates?(checkin, checkout) + # Date.parse???? + # dates_to_check = DateRange::range(checkin, checkout) + # dates_to_check.each do |date| + # if @dates.include? date + # return true # end end end diff --git a/lib/room.rb b/lib/room.rb index f2dee260d..342a9ef7e 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -6,7 +6,7 @@ def initialize(number) @number = number @cost = 200 end - - # #is_available?() + + # #is_avail?() end end From eeae8f84fe21567eac814cb2ef3cf224de63b333 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 21:54:34 -0700 Subject: [PATCH 012/131] test for @total_cost --- specs/reservation_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 01319425d..66e03efb0 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -10,6 +10,8 @@ @reservation.must_be_kind_of Hotel::Reservation end - + it 'has @total_cost value' do + @reservation.total_cost.must_equal 400 + end end end From 69d7740a33b2458579efaa472be71e0beac7bd8c Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 22:05:25 -0700 Subject: [PATCH 013/131] parses checkin & checkout into dates array --- lib/reservation.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index a139b20b1..838ae1fc3 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -9,9 +9,9 @@ class Reservation def initialize(room, checkin, checkout) @room = room - @checkin = Date.parse(checkin) - @checkout = Date.parse(checkout) - # @dates = DateRange::range(@checkin, @checkout) + checkin = Date.parse(checkin) + checkout = Date.parse(checkout) + # @dates = DateRange::range(checkin, checkout) get_total end From 96ea3dfb24defba2fd027218fee80c59c5321892 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Tue, 5 Sep 2017 22:05:54 -0700 Subject: [PATCH 014/131] fixed broken it block --- specs/hotel_spec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 50f7304d9..370a394bc 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -29,9 +29,11 @@ end describe '#make_reservation' do - @hotel.make_reservation('2017-09-05', '2017-09-08') + it "creates a reservation and adds it to the @reservations array" do + @hotel.make_reservation('2017-09-05', '2017-09-08') - @hotel.reservations[0].must_be_kind_of Hotel::Reservation + @hotel.reservations[0].must_be_kind_of Hotel::Reservation + end end # As an administrator, I can reserve a room for a given date range From 25c2edc220827cc0c0406fb20f93e6be7b81d8fb Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 11:05:36 -0700 Subject: [PATCH 015/131] implement ::validate method --- lib/date_range.rb | 16 +++++++++++++++- specs/date_range_spec.rb | 29 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index 97a2e1845..c767c1488 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -1,3 +1,17 @@ module DateRange - # ? ? ? + def self.range(start_date, end_date) + start_date = validate(start_date) + end_date = validate(end_date) + end + + # private + + def self.validate(input) + return input if input.class == Date + begin + Date.parse(input) + rescue + raise TypeError.new("Invalid input #{input.class} - must be Date or String") + end + end end diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index e69de29bb..f28f9d28e 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -0,0 +1,29 @@ +require_relative 'spec_helper' + +describe "DateRange" do + before do + @before = Date.new(2017,03,31) + @after = Date.new(2017,10,14) + end + describe "self.range" do + + end + + describe "validate" do + it "returns input unchanged if input is a Date object" do + DateRange::validate(@before).must_equal @before + end + + it "returns a Date object if input is a String" do + date = DateRange::validate('2017-10-14') + date.must_be_kind_of Date + date.month.must_equal 10 + end + + it "raises an exception if input is neither Date or String" do + proc { + DateRange::validate(20171014) + }.must_raise TypeError + end + end +end From 77c88aca1962196aaaf32e0f4574dcc5066a0209 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 11:22:11 -0700 Subject: [PATCH 016/131] implement ::range_to method --- lib/date_range.rb | 31 ++++++++++++++++++++++++++++--- specs/date_range_spec.rb | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index c767c1488..04915cbb2 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -1,7 +1,32 @@ module DateRange - def self.range(start_date, end_date) + def self.range_to(start_date, end_date) start_date = validate(start_date) end_date = validate(end_date) + raise ArgumentError.new('Start date must be before end date') unless start_date < end_date + + dates = [] + + while start_date < end_date + dates << start_date + start_date += 1 + end + + dates + end + + def self.range_with(start_date, end_date) + start_date = validate(start_date) + end_date = validate(end_date) + raise ArgumentError.new('Start date must be before end date') unless start_date < end_date + + dates = [] + + while start_date <= end_date + dates << start_date + start_date += 1 + end + + dates end # private @@ -11,7 +36,7 @@ def self.validate(input) begin Date.parse(input) rescue - raise TypeError.new("Invalid input #{input.class} - must be Date or String") - end + raise TypeError.new("Invalid input #{input.class}-must be Date or String") + end end end diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index f28f9d28e..4c91cd831 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -1,26 +1,49 @@ require_relative 'spec_helper' -describe "DateRange" do +describe 'DateRange' do + before do - @before = Date.new(2017,03,31) + @before = Date.new(2017,10,1) @after = Date.new(2017,10,14) end - describe "self.range" do + describe 'self.range_to' do + it 'raises ArgumentError if start date is after end date' do + proc { + DateRange::range_to(@after,@before) + }.must_raise ArgumentError + end + + it 'returns an array of Dates' do + dates = DateRange::range_to(@before, @after) + + dates.must_be_kind_of Array + + dates.each do |date| + date.must_be_kind_of Date + end + end + + it 'includes all dates up to, but not including, the end date' do + dates = DateRange::range_to(@before, @after) + + dates.first.strftime.must_equal '2017-10-01' + dates.last.strftime.must_equal '2017-10-13' + end end - describe "validate" do - it "returns input unchanged if input is a Date object" do + describe 'validate' do + it 'returns input unchanged if input is a Date object' do DateRange::validate(@before).must_equal @before end - it "returns a Date object if input is a String" do + it 'returns a Date object if input is a String' do date = DateRange::validate('2017-10-14') date.must_be_kind_of Date date.month.must_equal 10 end - it "raises an exception if input is neither Date or String" do + it 'raises an exception if input is neither Date or String' do proc { DateRange::validate(20171014) }.must_raise TypeError From 3e6c923b3f9304657a9447fb8446c7d5dbd9c672 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 11:23:15 -0700 Subject: [PATCH 017/131] implement ::range_with method --- specs/date_range_spec.rb | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index 4c91cd831..57db57c09 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -28,10 +28,36 @@ dates = DateRange::range_to(@before, @after) dates.first.strftime.must_equal '2017-10-01' - dates.last.strftime.must_equal '2017-10-13' + dates.last.strftime.must_equal '2017-10-13' end end + describe 'self.range_with' do + it 'raises ArgumentError if start date is after end date' do + proc { + DateRange::range_with(@after,@before) + }.must_raise ArgumentError + end + + it 'returns an array of Dates' do + dates = DateRange::range_with(@before, @after) + + dates.must_be_kind_of Array + + dates.each do |date| + date.must_be_kind_of Date + end + end + + it 'includes all dates up to AND including the end date' do + dates = DateRange::range_with(@before, @after) + + dates.first.strftime.must_equal '2017-10-01' + dates.last.strftime.must_equal '2017-10-14' + end + end + + describe 'validate' do it 'returns input unchanged if input is a Date object' do DateRange::validate(@before).must_equal @before From 8e8afd8e030f674eddeb0645b2cc6cad416b889b Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 11:26:09 -0700 Subject: [PATCH 018/131] add room_num parameter to initialize --- lib/reservation.rb | 2 +- specs/reservation_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 838ae1fc3..0a4c44dd8 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -1,6 +1,6 @@ module Hotel class Reservation - # require_relative 'date_range' + require_relative 'date_range' # @total_cost # @dates # @room diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 66e03efb0..3e0e6af94 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -2,7 +2,7 @@ describe 'Reservation' do before do - @reservation = Hotel::Reservation.new('2017-09-05', '2017-09-07') + @reservation = Hotel::Reservation.new(1, '2017-09-05', '2017-09-07') end describe '#initialize' do From e64ba2667400fda16c1932815181c40ac5959faa Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 11:29:37 -0700 Subject: [PATCH 019/131] implement #initialize and @dates --- lib/reservation.rb | 11 ++++------- specs/reservation_spec.rb | 5 +++++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 0a4c44dd8..3d4032676 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -1,23 +1,20 @@ module Hotel class Reservation require_relative 'date_range' - # @total_cost - # @dates - # @room # @reservation_id - attr_reader :total_cost + attr_reader :total_cost, :dates def initialize(room, checkin, checkout) @room = room checkin = Date.parse(checkin) checkout = Date.parse(checkout) - # @dates = DateRange::range(checkin, checkout) + @dates = DateRange::range_to(checkin, checkout) get_total end def get_total - num_nights = (@checkout - @checkin).to_i - @total_cost = num_nights * @room.cost + num_nights = @dates.length + # @total_cost = num_nights * @room.cost end # def includes_dates?(checkin, checkout) diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 3e0e6af94..289340419 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -10,6 +10,11 @@ @reservation.must_be_kind_of Hotel::Reservation end + it 'has @dates value, which is array of dates' do + @reservation.dates.must_be_kind_of Array + @reservation.dates.first.must_be_kind_of Date + end + it 'has @total_cost value' do @reservation.total_cost.must_equal 400 end From c8d85971667484d582015b35ffefce2c1630450b Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 11:29:51 -0700 Subject: [PATCH 020/131] skip future tests --- specs/hotel_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 370a394bc..d2c15ff3c 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -28,7 +28,7 @@ end end - describe '#make_reservation' do + xdescribe '#make_reservation' do it "creates a reservation and adds it to the @reservations array" do @hotel.make_reservation('2017-09-05', '2017-09-08') From 2382fa0cfab3cb968eaa8b6f776b9c04d49e8d07 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 11:40:59 -0700 Subject: [PATCH 021/131] implement @id and #create_id --- lib/reservation.rb | 15 +++++++++++---- specs/reservation_spec.rb | 9 ++++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 3d4032676..dd999b6d1 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -2,13 +2,14 @@ module Hotel class Reservation require_relative 'date_range' # @reservation_id - attr_reader :total_cost, :dates + attr_reader :total_cost, :dates, :checkin, :checkout, :id def initialize(room, checkin, checkout) @room = room - checkin = Date.parse(checkin) - checkout = Date.parse(checkout) - @dates = DateRange::range_to(checkin, checkout) + @checkin = Date.parse(checkin) + @checkout = Date.parse(checkout) + @dates = DateRange::range_to(@checkin, @checkout) + @id = create_id get_total end @@ -17,6 +18,12 @@ def get_total # @total_cost = num_nights * @room.cost end + private + + def create_id + '%.2d%.2d%.4d' % [@checkin.month, @checkin.day, rand(9999)] + end + # def includes_dates?(checkin, checkout) # Date.parse???? # dates_to_check = DateRange::range(checkin, checkout) diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 289340419..a54f59255 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -15,8 +15,15 @@ @reservation.dates.first.must_be_kind_of Date end - it 'has @total_cost value' do + xit 'has @total_cost value, which is rate * num of nights' do @reservation.total_cost.must_equal 400 + (@reservation.total_cost % @reservation.dates.length).must_equal 0 + end + + it 'has 8-digit @reservation_id value where first 4 digits are checkin date' do + @reservation.id.must_be_kind_of String + @reservation.id.length.must_equal 8 + @reservation.id[0..3].must_equal "0905" end end end From ce2065b01da50d473da7fa38a58b80516cee2e19 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 11:52:21 -0700 Subject: [PATCH 022/131] add Hotel ROOM_COST constant of 200, pass as parameter to Room.new --- lib/hotel.rb | 3 ++- lib/room.rb | 4 ++-- specs/room_spec.rb | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 2de1a0350..d53a7dc5b 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -1,11 +1,12 @@ module Hotel class Hotel attr_reader :rooms, :reservations + ROOM_COST = 200 def initialize(num_rooms) @rooms = [] num_rooms.times do |i| - @rooms << Room.new(i+1) + @rooms << Room.new(i+1, ROOM_COST) end @reservations = [] end diff --git a/lib/room.rb b/lib/room.rb index 342a9ef7e..e5ad6f9da 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -2,9 +2,9 @@ module Hotel class Room attr_reader :number, :cost - def initialize(number) + def initialize(number, cost) @number = number - @cost = 200 + @cost = cost end # #is_avail?() diff --git a/specs/room_spec.rb b/specs/room_spec.rb index d030a294b..f902236a6 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -3,15 +3,15 @@ describe "Room" do describe "initialize" do it "can be instantiated" do - Hotel::Room.new(1).must_be_kind_of Hotel::Room + Hotel::Room.new(1, 200).must_be_kind_of Hotel::Room end it "has a room number" do - Hotel::Room.new(5).number.must_equal 5 + Hotel::Room.new(5, 200).number.must_equal 5 end it "has a cost" do - Hotel::Room.new(5).cost.must_equal 200 + Hotel::Room.new(5, 200).cost.must_equal 200 end end end From facc88f709eb746c2ef971435542cdbd493f5fdb Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 11:53:10 -0700 Subject: [PATCH 023/131] move comments --- lib/reservation.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index dd999b6d1..f611b9c1f 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -17,6 +17,14 @@ def get_total num_nights = @dates.length # @total_cost = num_nights * @room.cost end + + # def includes_dates?(checkin, checkout) + # Date.parse???? + # dates_to_check = DateRange::range(checkin, checkout) + # dates_to_check.each do |date| + # if @dates.include? date + # return true + # end private @@ -24,12 +32,5 @@ def create_id '%.2d%.2d%.4d' % [@checkin.month, @checkin.day, rand(9999)] end - # def includes_dates?(checkin, checkout) - # Date.parse???? - # dates_to_check = DateRange::range(checkin, checkout) - # dates_to_check.each do |date| - # if @dates.include? date - # return true - # end end end From 46be31531897399e143e1b3cbb2c3b41da58dbf0 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 11:53:16 -0700 Subject: [PATCH 024/131] unskip test --- specs/reservation_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index a54f59255..7f95539d4 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -15,15 +15,15 @@ @reservation.dates.first.must_be_kind_of Date end - xit 'has @total_cost value, which is rate * num of nights' do - @reservation.total_cost.must_equal 400 - (@reservation.total_cost % @reservation.dates.length).must_equal 0 - end - it 'has 8-digit @reservation_id value where first 4 digits are checkin date' do @reservation.id.must_be_kind_of String @reservation.id.length.must_equal 8 @reservation.id[0..3].must_equal "0905" end + + it 'has @total_cost value, which is rate * num of nights' do + @reservation.total_cost.must_equal 400 + (@reservation.total_cost % @reservation.dates.length).must_equal 0 + end end end From 41b1d0ff0916ccf9a0cfcf13a9dd68594093c83f Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 12:02:41 -0700 Subject: [PATCH 025/131] implement #room method --- lib/hotel.rb | 10 +++++++++- specs/hotel_spec.rb | 12 ++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index d53a7dc5b..3c00a8548 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -18,7 +18,15 @@ def all_rooms end def make_reservation(checkin, checkout) - @reservations << Reservation.new(checkin, checkout) + @reservations << Reservation.new(checkin, checkout, self) + end + + def room(num) + @rooms.each do |room| + return room if room.number == num + end + + nil end # def view_avail(checkin, checkout) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index d2c15ff3c..0a6557609 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -28,6 +28,18 @@ end end + describe '#room' do + it 'returns the Room with corresponding number' do + room = @hotel.room(4) + room.must_be_kind_of Hotel::Room + room.number.must_equal 4 + end + + it 'returns nil if room is not found' do + @hotel.room(10000).must_equal nil + end + end + xdescribe '#make_reservation' do it "creates a reservation and adds it to the @reservations array" do @hotel.make_reservation('2017-09-05', '2017-09-08') From 5b016f438e39faadeed91c772e112b2de0ca6dc7 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 12:04:07 -0700 Subject: [PATCH 026/131] implement @total_cost and #get_cost --- lib/reservation.rb | 9 +++++---- specs/reservation_spec.rb | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index f611b9c1f..3ac27cfc4 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -2,22 +2,23 @@ module Hotel class Reservation require_relative 'date_range' # @reservation_id - attr_reader :total_cost, :dates, :checkin, :checkout, :id + attr_reader :total_cost, :dates, :checkin, :checkout, :id, :hotel - def initialize(room, checkin, checkout) + def initialize(room, checkin, checkout, hotel) @room = room @checkin = Date.parse(checkin) @checkout = Date.parse(checkout) @dates = DateRange::range_to(@checkin, @checkout) @id = create_id + @hotel = hotel get_total end def get_total num_nights = @dates.length - # @total_cost = num_nights * @room.cost + @total_cost = @hotel.room(@room).cost * num_nights end - + # def includes_dates?(checkin, checkout) # Date.parse???? # dates_to_check = DateRange::range(checkin, checkout) diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 7f95539d4..bd8d09558 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -2,7 +2,8 @@ describe 'Reservation' do before do - @reservation = Hotel::Reservation.new(1, '2017-09-05', '2017-09-07') + @hotel = Hotel::Hotel.new(20) + @reservation = Hotel::Reservation.new(1, '2017-09-05', '2017-09-07', @hotel) end describe '#initialize' do @@ -20,7 +21,7 @@ @reservation.id.length.must_equal 8 @reservation.id[0..3].must_equal "0905" end - + it 'has @total_cost value, which is rate * num of nights' do @reservation.total_cost.must_equal 400 (@reservation.total_cost % @reservation.dates.length).must_equal 0 From 8edfa6cd21b09cfa6390f7319ff351f7588dd46b Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 12:14:25 -0700 Subject: [PATCH 027/131] Hotel module requires classes --- lib/hotel.rb | 7 ++++++- specs/spec_helper.rb | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 3c00a8548..bb46dee7a 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -1,4 +1,9 @@ module Hotel + require_relative 'room' + require_relative 'reservation' + require_relative 'room' + require_relative 'block' + class Hotel attr_reader :rooms, :reservations ROOM_COST = 200 @@ -25,7 +30,7 @@ def room(num) @rooms.each do |room| return room if room.number == num end - + nil end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb index 9aed63107..01810940f 100644 --- a/specs/spec_helper.rb +++ b/specs/spec_helper.rb @@ -4,10 +4,10 @@ require 'minitest/autorun' require 'minitest/reporters' require 'minitest/skip_dsl' -require_relative '../lib/block.rb' -require_relative '../lib/date_range.rb' require_relative '../lib/hotel.rb' -require_relative '../lib/reservation.rb' -require_relative '../lib/room.rb' +require_relative '../lib/block.rb' +# require_relative '../lib/date_range.rb' +# require_relative '../lib/reservation.rb' +# require_relative '../lib/room.rb' Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new From 6bc23839f3be90b77e8dde8512681280fb39f965 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 12:15:38 -0700 Subject: [PATCH 028/131] remove to_do comment --- lib/reservation.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 3ac27cfc4..6c84e3f62 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -1,7 +1,6 @@ module Hotel class Reservation require_relative 'date_range' - # @reservation_id attr_reader :total_cost, :dates, :checkin, :checkout, :id, :hotel def initialize(room, checkin, checkout, hotel) From 1b551428bd91fafcbb759e6d5b1e9f2500e0bd00 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 12:28:40 -0700 Subject: [PATCH 029/131] passes Room into Reservation.initialize instead of room number --- lib/reservation.rb | 2 +- specs/reservation_spec.rb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 6c84e3f62..e415734d9 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -15,7 +15,7 @@ def initialize(room, checkin, checkout, hotel) def get_total num_nights = @dates.length - @total_cost = @hotel.room(@room).cost * num_nights + @total_cost = @room.cost * num_nights end # def includes_dates?(checkin, checkout) diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index bd8d09558..d3633e134 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -3,7 +3,8 @@ describe 'Reservation' do before do @hotel = Hotel::Hotel.new(20) - @reservation = Hotel::Reservation.new(1, '2017-09-05', '2017-09-07', @hotel) + @room = @hotel.rooms[0] + @reservation = Hotel::Reservation.new(@room, '2017-09-05', '2017-09-07', @hotel) end describe '#initialize' do From 09e964c0794295344972eb38b6e1fb10501d03b9 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 12:28:55 -0700 Subject: [PATCH 030/131] implement #make_reservation --- lib/hotel.rb | 34 ++++++++++++++-------------------- specs/hotel_spec.rb | 13 +++++++++---- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index bb46dee7a..b53663fb0 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -23,7 +23,8 @@ def all_rooms end def make_reservation(checkin, checkout) - @reservations << Reservation.new(checkin, checkout, self) + room_num = find_available_rooms(checkin, checkout).first + @reservations << Reservation.new(room_num, checkin, checkout, self) end def room(num) @@ -50,24 +51,17 @@ def room(num) # reservations # end - # def find_available_rooms(checkin, checkout) - # booked_rooms, available_rooms = [], [] - # @reservations.each do |reservation| - # if reservation.room is not in booked_room && !(reservation.includes_dates?(checkin,checkout)) - # booked_rooms << reservation.number - # end - # end - # @rooms.each do |room| - # available_rooms << room unless booked_rooms.include?room.number - # end - # available_rooms - # end - - - # def make_reservation(checkin, checkout) - # room_num = find_available_rooms(checkin, checkout).first - # @reservations << Reservation.new(room_num, checkin, checkout) - # end - + def find_available_rooms(checkin, checkout) + booked_rooms, available_rooms = [], [] + # @reservations.each do |reservation| + # if reservation.room is not in booked_room && !(reservation.includes_dates?(checkin,checkout)) + # booked_rooms << reservation.number + # end + # end + @rooms.each do |room| + available_rooms << room unless booked_rooms.include?room.number + end + available_rooms + end end end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 0a6557609..68d0f6afd 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -40,14 +40,19 @@ end end - xdescribe '#make_reservation' do + describe "find_available_rooms" do + + end + + describe '#make_reservation' do + # As an administrator, I can reserve a room for a given date range it "creates a reservation and adds it to the @reservations array" do @hotel.make_reservation('2017-09-05', '2017-09-08') - - @hotel.reservations[0].must_be_kind_of Hotel::Reservation + reservation = @hotel.reservations[0] + reservation.must_be_kind_of Hotel::Reservation + reservation.checkout.strftime.must_equal '2017-09-08' end end - # As an administrator, I can reserve a room for a given date range # As an administrator, I can access the list of reservations for a specific date From e2ff5fd8a5ca0772beb205d12d11f1e03ed9da29 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 15:10:33 -0700 Subject: [PATCH 031/131] moved Wave 1 TODO comment from hotel to reservation spec --- specs/hotel_spec.rb | 2 -- specs/reservation_spec.rb | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 68d0f6afd..2e11e0eca 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -55,6 +55,4 @@ end # As an administrator, I can access the list of reservations for a specific date - - # As an administrator, I can get the total cost for a given reservation end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index d3633e134..0da27fdd7 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -24,6 +24,7 @@ end it 'has @total_cost value, which is rate * num of nights' do + # As an administrator, I can get the total cost for a given reservation @reservation.total_cost.must_equal 400 (@reservation.total_cost % @reservation.dates.length).must_equal 0 end From 67306ab365402d86b4e61a6150251c79fc32405b Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 15:18:44 -0700 Subject: [PATCH 032/131] implement #find_available_rooms --- lib/hotel.rb | 14 +++++++------- specs/hotel_spec.rb | 7 +++++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index b53663fb0..d34eab068 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -43,13 +43,13 @@ def room(num) # end # end - # def view_reservations(date) - # reservations = [] - # @reservations.each do |reservation| - # reservations << reservation if reservation.dates.include?(date) - # end - # reservations - # end + def view_reservations(date) + reservations = [] + @reservations.each do |reservation| + reservations << reservation if reservation.dates.include?(date) + end + reservations + end def find_available_rooms(checkin, checkout) booked_rooms, available_rooms = [], [] diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 2e11e0eca..fa80701f8 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -40,8 +40,11 @@ end end - describe "find_available_rooms" do - + describe 'find_available_rooms' do + it 'returns an array of rooms' do + rooms = @hotel.find_available_rooms('2017-09-05', '2017-09-09') + rooms.must_be_kind_of Array + end end describe '#make_reservation' do From c79af96a2ef672cb385019d1274f659b3be192b6 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 15:19:29 -0700 Subject: [PATCH 033/131] require date --- lib/date_range.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/date_range.rb b/lib/date_range.rb index 04915cbb2..b65542bf2 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -1,4 +1,6 @@ module DateRange + require 'date' + def self.range_to(start_date, end_date) start_date = validate(start_date) end_date = validate(end_date) From d37bc740387446c57402279e00c96364afdc0410 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 15:25:35 -0700 Subject: [PATCH 034/131] implement #view_reservations method --- lib/hotel.rb | 1 + specs/hotel_spec.rb | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index d34eab068..05034a012 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -44,6 +44,7 @@ def room(num) # end def view_reservations(date) + date = DateRange::validate(date) reservations = [] @reservations.each do |reservation| reservations << reservation if reservation.dates.include?(date) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index fa80701f8..1ae090acc 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -57,5 +57,18 @@ end end - # As an administrator, I can access the list of reservations for a specific date + describe '#view_reservations' do + # As an administrator, I can access the list of reservations for a specific date + it 'returns an array of Reservations' do + @hotel.make_reservation('2017-10-14','2017-10-18') + reservations = @hotel.view_reservations('2017-10-14') + + reservations.must_be_kind_of Array + reservations.length.must_equal 1 + reservations.each do |reservation| + reservation.must_be_kind_of Hotel::Reservation + end + end + end + end From 6a515561dde63fce2f9aff2b0887f0e9b44d674d Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 15:29:49 -0700 Subject: [PATCH 035/131] create class AlreadyBookedError --- lib/already_booked_error.rb | 2 ++ lib/hotel.rb | 1 + 2 files changed, 3 insertions(+) create mode 100644 lib/already_booked_error.rb diff --git a/lib/already_booked_error.rb b/lib/already_booked_error.rb new file mode 100644 index 000000000..0189384b7 --- /dev/null +++ b/lib/already_booked_error.rb @@ -0,0 +1,2 @@ +class AlreadyBookedError < StandardError +end diff --git a/lib/hotel.rb b/lib/hotel.rb index 05034a012..33d2545c0 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -3,6 +3,7 @@ module Hotel require_relative 'reservation' require_relative 'room' require_relative 'block' + require_relative 'already_booked_error' class Hotel attr_reader :rooms, :reservations From 48475b022ecefdc7986f12725d15afc5ceae9bad Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 15:29:58 -0700 Subject: [PATCH 036/131] add Wave 2 comments --- specs/hotel_spec.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 1ae090acc..f22783ae1 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -70,5 +70,10 @@ end end end - end + +# As an administrator, I can view a list of rooms that are not reserved for a given date range +# As an administrator, I can reserve an available room for a given date range +# +# A reservation is allowed start on the same day that another reservation for the same room ends +# Your code should raise an exception when asked to reserve a room that is not available From 7805a128a00aab40587d5a5a2ce818d6ec0ac1c5 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 16:10:59 -0700 Subject: [PATCH 037/131] implement #includes_dates? method --- lib/reservation.rb | 18 ++++++++++-------- specs/reservation_spec.rb | 12 ++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index e415734d9..e3852c652 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -1,7 +1,7 @@ module Hotel class Reservation require_relative 'date_range' - attr_reader :total_cost, :dates, :checkin, :checkout, :id, :hotel + attr_reader :total_cost, :dates, :checkin, :checkout, :id, :hotel, :room def initialize(room, checkin, checkout, hotel) @room = room @@ -18,13 +18,15 @@ def get_total @total_cost = @room.cost * num_nights end - # def includes_dates?(checkin, checkout) - # Date.parse???? - # dates_to_check = DateRange::range(checkin, checkout) - # dates_to_check.each do |date| - # if @dates.include? date - # return true - # end + def includes_dates?(checkfirst, checklast) + dates_to_check = DateRange::range_to(checkfirst, checklast) + dates_to_check.each do |check_date| + @dates.each do |book_date| + return true if book_date.strftime == check_date.strftime + end + end + false + end private diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 0da27fdd7..df76c2b39 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -29,4 +29,16 @@ (@reservation.total_cost % @reservation.dates.length).must_equal 0 end end + + describe '#includes_dates?' do + it 'returns true if provided date range overlaps' do + overlap = @reservation.includes_dates?('2017-09-06', '2017-09-07') + overlap.must_equal true + end + + it 'returns false if provided date range does not overlap' do + overlap = @reservation.includes_dates?('2017-10-14', '2017-10-15') + overlap.must_equal false + end + end end From e0e27b4955f1dade699c31ec48f94198747516e3 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 16:11:40 -0700 Subject: [PATCH 038/131] #view_avail method checks reservations --- lib/hotel.rb | 20 ++++++-------------- specs/hotel_spec.rb | 13 ++++++++++++- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 33d2545c0..5b76d7738 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -36,14 +36,6 @@ def room(num) nil end - # def view_avail(checkin, checkout) - # available_rooms = [] - # @rooms.each do |room| - # available_rooms << room.number if room.is_avail?(checkin, checkout) - # available_rooms - # end - # end - def view_reservations(date) date = DateRange::validate(date) reservations = [] @@ -55,13 +47,13 @@ def view_reservations(date) def find_available_rooms(checkin, checkout) booked_rooms, available_rooms = [], [] - # @reservations.each do |reservation| - # if reservation.room is not in booked_room && !(reservation.includes_dates?(checkin,checkout)) - # booked_rooms << reservation.number - # end - # end + @reservations.each do |reservation| + if !(booked_rooms.include?reservation.room) && reservation.includes_dates?(checkin, checkout) + booked_rooms << reservation.room + end + end @rooms.each do |room| - available_rooms << room unless booked_rooms.include?room.number + available_rooms << room unless booked_rooms.include?room end available_rooms end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index f22783ae1..c85416a05 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -45,6 +45,18 @@ rooms = @hotel.find_available_rooms('2017-09-05', '2017-09-09') rooms.must_be_kind_of Array end + + it 'returns only available rooms' do + @hotel.make_reservation('2017-10-14', '2017-10-18') + @hotel.make_reservation('2017-10-14', '2017-10-18') + @hotel.make_reservation('2018-10-14', '2018-10-18') + rooms = @hotel.find_available_rooms('2017-10-14', '2017-10-18') + + rooms.length.must_equal 18 + rooms.each do |room| + puts "Room number #{room.number} is free" + end + end end describe '#make_reservation' do @@ -74,6 +86,5 @@ # As an administrator, I can view a list of rooms that are not reserved for a given date range # As an administrator, I can reserve an available room for a given date range -# # A reservation is allowed start on the same day that another reservation for the same room ends # Your code should raise an exception when asked to reserve a room that is not available From 3058ab584471e8706a07242330129bb30bf696f4 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 16:19:46 -0700 Subject: [PATCH 039/131] renamed already_booked_error to no_room_error --- lib/already_booked_error.rb | 2 -- lib/no_room_error.rb | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 lib/already_booked_error.rb create mode 100644 lib/no_room_error.rb diff --git a/lib/already_booked_error.rb b/lib/already_booked_error.rb deleted file mode 100644 index 0189384b7..000000000 --- a/lib/already_booked_error.rb +++ /dev/null @@ -1,2 +0,0 @@ -class AlreadyBookedError < StandardError -end diff --git a/lib/no_room_error.rb b/lib/no_room_error.rb new file mode 100644 index 000000000..b446dfebc --- /dev/null +++ b/lib/no_room_error.rb @@ -0,0 +1,2 @@ +class NoRoomError < StandardError +end From 51d38934275423fddc315d9cdca6b36ab4bf5b4e Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 16:24:43 -0700 Subject: [PATCH 040/131] implement NoRoomError, tests for availability --- lib/hotel.rb | 5 ++++- specs/hotel_spec.rb | 45 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 5b76d7738..ab78aefbc 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -3,7 +3,7 @@ module Hotel require_relative 'reservation' require_relative 'room' require_relative 'block' - require_relative 'already_booked_error' + require_relative 'no_room_error' class Hotel attr_reader :rooms, :reservations @@ -25,6 +25,9 @@ def all_rooms def make_reservation(checkin, checkout) room_num = find_available_rooms(checkin, checkout).first + if room_num == nil + raise NoRoomError.new("No available rooms for dates #{checkin} - #{checkout}") + end @reservations << Reservation.new(room_num, checkin, checkout, self) end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index c85416a05..12e91db12 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -41,6 +41,7 @@ end describe 'find_available_rooms' do + # As an administrator, I can view a list of rooms that are not reserved for a given date range it 'returns an array of rooms' do rooms = @hotel.find_available_rooms('2017-09-05', '2017-09-09') rooms.must_be_kind_of Array @@ -53,20 +54,53 @@ rooms = @hotel.find_available_rooms('2017-10-14', '2017-10-18') rooms.length.must_equal 18 - rooms.each do |room| - puts "Room number #{room.number} is free" - end end end describe '#make_reservation' do # As an administrator, I can reserve a room for a given date range + # As an administrator, I can reserve an available room for a given date range it "creates a reservation and adds it to the @reservations array" do @hotel.make_reservation('2017-09-05', '2017-09-08') reservation = @hotel.reservations[0] reservation.must_be_kind_of Hotel::Reservation reservation.checkout.strftime.must_equal '2017-09-08' end + + it 'will reserve the first available room' do + @hotel.make_reservation('2017-09-05', '2017-09-08') + @hotel.make_reservation('2017-09-05', '2017-09-08') + reservation1 = @hotel.reservations[0] + reservation2 = @hotel.reservations[1] + + reservation1.room.wont_equal reservation2.room + end + + it 'will book a room again after a reservation ends' do + @hotel.make_reservation('2017-09-05', '2017-09-08') + @hotel.make_reservation('2018-09-05', '2018-09-08') + reservation1 = @hotel.reservations[0] + reservation2 = @hotel.reservations[1] + + reservation1.room.must_equal reservation2.room + end + + it 'can book two consecutive reservations to the same room' do + # A reservation is allowed start on the same day that another reservation for the same room ends + @hotel.make_reservation('2017-09-05', '2017-09-08') + @hotel.make_reservation('2017-09-08', '2017-09-11') + reservation1 = @hotel.reservations[0] + reservation2 = @hotel.reservations[1] + + reservation1.room.must_equal reservation2.room + end + + it 'raises NoRoomError if no rooms are available' do + # Your code should raise an exception when asked to reserve a room that is not available + proc { + 21.times { @hotel.make_reservation('2017-09-05', '2017-09-08') } + }.must_raise NoRoomError + end end describe '#view_reservations' do @@ -83,8 +117,3 @@ end end end - -# As an administrator, I can view a list of rooms that are not reserved for a given date range -# As an administrator, I can reserve an available room for a given date range -# A reservation is allowed start on the same day that another reservation for the same room ends -# Your code should raise an exception when asked to reserve a room that is not available From db06bfd6cf0ed91931f8ff201944cb3e0f162325 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 16:29:30 -0700 Subject: [PATCH 041/131] #all_rooms returns list of Rooms, not numbers --- lib/hotel.rb | 2 +- specs/hotel_spec.rb | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index ab78aefbc..18ef37a0a 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -19,7 +19,7 @@ def initialize(num_rooms) def all_rooms list = [] - @rooms.each { |room| list << room.number } + @rooms.each { |room| list << room } list end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 12e91db12..fd7dc0e33 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -24,7 +24,11 @@ describe '#all_rooms' do # As an administrator, I can access the list of all of the rooms in the hotel it 'Returns an array of all room numbers' do - @hotel.all_rooms.must_equal (1..20).to_a + all_rooms = @hotel.all_rooms + all_rooms.must_be_kind_of Array + all_rooms.each do |room| + room.must_be_kind_of Hotel::Room + end end end From b2d1a366f9168e968e0014edc3402dfa5849d77b Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Wed, 6 Sep 2017 16:45:27 -0700 Subject: [PATCH 042/131] rubocop style guide tweaks --- lib/date_range.rb | 7 +++---- lib/hotel.rb | 12 ++++++------ lib/reservation.rb | 7 +++---- specs/date_range_spec.rb | 24 +++++++++++------------- specs/hotel_spec.rb | 11 +++++------ specs/reservation_spec.rb | 4 ++-- specs/room_spec.rb | 10 +++++----- 7 files changed, 35 insertions(+), 40 deletions(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index b65542bf2..1c729e85a 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -1,10 +1,9 @@ module DateRange require 'date' - def self.range_to(start_date, end_date) start_date = validate(start_date) end_date = validate(end_date) - raise ArgumentError.new('Start date must be before end date') unless start_date < end_date + raise(ArgumentError, 'Start date must be before end date') unless start_date < end_date dates = [] @@ -19,7 +18,7 @@ def self.range_to(start_date, end_date) def self.range_with(start_date, end_date) start_date = validate(start_date) end_date = validate(end_date) - raise ArgumentError.new('Start date must be before end date') unless start_date < end_date + raise(ArgumentError, 'Start date must be before end date') unless start_date < end_date dates = [] @@ -38,7 +37,7 @@ def self.validate(input) begin Date.parse(input) rescue - raise TypeError.new("Invalid input #{input.class}-must be Date or String") + raise(TypeError, "Invalid input #{input.class}-must be Date or String") end end end diff --git a/lib/hotel.rb b/lib/hotel.rb index 18ef37a0a..6171337a3 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -12,7 +12,7 @@ class Hotel def initialize(num_rooms) @rooms = [] num_rooms.times do |i| - @rooms << Room.new(i+1, ROOM_COST) + @rooms << Room.new(i + 1, ROOM_COST) end @reservations = [] end @@ -25,8 +25,8 @@ def all_rooms def make_reservation(checkin, checkout) room_num = find_available_rooms(checkin, checkout).first - if room_num == nil - raise NoRoomError.new("No available rooms for dates #{checkin} - #{checkout}") + if room_num.nil? + raise(NoRoomError, "No available rooms for dates #{checkin} - #{checkout}") end @reservations << Reservation.new(room_num, checkin, checkout, self) end @@ -40,7 +40,7 @@ def room(num) end def view_reservations(date) - date = DateRange::validate(date) + date = DateRange.validate(date) reservations = [] @reservations.each do |reservation| reservations << reservation if reservation.dates.include?(date) @@ -51,12 +51,12 @@ def view_reservations(date) def find_available_rooms(checkin, checkout) booked_rooms, available_rooms = [], [] @reservations.each do |reservation| - if !(booked_rooms.include?reservation.room) && reservation.includes_dates?(checkin, checkout) + if !(booked_rooms.include? reservation.room) && reservation.includes_dates?(checkin, checkout) booked_rooms << reservation.room end end @rooms.each do |room| - available_rooms << room unless booked_rooms.include?room + available_rooms << room unless booked_rooms.include? room end available_rooms end diff --git a/lib/reservation.rb b/lib/reservation.rb index e3852c652..af06b5f7f 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -7,7 +7,7 @@ def initialize(room, checkin, checkout, hotel) @room = room @checkin = Date.parse(checkin) @checkout = Date.parse(checkout) - @dates = DateRange::range_to(@checkin, @checkout) + @dates = DateRange.range_to(@checkin, @checkout) @id = create_id @hotel = hotel get_total @@ -19,7 +19,7 @@ def get_total end def includes_dates?(checkfirst, checklast) - dates_to_check = DateRange::range_to(checkfirst, checklast) + dates_to_check = DateRange.range_to(checkfirst, checklast) dates_to_check.each do |check_date| @dates.each do |book_date| return true if book_date.strftime == check_date.strftime @@ -31,8 +31,7 @@ def includes_dates?(checkfirst, checklast) private def create_id - '%.2d%.2d%.4d' % [@checkin.month, @checkin.day, rand(9999)] + format('%.2d%.2d%.4d', @checkin.month, @checkin.day, rand(9999)) end - end end diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index 57db57c09..d9cd464ec 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -1,21 +1,20 @@ require_relative 'spec_helper' describe 'DateRange' do - before do - @before = Date.new(2017,10,1) - @after = Date.new(2017,10,14) + @before = Date.new(2017, 10, 1) + @after = Date.new(2017, 10, 14) end describe 'self.range_to' do it 'raises ArgumentError if start date is after end date' do proc { - DateRange::range_to(@after,@before) + DateRange.range_to(@after, @before) }.must_raise ArgumentError end it 'returns an array of Dates' do - dates = DateRange::range_to(@before, @after) + dates = DateRange.range_to(@before, @after) dates.must_be_kind_of Array @@ -25,7 +24,7 @@ end it 'includes all dates up to, but not including, the end date' do - dates = DateRange::range_to(@before, @after) + dates = DateRange.range_to(@before, @after) dates.first.strftime.must_equal '2017-10-01' dates.last.strftime.must_equal '2017-10-13' @@ -35,12 +34,12 @@ describe 'self.range_with' do it 'raises ArgumentError if start date is after end date' do proc { - DateRange::range_with(@after,@before) + DateRange.range_with(@after, @before) }.must_raise ArgumentError end it 'returns an array of Dates' do - dates = DateRange::range_with(@before, @after) + dates = DateRange.range_with(@before, @after) dates.must_be_kind_of Array @@ -50,28 +49,27 @@ end it 'includes all dates up to AND including the end date' do - dates = DateRange::range_with(@before, @after) + dates = DateRange.range_with(@before, @after) dates.first.strftime.must_equal '2017-10-01' dates.last.strftime.must_equal '2017-10-14' end end - describe 'validate' do it 'returns input unchanged if input is a Date object' do - DateRange::validate(@before).must_equal @before + DateRange.validate(@before).must_equal @before end it 'returns a Date object if input is a String' do - date = DateRange::validate('2017-10-14') + date = DateRange.validate('2017-10-14') date.must_be_kind_of Date date.month.must_equal 10 end it 'raises an exception if input is neither Date or String' do proc { - DateRange::validate(20171014) + DateRange.validate(2017_10_14) }.must_raise TypeError end end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index fd7dc0e33..38ddfe4c8 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -1,13 +1,12 @@ require_relative 'spec_helper' - describe 'Hotel' do before do @hotel = Hotel::Hotel.new(20) end describe '#initialize' do - it "Can be instantiated" do + it 'Can be instantiated' do @hotel.must_be_kind_of Hotel::Hotel end @@ -40,7 +39,7 @@ end it 'returns nil if room is not found' do - @hotel.room(10000).must_equal nil + @hotel.room(1000).must_equal nil end end @@ -64,7 +63,7 @@ describe '#make_reservation' do # As an administrator, I can reserve a room for a given date range # As an administrator, I can reserve an available room for a given date range - it "creates a reservation and adds it to the @reservations array" do + it 'creates a reservation and adds it to the @reservations array' do @hotel.make_reservation('2017-09-05', '2017-09-08') reservation = @hotel.reservations[0] reservation.must_be_kind_of Hotel::Reservation @@ -103,14 +102,14 @@ # Your code should raise an exception when asked to reserve a room that is not available proc { 21.times { @hotel.make_reservation('2017-09-05', '2017-09-08') } - }.must_raise NoRoomError + }.must_raise NoRoomError end end describe '#view_reservations' do # As an administrator, I can access the list of reservations for a specific date it 'returns an array of Reservations' do - @hotel.make_reservation('2017-10-14','2017-10-18') + @hotel.make_reservation('2017-10-14', '2017-10-18') reservations = @hotel.view_reservations('2017-10-14') reservations.must_be_kind_of Array diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index df76c2b39..32acd19e5 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -20,7 +20,7 @@ it 'has 8-digit @reservation_id value where first 4 digits are checkin date' do @reservation.id.must_be_kind_of String @reservation.id.length.must_equal 8 - @reservation.id[0..3].must_equal "0905" + @reservation.id[0..3].must_equal '0905' end it 'has @total_cost value, which is rate * num of nights' do @@ -38,7 +38,7 @@ it 'returns false if provided date range does not overlap' do overlap = @reservation.includes_dates?('2017-10-14', '2017-10-15') - overlap.must_equal false + overlap.must_equal false end end end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index f902236a6..28011d8c0 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -1,16 +1,16 @@ require_relative 'spec_helper' -describe "Room" do - describe "initialize" do - it "can be instantiated" do +describe 'Room' do + describe 'initialize' do + it 'can be instantiated' do Hotel::Room.new(1, 200).must_be_kind_of Hotel::Room end - it "has a room number" do + it 'has a room number' do Hotel::Room.new(5, 200).number.must_equal 5 end - it "has a cost" do + it 'has a cost' do Hotel::Room.new(5, 200).cost.must_equal 200 end end From ba9c895cf6e7ff15c09b94e0afe693cb17035ee7 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 10:01:27 -0700 Subject: [PATCH 043/131] #make_reservation returns reservation, pseudocode for #make_block --- lib/hotel.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 6171337a3..dde203551 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -24,11 +24,14 @@ def all_rooms end def make_reservation(checkin, checkout) + #TODO: add block functionality room_num = find_available_rooms(checkin, checkout).first if room_num.nil? raise(NoRoomError, "No available rooms for dates #{checkin} - #{checkout}") end - @reservations << Reservation.new(room_num, checkin, checkout, self) + reservation = Reservation.new(room_num, checkin, checkout, self) + @reservations << reservation + reservation end def room(num) @@ -49,6 +52,7 @@ def view_reservations(date) end def find_available_rooms(checkin, checkout) + # TODO: add block functionality booked_rooms, available_rooms = [], [] @reservations.each do |reservation| if !(booked_rooms.include? reservation.room) && reservation.includes_dates?(checkin, checkout) @@ -60,5 +64,12 @@ def find_available_rooms(checkin, checkout) end available_rooms end + + def create_block(start_date, end_date, num_rooms, discount) + # rooms = find_available_rooms(start_date, end_date)[0...num_rooms] + # block = Block.new(start_date, end_date, rooms, discount) + # @blocks << block + # block + end end end From 2864b1b4086f848cf9abf8e6929450d0ee864a4d Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 10:15:11 -0700 Subject: [PATCH 044/131] add #initialize for Block class, implement basic #make_block method --- lib/block.rb | 7 +++++++ lib/hotel.rb | 13 +++++++------ specs/block_spec.rb | 12 ++++++++++++ specs/hotel_spec.rb | 19 +++++++++++++++++++ 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index 86c9e0d94..7a7a24c0e 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -3,5 +3,12 @@ class Block # @rooms # @dates # @discount_rate + def initialize(start_date, end_date, rooms, discount_rate) + @start_date = start_date + @end_date = end_date + @dates = DateRange.range_to(@start_date, @end_date) + @rooms = rooms + @discount_rate = (100 - discount_rate) / 100 + end end end diff --git a/lib/hotel.rb b/lib/hotel.rb index dde203551..0e3f02c1b 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -6,7 +6,7 @@ module Hotel require_relative 'no_room_error' class Hotel - attr_reader :rooms, :reservations + attr_reader :rooms, :reservations, :blocks ROOM_COST = 200 def initialize(num_rooms) @@ -15,6 +15,7 @@ def initialize(num_rooms) @rooms << Room.new(i + 1, ROOM_COST) end @reservations = [] + @blocks = [] end def all_rooms @@ -65,11 +66,11 @@ def find_available_rooms(checkin, checkout) available_rooms end - def create_block(start_date, end_date, num_rooms, discount) - # rooms = find_available_rooms(start_date, end_date)[0...num_rooms] - # block = Block.new(start_date, end_date, rooms, discount) - # @blocks << block - # block + def make_block(start_date, end_date, num_rooms, discount) + rooms = find_available_rooms(start_date, end_date)[0...num_rooms] + block = Block.new(start_date, end_date, rooms, discount) + @blocks << block + block end end end diff --git a/specs/block_spec.rb b/specs/block_spec.rb index e69de29bb..8c4985278 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -0,0 +1,12 @@ +require_relative 'spec_helper' + +describe 'Block' do + before do + # - To create a block you need a date range, collection of rooms and a discounted room rate + @block = Hotel::Block.new('2017-08-03', '2017-08-07', 5, 20) + end + + it 'can be instantiated' do + @block.must_be_kind_of Hotel::Block + end +end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 38ddfe4c8..2cffc8bb7 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -119,4 +119,23 @@ end end end + + describe '#make_block' do + # - As an administrator, I can create a block of rooms + it 'returns a new Block object' do + block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) + block.must_be_kind_of Hotel::Block + end + + it 'adds to @blocks array' do + block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) + + @hotel.blocks.length.must_equal 1 + end + end end + +# - The collection of rooms should only include rooms that are available for the given date range +# - If a room is set aside in a block, it is not available for reservation by the general public, nor can it be included in another block +# - As an administrator, I can check whether a given block has any rooms available +# - As an administrator, I can reserve a room from within a block of rooms From e4d87915602773f743be413bb427b9ca8929ce12 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 10:28:15 -0700 Subject: [PATCH 045/131] Hotel.create_block will not take booked room --- lib/block.rb | 5 ++--- lib/hotel.rb | 1 - specs/hotel_spec.rb | 19 +++++++++++++++---- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index 7a7a24c0e..d063068d2 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -1,8 +1,7 @@ module Hotel class Block - # @rooms - # @dates - # @discount_rate + attr_reader :rooms + def initialize(start_date, end_date, rooms, discount_rate) @start_date = start_date @end_date = end_date diff --git a/lib/hotel.rb b/lib/hotel.rb index 0e3f02c1b..788a10be1 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -39,7 +39,6 @@ def room(num) @rooms.each do |room| return room if room.number == num end - nil end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 2cffc8bb7..658d88c53 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -121,17 +121,28 @@ end describe '#make_block' do + before do + @block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) + end + # - As an administrator, I can create a block of rooms it 'returns a new Block object' do - block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) - block.must_be_kind_of Hotel::Block + @block.must_be_kind_of Hotel::Block end it 'adds to @blocks array' do - block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) - @hotel.blocks.length.must_equal 1 end + + it 'fills block with available rooms only' do + 3.times { @hotel.make_reservation('2017-10-05', '2017-10-07') } + new_block = @hotel.make_block('2017-10-03', '2017-10-07', 10, 20) + reserved = @hotel.view_reservations('2017-10-06') + + reserved.each do |reservation| + new_block.rooms.wont_include reservation.room + end + end end end From 1de2b4bf5be54b0175b48f37acc6d3e04c1b5358 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 13:32:08 -0700 Subject: [PATCH 046/131] dry out #make_reservation tests --- specs/hotel_spec.rb | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 658d88c53..3280bdb49 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -61,41 +61,38 @@ end describe '#make_reservation' do - # As an administrator, I can reserve a room for a given date range - # As an administrator, I can reserve an available room for a given date range + before do + @reservation1 = @hotel.make_reservation('2017-09-05', '2017-09-08') + end it 'creates a reservation and adds it to the @reservations array' do - @hotel.make_reservation('2017-09-05', '2017-09-08') - reservation = @hotel.reservations[0] - reservation.must_be_kind_of Hotel::Reservation - reservation.checkout.strftime.must_equal '2017-09-08' + # As an administrator, I can reserve a room for a given date range + @reservation1.must_be_kind_of Hotel::Reservation + @reservation1.checkout.strftime.must_equal '2017-09-08' end it 'will reserve the first available room' do - @hotel.make_reservation('2017-09-05', '2017-09-08') - @hotel.make_reservation('2017-09-05', '2017-09-08') - reservation1 = @hotel.reservations[0] - reservation2 = @hotel.reservations[1] - - reservation1.room.wont_equal reservation2.room + # As an administrator, I can reserve an available room for a given date range + reservation2 = @hotel.make_reservation('2017-09-05', '2017-09-08') + @reservation1.room.wont_equal reservation2.room end it 'will book a room again after a reservation ends' do - @hotel.make_reservation('2017-09-05', '2017-09-08') - @hotel.make_reservation('2018-09-05', '2018-09-08') - reservation1 = @hotel.reservations[0] - reservation2 = @hotel.reservations[1] + reservation2 = @hotel.make_reservation('2018-09-05', '2018-09-08') - reservation1.room.must_equal reservation2.room + @reservation1.room.must_equal reservation2.room end it 'can book two consecutive reservations to the same room' do # A reservation is allowed start on the same day that another reservation for the same room ends - @hotel.make_reservation('2017-09-05', '2017-09-08') - @hotel.make_reservation('2017-09-08', '2017-09-11') - reservation1 = @hotel.reservations[0] - reservation2 = @hotel.reservations[1] + reservation2 = @hotel.make_reservation('2017-09-08', '2017-09-11') + + @reservation1.room.must_equal reservation2.room + end + + it 'will not book a room that is part of a block' do + block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) + @hotel.make_reservation('2017-08-04', '2017-08-05') - reservation1.room.must_equal reservation2.room end it 'raises NoRoomError if no rooms are available' do @@ -135,6 +132,7 @@ end it 'fills block with available rooms only' do + # - The collection of rooms should only include rooms that are available for the given date range 3.times { @hotel.make_reservation('2017-10-05', '2017-10-07') } new_block = @hotel.make_block('2017-10-03', '2017-10-07', 10, 20) reserved = @hotel.view_reservations('2017-10-06') @@ -146,7 +144,6 @@ end end -# - The collection of rooms should only include rooms that are available for the given date range # - If a room is set aside in a block, it is not available for reservation by the general public, nor can it be included in another block # - As an administrator, I can check whether a given block has any rooms available # - As an administrator, I can reserve a room from within a block of rooms From 492cfc03da3764f8df776c32145b09f1010f1e9b Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 13:41:06 -0700 Subject: [PATCH 047/131] added 'block = false' argument to #make_reservation, #find_available_rooms, and Reservation.initialize methods --- lib/hotel.rb | 8 ++++---- lib/reservation.rb | 2 +- specs/hotel_spec.rb | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 788a10be1..c909b5b9d 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -24,13 +24,13 @@ def all_rooms list end - def make_reservation(checkin, checkout) + def make_reservation(checkin, checkout, block = false) #TODO: add block functionality - room_num = find_available_rooms(checkin, checkout).first + room_num = find_available_rooms(checkin, checkout, block).first if room_num.nil? raise(NoRoomError, "No available rooms for dates #{checkin} - #{checkout}") end - reservation = Reservation.new(room_num, checkin, checkout, self) + reservation = Reservation.new(room_num, checkin, checkout, self, block) @reservations << reservation reservation end @@ -51,7 +51,7 @@ def view_reservations(date) reservations end - def find_available_rooms(checkin, checkout) + def find_available_rooms(checkin, checkout, block = false) # TODO: add block functionality booked_rooms, available_rooms = [], [] @reservations.each do |reservation| diff --git a/lib/reservation.rb b/lib/reservation.rb index af06b5f7f..ce5fc0be8 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -3,7 +3,7 @@ class Reservation require_relative 'date_range' attr_reader :total_cost, :dates, :checkin, :checkout, :id, :hotel, :room - def initialize(room, checkin, checkout, hotel) + def initialize(room, checkin, checkout, hotel, block = false) @room = room @checkin = Date.parse(checkin) @checkout = Date.parse(checkout) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 3280bdb49..31ce1d7c6 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -91,8 +91,9 @@ it 'will not book a room that is part of a block' do block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) - @hotel.make_reservation('2017-08-04', '2017-08-05') + reservation = @hotel.make_reservation('2017-08-04', '2017-08-05') + block.rooms.wont_include reservation.room end it 'raises NoRoomError if no rooms are available' do From 53439e8e39d786447b7b9f42dbd8cb3b376f22f2 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 13:47:06 -0700 Subject: [PATCH 048/131] add leading B or R to block & reservation IDs --- lib/block.rb | 7 ++++++- lib/reservation.rb | 2 +- specs/block_spec.rb | 6 ++++++ specs/reservation_spec.rb | 6 +++--- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index d063068d2..ac83eb87b 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -1,13 +1,18 @@ module Hotel class Block attr_reader :rooms - + def initialize(start_date, end_date, rooms, discount_rate) @start_date = start_date @end_date = end_date @dates = DateRange.range_to(@start_date, @end_date) @rooms = rooms @discount_rate = (100 - discount_rate) / 100 + @id = create_id + end + + def create_id + format('B%.2d%.2d%.4d', @start_date.month, @start_date.day, rand(9999)) end end end diff --git a/lib/reservation.rb b/lib/reservation.rb index ce5fc0be8..ebd63decf 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -31,7 +31,7 @@ def includes_dates?(checkfirst, checklast) private def create_id - format('%.2d%.2d%.4d', @checkin.month, @checkin.day, rand(9999)) + format('R%.2d%.2d%.4d', @checkin.month, @checkin.day, rand(9999)) end end end diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 8c4985278..0ccd20c04 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -9,4 +9,10 @@ it 'can be instantiated' do @block.must_be_kind_of Hotel::Block end + + it 'has 9-character @id value' do + @block.id.must_be_kind_of String + @block.id.length.must_equal 9 + @block.id[0..4].must_equal 'B0803' + end end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 32acd19e5..d0683861e 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -17,10 +17,10 @@ @reservation.dates.first.must_be_kind_of Date end - it 'has 8-digit @reservation_id value where first 4 digits are checkin date' do + it 'has 9-character @id value' do @reservation.id.must_be_kind_of String - @reservation.id.length.must_equal 8 - @reservation.id[0..3].must_equal '0905' + @reservation.id.length.must_equal 9 + @reservation.id[0..4].must_equal 'R0905' end it 'has @total_cost value, which is rate * num of nights' do From 67f6684979ec3b81e961cfdaedca1ac9d061af23 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 13:59:12 -0700 Subject: [PATCH 049/131] pseudocode and skeleton tests for adding block functionality to #find_available_rooms --- lib/hotel.rb | 14 ++++++++++++++ specs/hotel_spec.rb | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/hotel.rb b/lib/hotel.rb index c909b5b9d..79f047a05 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -53,6 +53,20 @@ def view_reservations(date) def find_available_rooms(checkin, checkout, block = false) # TODO: add block functionality + + # if block + # raise exception if search dates dont match block dates + # @rooms.each do + # booked_rooms << room unless room is in block + # end + # else + # blocks.each do |block| + # if block.includes_dates?(checkin, checkout) + # booked_rooms += block.rooms + # end + # end + # end + booked_rooms, available_rooms = [], [] @reservations.each do |reservation| if !(booked_rooms.include? reservation.room) && reservation.includes_dates?(checkin, checkout) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 31ce1d7c6..00e72e496 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -58,6 +58,14 @@ rooms.length.must_equal 18 end + + it 'will not return rooms in a block' do + + end + + it 'will return rooms in a provided block' do + + end end describe '#make_reservation' do From e9b1155c064eadfd5a5d0283b3eafab4eaaeddc1 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 13:59:39 -0700 Subject: [PATCH 050/131] fix date issue in @id and #create_id --- lib/block.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index ac83eb87b..b9e8a385f 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -1,10 +1,10 @@ module Hotel class Block - attr_reader :rooms + attr_reader :rooms, :id def initialize(start_date, end_date, rooms, discount_rate) - @start_date = start_date - @end_date = end_date + @start_date = Date.parse(start_date) + @end_date = Date.parse(end_date) @dates = DateRange.range_to(@start_date, @end_date) @rooms = rooms @discount_rate = (100 - discount_rate) / 100 From ed39e6a5db9adf2840e03c36ba42fe78c61c3e80 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 14:12:43 -0700 Subject: [PATCH 051/131] moved Reservation.includes_dates? functionality into DateRange.overlap? --- lib/date_range.rb | 23 +++++++++++++++++------ lib/reservation.rb | 8 +------- specs/date_range_spec.rb | 24 +++++++++++++++++++++++- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index 1c729e85a..712d05503 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -4,14 +4,11 @@ def self.range_to(start_date, end_date) start_date = validate(start_date) end_date = validate(end_date) raise(ArgumentError, 'Start date must be before end date') unless start_date < end_date - dates = [] - while start_date < end_date dates << start_date start_date += 1 end - dates end @@ -19,17 +16,31 @@ def self.range_with(start_date, end_date) start_date = validate(start_date) end_date = validate(end_date) raise(ArgumentError, 'Start date must be before end date') unless start_date < end_date - dates = [] - while start_date <= end_date dates << start_date start_date += 1 end - dates end + def self.overlap?(first_start, first_end, second_start, second_end) + first_start = validate(first_start) + first_end = validate(first_end) + second_start = validate(second_start) + second_end = validate(second_end) + + first_dates = DateRange.range_to(first_start, first_end) + second_dates = DateRange.range_to(second_start, second_end) + + first_dates.each do |first_date| + second_dates.each do |second_date| + return true if first_date.strftime == second_date.strftime + end + end + false + end + # private def self.validate(input) diff --git a/lib/reservation.rb b/lib/reservation.rb index ebd63decf..0bad418c0 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -19,13 +19,7 @@ def get_total end def includes_dates?(checkfirst, checklast) - dates_to_check = DateRange.range_to(checkfirst, checklast) - dates_to_check.each do |check_date| - @dates.each do |book_date| - return true if book_date.strftime == check_date.strftime - end - end - false + DateRange.overlap?(checkfirst, checklast, @checkin, @checkout) end private diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index d9cd464ec..ae5d8a1ba 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -56,7 +56,29 @@ end end - describe 'validate' do + describe 'self.overlap?' do + it 'returns true if provided date range overlaps' do + overlap = DateRange.overlap?('2017-09-06', '2017-09-07', '2017-09-06', '2017-09-07') + overlap.must_equal true + end + + it 'returns false if provided date range does not overlap' do + overlap = DateRange.overlap?('2017-10-14', '2017-10-15', '2017-09-06', '2017-09-07') + overlap.must_equal false + end + + it 'returns true for partial overlap' do + overlap = DateRange.overlap?('2017-09-06', '2017-09-10', '2017-09-8', '2017-09-20') + overlap.must_equal true + end + + it 'allows one range to end the day the next starts' do + overlap = DateRange.overlap?('2017-09-06', '2017-09-10', '2017-09-10', '2017-09-20') + overlap.must_equal false + end + end + + describe 'self.validate' do it 'returns input unchanged if input is a Date object' do DateRange.validate(@before).must_equal @before end From ca39406a149efda3d0a702183a881c45ad041485 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 14:19:54 -0700 Subject: [PATCH 052/131] add reader methods for dates --- lib/block.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/block.rb b/lib/block.rb index b9e8a385f..12dd5907a 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -1,6 +1,6 @@ module Hotel class Block - attr_reader :rooms, :id + attr_reader :rooms, :id, :start_date, :end_date, :dates def initialize(start_date, end_date, rooms, discount_rate) @start_date = Date.parse(start_date) From 33dce756571d41d45880bbafa67d3ba5ceeaa858 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 14:25:15 -0700 Subject: [PATCH 053/131] #find_available_rooms raises RangeError if passed incongruent dates & block --- lib/hotel.rb | 28 +++++++++++++++++++--------- specs/hotel_spec.rb | 17 +++++++++++++++++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 79f047a05..ebf2174b7 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -35,12 +35,6 @@ def make_reservation(checkin, checkout, block = false) reservation end - def room(num) - @rooms.each do |room| - return room if room.number == num - end - nil - end def view_reservations(date) date = DateRange.validate(date) @@ -51,11 +45,13 @@ def view_reservations(date) reservations end - def find_available_rooms(checkin, checkout, block = false) + def find_available_rooms(checkin, checkout, block_id = false) # TODO: add block functionality - # if block - # raise exception if search dates dont match block dates + if block_id + current_block = block(block_id) + raise(RangeError,"Dates (#{checkin}, #{checkout}) do not fall within provided block #{current_block.id}") unless DateRange.overlap?(checkin, checkout, current_block.start_date, current_block.end_date) + end # @rooms.each do # booked_rooms << room unless room is in block # end @@ -85,5 +81,19 @@ def make_block(start_date, end_date, num_rooms, discount) @blocks << block block end + + def room(num) + @rooms.each do |room| + return room if room.number == num + end + nil + end + + def block(id) + @blocks.each do |block| + return block if block.id == id + end + nil + end end end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 00e72e496..adc9a9f6d 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -60,11 +60,27 @@ end it 'will not return rooms in a block' do + skip + @hotel.make_reservation('2017-10-14', '2017-10-18') + @hotel.make_block('2017-10-10', '2017-10-16', 5, 20) + rooms = @hotel.find_available_rooms('2017-10-14','2017-10-15') + rooms.length.must_equal 14 end it 'will return rooms in a provided block' do + skip + block = @hotel.make_block('2017-10-10', '2017-10-16', 5, 20) + rooms = @hotel.find_available_rooms('2017-10-14','2017-10-15', block.id) + + rooms.length.must_equal 5 + end + + it 'raises an error if dates do not fall within given block' do + block = @hotel.make_block('2017-08-03', '2017-08-08', 5, 20) + proc { @hotel.find_available_rooms('2017-10-14', '2017-10-15', block.id) + }.must_raise RangeError end end @@ -98,6 +114,7 @@ end it 'will not book a room that is part of a block' do + skip block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) reservation = @hotel.make_reservation('2017-08-04', '2017-08-05') From c40839c3a762dc5f08af0f6f960522cc840551b7 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 14:42:55 -0700 Subject: [PATCH 054/131] add block functionality to #make_reservation --- lib/hotel.rb | 22 +++++++++++----------- specs/hotel_spec.rb | 39 +++++++++++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index ebf2174b7..0c9958a29 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -48,22 +48,21 @@ def view_reservations(date) def find_available_rooms(checkin, checkout, block_id = false) # TODO: add block functionality + booked_rooms, available_rooms = [], [] + if block_id current_block = block(block_id) raise(RangeError,"Dates (#{checkin}, #{checkout}) do not fall within provided block #{current_block.id}") unless DateRange.overlap?(checkin, checkout, current_block.start_date, current_block.end_date) + + @rooms.each do |room| + booked_rooms << room unless current_block.rooms.include? room + end + else # not in block + @blocks.each do |block| + booked_rooms += block.rooms if block.includes_dates?(checkin, checkout) + end end - # @rooms.each do - # booked_rooms << room unless room is in block - # end - # else - # blocks.each do |block| - # if block.includes_dates?(checkin, checkout) - # booked_rooms += block.rooms - # end - # end - # end - booked_rooms, available_rooms = [], [] @reservations.each do |reservation| if !(booked_rooms.include? reservation.room) && reservation.includes_dates?(checkin, checkout) booked_rooms << reservation.room @@ -77,6 +76,7 @@ def find_available_rooms(checkin, checkout, block_id = false) def make_block(start_date, end_date, num_rooms, discount) rooms = find_available_rooms(start_date, end_date)[0...num_rooms] + raise(NoRoomError, "Not enough available rooms for amount #{num_rooms}") if rooms.length < num_rooms block = Block.new(start_date, end_date, rooms, discount) @blocks << block block diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index adc9a9f6d..fcebe9abc 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -60,7 +60,7 @@ end it 'will not return rooms in a block' do - skip + # skip @hotel.make_reservation('2017-10-14', '2017-10-18') @hotel.make_block('2017-10-10', '2017-10-16', 5, 20) rooms = @hotel.find_available_rooms('2017-10-14','2017-10-15') @@ -68,8 +68,8 @@ rooms.length.must_equal 14 end - it 'will return rooms in a provided block' do - skip + it 'will return rooms in a block when provided block ID' do + # skip block = @hotel.make_block('2017-10-10', '2017-10-16', 5, 20) rooms = @hotel.find_available_rooms('2017-10-14','2017-10-15', block.id) @@ -114,19 +114,34 @@ end it 'will not book a room that is part of a block' do - skip + # - If a room is set aside in a block, it is not available for reservation by the general public block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) reservation = @hotel.make_reservation('2017-08-04', '2017-08-05') block.rooms.wont_include reservation.room end + it 'will book room in block if provided a block ID' do + # - As an administrator, I can reserve a room from within a block of rooms + block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) + reservation = @hotel.make_reservation('2017-08-04', '2017-08-05', block.id) + + block.rooms.must_include reservation.room + end + it 'raises NoRoomError if no rooms are available' do # Your code should raise an exception when asked to reserve a room that is not available proc { 21.times { @hotel.make_reservation('2017-09-05', '2017-09-08') } }.must_raise NoRoomError end + + it 'raises NoRoomError if all rooms are in a block' do + @hotel.make_block('2017-09-05', '2017-09-08', 19, 20) + + proc { @hotel.make_reservation('2017-09-05', '2017-09-08') + }.must_raise NoRoomError + end end describe '#view_reservations' do @@ -167,9 +182,21 @@ new_block.rooms.wont_include reservation.room end end + + it 'will not overlap multiple blocks' do + # - If a room is set aside in a block, it cannot be included in another block + block2 = @hotel.make_block('2017-08-03', '2017-08-07', 5, 20) + + @block.rooms.each do |room| + block2.rooms.wont_include room + end + end + + it 'raises an error when there are not enough rooms to fill a block' do + proc { block2 = @hotel.make_block('2017-08-03', '2017-08-07', 11, 20) + }.must_raise NoRoomError + end end end -# - If a room is set aside in a block, it is not available for reservation by the general public, nor can it be included in another block # - As an administrator, I can check whether a given block has any rooms available -# - As an administrator, I can reserve a room from within a block of rooms From 8eba6cf1e5a917c8d25d061d0bb36200f6b1fc6f Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 7 Sep 2017 14:43:05 -0700 Subject: [PATCH 055/131] add #includes_dates? --- lib/block.rb | 5 +++++ specs/block_spec.rb | 2 ++ 2 files changed, 7 insertions(+) diff --git a/lib/block.rb b/lib/block.rb index 12dd5907a..83f58eb51 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -14,5 +14,10 @@ def initialize(start_date, end_date, rooms, discount_rate) def create_id format('B%.2d%.2d%.4d', @start_date.month, @start_date.day, rand(9999)) end + + def includes_dates?(checkfirst, checklast) + DateRange.overlap?(checkfirst, checklast, @start_date, @end_date) + end + end end diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 0ccd20c04..58a3d466c 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -15,4 +15,6 @@ @block.id.length.must_equal 9 @block.id[0..4].must_equal 'B0803' end + + #TODO: test includes_dates? end From eac25925070f43ac63bfa99f98e4bd09aa1cbf1b Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 09:33:07 -0700 Subject: [PATCH 056/131] renamed no_room_error to exceptions --- lib/exceptions.rb | 5 +++++ lib/no_room_error.rb | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 lib/exceptions.rb delete mode 100644 lib/no_room_error.rb diff --git a/lib/exceptions.rb b/lib/exceptions.rb new file mode 100644 index 000000000..0a472736a --- /dev/null +++ b/lib/exceptions.rb @@ -0,0 +1,5 @@ +class NoRoomError < StandardError +end + +class InvalidDatesError < StandardError +end diff --git a/lib/no_room_error.rb b/lib/no_room_error.rb deleted file mode 100644 index b446dfebc..000000000 --- a/lib/no_room_error.rb +++ /dev/null @@ -1,2 +0,0 @@ -class NoRoomError < StandardError -end From 4951fddc4010d0b6982cedab94bea77fd89f9a0f Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 09:36:08 -0700 Subject: [PATCH 057/131] streamlined #block and #room --- lib/hotel.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 0c9958a29..38816cd1d 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -3,7 +3,7 @@ module Hotel require_relative 'reservation' require_relative 'room' require_relative 'block' - require_relative 'no_room_error' + require_relative 'exceptions' class Hotel attr_reader :rooms, :reservations, :blocks @@ -83,16 +83,12 @@ def make_block(start_date, end_date, num_rooms, discount) end def room(num) - @rooms.each do |room| - return room if room.number == num - end + @rooms.each { |room| return room if room.number == num } nil end def block(id) - @blocks.each do |block| - return block if block.id == id - end + @blocks.each { |block| return block if block.id == id } nil end end From f04af7ead759ae0b9651b05d80f67b10601cb623 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 09:36:19 -0700 Subject: [PATCH 058/131] add TODO --- specs/hotel_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index fcebe9abc..1d7040d0e 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -200,3 +200,5 @@ end # - As an administrator, I can check whether a given block has any rooms available + +# TODO: lots and lots of edge case testing From 0532edf42b666f762012681ab8bbe2bd68c6d61e Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 10:07:29 -0700 Subject: [PATCH 059/131] refactored #range_to and #range_with to be more DRY --- lib/date_range.rb | 37 +++++++++++++++++++------------------ specs/date_range_spec.rb | 6 +++--- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index 712d05503..01c172484 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -1,27 +1,11 @@ module DateRange require 'date' def self.range_to(start_date, end_date) - start_date = validate(start_date) - end_date = validate(end_date) - raise(ArgumentError, 'Start date must be before end date') unless start_date < end_date - dates = [] - while start_date < end_date - dates << start_date - start_date += 1 - end - dates + find_range(start_date, end_date) end def self.range_with(start_date, end_date) - start_date = validate(start_date) - end_date = validate(end_date) - raise(ArgumentError, 'Start date must be before end date') unless start_date < end_date - dates = [] - while start_date <= end_date - dates << start_date - start_date += 1 - end - dates + find_range(start_date, end_date, :inclusive) end def self.overlap?(first_start, first_end, second_start, second_end) @@ -51,4 +35,21 @@ def self.validate(input) raise(TypeError, "Invalid input #{input.class}-must be Date or String") end end + + def self.invalid_dates_error + raise(InvalidDatesError, 'Start date must be before end date') + end + + def self.find_range(start_date, end_date, flag = false) + start_date = validate(start_date) + end_date = validate(end_date) + invalid_dates_error unless start_date < end_date + dates = [] + while start_date < end_date + dates << start_date + start_date += 1 + end + dates << end_date if flag == :inclusive + dates + end end diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index ae5d8a1ba..2dca86ae4 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -7,10 +7,10 @@ end describe 'self.range_to' do - it 'raises ArgumentError if start date is after end date' do + it 'raises InvalidDatesError if start date is after end date' do proc { DateRange.range_to(@after, @before) - }.must_raise ArgumentError + }.must_raise InvalidDatesError end it 'returns an array of Dates' do @@ -35,7 +35,7 @@ it 'raises ArgumentError if start date is after end date' do proc { DateRange.range_with(@after, @before) - }.must_raise ArgumentError + }.must_raise InvalidDatesError end it 'returns an array of Dates' do From 573dff1ad99b3455304422bb92f83d42be503f5e Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 10:08:00 -0700 Subject: [PATCH 060/131] change RangeError to InvalidDatesError --- lib/hotel.rb | 7 +------ specs/hotel_spec.rb | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 38816cd1d..4433cb0c1 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -25,7 +25,6 @@ def all_rooms end def make_reservation(checkin, checkout, block = false) - #TODO: add block functionality room_num = find_available_rooms(checkin, checkout, block).first if room_num.nil? raise(NoRoomError, "No available rooms for dates #{checkin} - #{checkout}") @@ -35,7 +34,6 @@ def make_reservation(checkin, checkout, block = false) reservation end - def view_reservations(date) date = DateRange.validate(date) reservations = [] @@ -46,14 +44,11 @@ def view_reservations(date) end def find_available_rooms(checkin, checkout, block_id = false) - # TODO: add block functionality - booked_rooms, available_rooms = [], [] if block_id current_block = block(block_id) - raise(RangeError,"Dates (#{checkin}, #{checkout}) do not fall within provided block #{current_block.id}") unless DateRange.overlap?(checkin, checkout, current_block.start_date, current_block.end_date) - + raise(InvalidDatesError,"Dates (#{checkin}, #{checkout}) do not fall within provided block #{current_block.id}") unless DateRange.overlap?(checkin, checkout, current_block.start_date, current_block.end_date) @rooms.each do |room| booked_rooms << room unless current_block.rooms.include? room end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 1d7040d0e..ef1cf6580 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -80,7 +80,7 @@ block = @hotel.make_block('2017-08-03', '2017-08-08', 5, 20) proc { @hotel.find_available_rooms('2017-10-14', '2017-10-15', block.id) - }.must_raise RangeError + }.must_raise InvalidDatesError end end From e45f56ce30ccba1c1ce741e003c43696b70c7f73 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 10:08:15 -0700 Subject: [PATCH 061/131] rubocop style guide tweaks --- lib/block.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/block.rb b/lib/block.rb index 83f58eb51..69e968ee1 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -18,6 +18,5 @@ def create_id def includes_dates?(checkfirst, checklast) DateRange.overlap?(checkfirst, checklast, @start_date, @end_date) end - end end From f70d6e0472fd9f65f8c60b23850ae8a7d7e00631 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 10:10:55 -0700 Subject: [PATCH 062/131] add TODO: implement block discount --- lib/reservation.rb | 1 + specs/reservation_spec.rb | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/reservation.rb b/lib/reservation.rb index 0bad418c0..1cb64ba84 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -10,6 +10,7 @@ def initialize(room, checkin, checkout, hotel, block = false) @dates = DateRange.range_to(@checkin, @checkout) @id = create_id @hotel = hotel + @block = get_total end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index d0683861e..b6744fae5 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -28,6 +28,8 @@ @reservation.total_cost.must_equal 400 (@reservation.total_cost % @reservation.dates.length).must_equal 0 end + + #TODO: @total_cost for blocks end describe '#includes_dates?' do From 626f97a5eb1d1fa4612671a1847bc6d6136dce6d Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 10:13:59 -0700 Subject: [PATCH 063/131] rubocop style guide tweaks --- lib/hotel.rb | 2 +- specs/hotel_spec.rb | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 4433cb0c1..6f99b521e 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -48,7 +48,7 @@ def find_available_rooms(checkin, checkout, block_id = false) if block_id current_block = block(block_id) - raise(InvalidDatesError,"Dates (#{checkin}, #{checkout}) do not fall within provided block #{current_block.id}") unless DateRange.overlap?(checkin, checkout, current_block.start_date, current_block.end_date) + raise(InvalidDatesError, "Dates (#{checkin}, #{checkout}) do not fall within provided block #{current_block.id}") unless DateRange.overlap?(checkin, checkout, current_block.start_date, current_block.end_date) @rooms.each do |room| booked_rooms << room unless current_block.rooms.include? room end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index ef1cf6580..6f2552e7d 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -79,7 +79,8 @@ it 'raises an error if dates do not fall within given block' do block = @hotel.make_block('2017-08-03', '2017-08-08', 5, 20) - proc { @hotel.find_available_rooms('2017-10-14', '2017-10-15', block.id) + proc { + @hotel.find_available_rooms('2017-10-14', '2017-10-15', block.id) }.must_raise InvalidDatesError end end @@ -139,7 +140,8 @@ it 'raises NoRoomError if all rooms are in a block' do @hotel.make_block('2017-09-05', '2017-09-08', 19, 20) - proc { @hotel.make_reservation('2017-09-05', '2017-09-08') + proc { + @hotel.make_reservation('2017-09-05', '2017-09-08') }.must_raise NoRoomError end end @@ -193,7 +195,8 @@ end it 'raises an error when there are not enough rooms to fill a block' do - proc { block2 = @hotel.make_block('2017-08-03', '2017-08-07', 11, 20) + proc { + @hotel.make_block('2017-08-03', '2017-08-07', 11, 20) }.must_raise NoRoomError end end From 9ffeef11674209e568aadf8b3f50ec054d16b07a Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 11:04:43 -0700 Subject: [PATCH 064/131] added comparability for rooms by room number - not sure if this will be necessary? --- lib/room.rb | 5 ++++- specs/room_spec.rb | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/room.rb b/lib/room.rb index e5ad6f9da..c370cc12d 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -1,5 +1,6 @@ module Hotel class Room + include Comparable attr_reader :number, :cost def initialize(number, cost) @@ -7,6 +8,8 @@ def initialize(number, cost) @cost = cost end - # #is_avail?() + def <=>(other) + @number <=> other.number + end end end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index 28011d8c0..015e8e8f6 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -1,17 +1,27 @@ require_relative 'spec_helper' describe 'Room' do + before do + @room = Hotel::Room.new(5, 200) + end describe 'initialize' do it 'can be instantiated' do - Hotel::Room.new(1, 200).must_be_kind_of Hotel::Room + @room.must_be_kind_of Hotel::Room end it 'has a room number' do - Hotel::Room.new(5, 200).number.must_equal 5 + @room.number.must_equal 5 end it 'has a cost' do - Hotel::Room.new(5, 200).cost.must_equal 200 + @room.cost.must_equal 200 + end + + describe 'comparable' do + it 'is equivalent to another room with the same number' do + room2 = Hotel::Room.new(5, 200) + (@room == room2).must_equal true + end end end end From 8b134cc8f3b22abc0c86ed3bc1c589a8af1e5025 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 11:05:20 -0700 Subject: [PATCH 065/131] much-needed refactor for #find_available_rooms --- lib/hotel.rb | 38 ++++++++++++++++++++------------------ specs/hotel_spec.rb | 15 +++++++++++++++ 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 6f99b521e..8ad591207 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -1,3 +1,5 @@ +require 'pry' + module Hotel require_relative 'room' require_relative 'reservation' @@ -44,29 +46,17 @@ def view_reservations(date) end def find_available_rooms(checkin, checkout, block_id = false) - booked_rooms, available_rooms = [], [] - if block_id - current_block = block(block_id) - raise(InvalidDatesError, "Dates (#{checkin}, #{checkout}) do not fall within provided block #{current_block.id}") unless DateRange.overlap?(checkin, checkout, current_block.start_date, current_block.end_date) - @rooms.each do |room| - booked_rooms << room unless current_block.rooms.include? room - end - else # not in block - @blocks.each do |block| - booked_rooms += block.rooms if block.includes_dates?(checkin, checkout) - end + raise(InvalidDatesError, "Dates (#{checkin}, #{checkout}) do not fall within provided block #{block(block_id).id}") unless block(block_id).includes_dates?(checkin, checkout) + rooms = block(block_id).rooms + else + rooms = find_rooms_not_in_blocks(checkin, checkout) end @reservations.each do |reservation| - if !(booked_rooms.include? reservation.room) && reservation.includes_dates?(checkin, checkout) - booked_rooms << reservation.room - end - end - @rooms.each do |room| - available_rooms << room unless booked_rooms.include? room + rooms.delete(reservation.room) if (rooms.include? reservation.room) && reservation.includes_dates?(checkin, checkout) end - available_rooms + rooms end def make_block(start_date, end_date, num_rooms, discount) @@ -86,5 +76,17 @@ def block(id) @blocks.each { |block| return block if block.id == id } nil end + + # private + + def find_rooms_not_in_blocks(start_date, end_date) + rooms = @rooms.dup + @blocks.each do |block| + if block.includes_dates?(start_date, end_date) + rooms.delete_if { |room| block.rooms.include? room } + end + end + rooms + end end end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 6f2552e7d..f7361ffda 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -200,6 +200,21 @@ }.must_raise NoRoomError end end + + describe 'find_rooms_not_in_blocks' do + it 'returns array of rooms' do + rooms = @hotel.find_rooms_not_in_blocks('2017-10-14', '2017-10-18') + rooms.must_be_kind_of Array + end + + it 'returns rooms that are not in block' do + block = @hotel.make_block('2017-10-10', '2017-10-20', 5, 20) + rooms = @hotel.find_rooms_not_in_blocks('2017-10-14', '2017-10-18') + rooms.each do |room| + block.rooms.wont_include room + end + end + end end # - As an administrator, I can check whether a given block has any rooms available From 4c87057b03028d347229569b32aa35367ba6af54 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 11:15:46 -0700 Subject: [PATCH 066/131] removed unnecessary code (Hotel to Reservation, etc) --- lib/date_range.rb | 14 +++----------- lib/hotel.rb | 6 ++++-- lib/reservation.rb | 1 - 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index 01c172484..b96bf28fe 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -25,25 +25,17 @@ def self.overlap?(first_start, first_end, second_start, second_end) false end - # private + private def self.validate(input) return input if input.class == Date - begin - Date.parse(input) - rescue - raise(TypeError, "Invalid input #{input.class}-must be Date or String") - end - end - - def self.invalid_dates_error - raise(InvalidDatesError, 'Start date must be before end date') + Date.parse(input) end def self.find_range(start_date, end_date, flag = false) start_date = validate(start_date) end_date = validate(end_date) - invalid_dates_error unless start_date < end_date + raise(InvalidDatesError, 'Start date must be before end date') unless start_date < end_date dates = [] while start_date < end_date dates << start_date diff --git a/lib/hotel.rb b/lib/hotel.rb index 8ad591207..b6a7f9145 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -31,7 +31,7 @@ def make_reservation(checkin, checkout, block = false) if room_num.nil? raise(NoRoomError, "No available rooms for dates #{checkin} - #{checkout}") end - reservation = Reservation.new(room_num, checkin, checkout, self, block) + reservation = Reservation.new(room_num, checkin, checkout, block) @reservations << reservation reservation end @@ -47,7 +47,9 @@ def view_reservations(date) def find_available_rooms(checkin, checkout, block_id = false) if block_id - raise(InvalidDatesError, "Dates (#{checkin}, #{checkout}) do not fall within provided block #{block(block_id).id}") unless block(block_id).includes_dates?(checkin, checkout) + unless block(block_id).includes_dates?(checkin, checkout) + raise(InvalidDatesError, "Dates (#{checkin}, #{checkout}) do not fall within provided block #{block(block_id).id}") + end rooms = block(block_id).rooms else rooms = find_rooms_not_in_blocks(checkin, checkout) diff --git a/lib/reservation.rb b/lib/reservation.rb index 1cb64ba84..35e6c7a1a 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -9,7 +9,6 @@ def initialize(room, checkin, checkout, hotel, block = false) @checkout = Date.parse(checkout) @dates = DateRange.range_to(@checkin, @checkout) @id = create_id - @hotel = hotel @block = get_total end From 4622f6f11425206f69a173619979629e0ef5b6de Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 11:34:28 -0700 Subject: [PATCH 067/131] formatting --- specs/block_spec.rb | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 58a3d466c..3a10c53bb 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -6,15 +6,19 @@ @block = Hotel::Block.new('2017-08-03', '2017-08-07', 5, 20) end - it 'can be instantiated' do - @block.must_be_kind_of Hotel::Block - end + describe 'initialize' do + it 'can be instantiated' do + @block.must_be_kind_of Hotel::Block + end - it 'has 9-character @id value' do - @block.id.must_be_kind_of String - @block.id.length.must_equal 9 - @block.id[0..4].must_equal 'B0803' + it 'has 9-character @id value' do + @block.id.must_be_kind_of String + @block.id.length.must_equal 9 + @block.id[0..4].must_equal 'B0803' + end end - #TODO: test includes_dates? + describe 'includes_dates?' do + #TODO: test includes_dates? + end end From 14fcd5d15e6bde6ac94ed4ac327efbe3c5d98f69 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 11:34:42 -0700 Subject: [PATCH 068/131] fix broken @block assignment --- lib/reservation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 35e6c7a1a..35269c55f 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -9,7 +9,7 @@ def initialize(room, checkin, checkout, hotel, block = false) @checkout = Date.parse(checkout) @dates = DateRange.range_to(@checkin, @checkout) @id = create_id - @block = + @block = block get_total end From f34830b461d4789c7d38efa8bb7e3d55d157fe12 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 11:35:00 -0700 Subject: [PATCH 069/131] implement #block_availability? method --- lib/hotel.rb | 4 ++ specs/hotel_spec.rb | 95 +++++++++++++++++++++++++++------------------ 2 files changed, 62 insertions(+), 37 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index b6a7f9145..0fcef8b05 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -69,6 +69,10 @@ def make_block(start_date, end_date, num_rooms, discount) block end + def block_availability?(checkin, checkout, block_id) + find_available_rooms(checkin, checkout, block_id) != [] + end + def room(num) @rooms.each { |room| return room if room.number == num } nil diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index f7361ffda..f635e328e 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -160,63 +160,84 @@ end end - describe '#make_block' do + describe 'blocks' do before do @block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) end - # - As an administrator, I can create a block of rooms - it 'returns a new Block object' do - @block.must_be_kind_of Hotel::Block - end + describe '#make_block' do + # - As an administrator, I can create a block of rooms + it 'returns a new Block object' do + @block.must_be_kind_of Hotel::Block + end - it 'adds to @blocks array' do - @hotel.blocks.length.must_equal 1 - end + it 'adds to @blocks array' do + @hotel.blocks.length.must_equal 1 + end - it 'fills block with available rooms only' do - # - The collection of rooms should only include rooms that are available for the given date range - 3.times { @hotel.make_reservation('2017-10-05', '2017-10-07') } - new_block = @hotel.make_block('2017-10-03', '2017-10-07', 10, 20) - reserved = @hotel.view_reservations('2017-10-06') + it 'fills block with available rooms only' do + # - The collection of rooms should only include rooms that are available for the given date range + 3.times { @hotel.make_reservation('2017-10-05', '2017-10-07') } + new_block = @hotel.make_block('2017-10-03', '2017-10-07', 10, 20) + reserved = @hotel.view_reservations('2017-10-06') - reserved.each do |reservation| - new_block.rooms.wont_include reservation.room + reserved.each do |reservation| + new_block.rooms.wont_include reservation.room + end end - end - it 'will not overlap multiple blocks' do - # - If a room is set aside in a block, it cannot be included in another block - block2 = @hotel.make_block('2017-08-03', '2017-08-07', 5, 20) + it 'will not overlap multiple blocks' do + # - If a room is set aside in a block, it cannot be included in another block + block2 = @hotel.make_block('2017-08-03', '2017-08-07', 5, 20) - @block.rooms.each do |room| - block2.rooms.wont_include room + @block.rooms.each do |room| + block2.rooms.wont_include room + end end - end - it 'raises an error when there are not enough rooms to fill a block' do - proc { - @hotel.make_block('2017-08-03', '2017-08-07', 11, 20) - }.must_raise NoRoomError + it 'raises an error when there are not enough rooms to fill a block' do + proc { + @hotel.make_block('2017-08-03', '2017-08-07', 11, 20) + }.must_raise NoRoomError + end end - end - describe 'find_rooms_not_in_blocks' do - it 'returns array of rooms' do - rooms = @hotel.find_rooms_not_in_blocks('2017-10-14', '2017-10-18') - rooms.must_be_kind_of Array + describe 'find_rooms_not_in_blocks' do + it 'returns array of rooms' do + rooms = @hotel.find_rooms_not_in_blocks('2017-10-14', '2017-10-18') + rooms.must_be_kind_of Array + end + + it 'returns rooms that are not in block' do + rooms = @hotel.find_rooms_not_in_blocks('2017-08-05', '2017-08-07') + rooms.each do |room| + @block.rooms.wont_include room + end + end end - it 'returns rooms that are not in block' do - block = @hotel.make_block('2017-10-10', '2017-10-20', 5, 20) - rooms = @hotel.find_rooms_not_in_blocks('2017-10-14', '2017-10-18') - rooms.each do |room| - block.rooms.wont_include room + describe 'block_availability?' do + it 'returns true if there are unbooked rooms within block for given dates' do + check = @hotel.block_availability?('2017-08-05', '2017-08-07', @block.id) + check.must_equal true + end + + it 'returns false if there are no unbooked rooms within block for given dates' do + 10.times { @hotel.make_reservation('2017-08-03', '2017-08-07', @block.id) } + check = @hotel.block_availability?('2017-08-05', '2017-08-07', @block.id) + check.must_equal false + end + + it 'raises an exception if the dates do not fall within the block' do + proc { + @hotel.block_availability?('2017-10-14','2017-10-15', @block.id) + }.must_raise InvalidDatesError end end end end -# - As an administrator, I can check whether a given block has any rooms available # TODO: lots and lots of edge case testing + +# - As an administrator, I can check whether a given block has any rooms available From 41bdcc24138428f53afdd7f96a9d414c9c90e0d1 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 11:39:13 -0700 Subject: [PATCH 070/131] removed room comparability, wasnt necessary --- lib/room.rb | 5 ----- specs/room_spec.rb | 7 ------- 2 files changed, 12 deletions(-) diff --git a/lib/room.rb b/lib/room.rb index c370cc12d..297cb49ef 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -1,15 +1,10 @@ module Hotel class Room - include Comparable attr_reader :number, :cost def initialize(number, cost) @number = number @cost = cost end - - def <=>(other) - @number <=> other.number - end end end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index 015e8e8f6..7cbfd962f 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -16,12 +16,5 @@ it 'has a cost' do @room.cost.must_equal 200 end - - describe 'comparable' do - it 'is equivalent to another room with the same number' do - room2 = Hotel::Room.new(5, 200) - (@room == room2).must_equal true - end - end end end From 543d4b23a9ca123b5eb82f1d6100e5c9c075b4df Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 11:42:17 -0700 Subject: [PATCH 071/131] removed unnecessary private methods --- lib/date_range.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index b96bf28fe..88967aced 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -25,8 +25,6 @@ def self.overlap?(first_start, first_end, second_start, second_end) false end - private - def self.validate(input) return input if input.class == Date Date.parse(input) From 328ed624df469b360eeb27fd47bf0a5b33ad7709 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 11:42:46 -0700 Subject: [PATCH 072/131] removed unnecessary hotel parameter --- lib/reservation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 35269c55f..51c440ce9 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -3,7 +3,7 @@ class Reservation require_relative 'date_range' attr_reader :total_cost, :dates, :checkin, :checkout, :id, :hotel, :room - def initialize(room, checkin, checkout, hotel, block = false) + def initialize(room, checkin, checkout, block = false) @room = room @checkin = Date.parse(checkin) @checkout = Date.parse(checkout) From d5fdd642824d948572abf96e65d1896ef553bd09 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 11:43:03 -0700 Subject: [PATCH 073/131] comment format --- specs/hotel_spec.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index f635e328e..c428de3ef 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -217,6 +217,7 @@ end describe 'block_availability?' do + # - As an administrator, I can check whether a given block has any rooms available it 'returns true if there are unbooked rooms within block for given dates' do check = @hotel.block_availability?('2017-08-05', '2017-08-07', @block.id) check.must_equal true @@ -237,7 +238,4 @@ end end - # TODO: lots and lots of edge case testing - -# - As an administrator, I can check whether a given block has any rooms available From 84a61ce66881303feff504cfaffb13a2a55e7ca5 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 12:28:07 -0700 Subject: [PATCH 074/131] validate input in initialize, remove useless #all_rooms method --- lib/hotel.rb | 11 +++++------ specs/hotel_spec.rb | 45 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 0fcef8b05..b5d8636fd 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -13,6 +13,11 @@ class Hotel def initialize(num_rooms) @rooms = [] + + unless num_rooms.class == Integer + raise(ArgumentError, "Number of rooms parameter must be Integer: #{num_rooms}") + end + num_rooms.times do |i| @rooms << Room.new(i + 1, ROOM_COST) end @@ -20,12 +25,6 @@ def initialize(num_rooms) @blocks = [] end - def all_rooms - list = [] - @rooms.each { |room| list << room } - list - end - def make_reservation(checkin, checkout, block = false) room_num = find_available_rooms(checkin, checkout, block).first if room_num.nil? diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index c428de3ef..b09577b6f 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -8,27 +8,64 @@ describe '#initialize' do it 'Can be instantiated' do @hotel.must_be_kind_of Hotel::Hotel + @hotel.reservations.must_equal [] + @hotel.blocks.must_equal [] end it 'Creates an array of rooms' do @hotel.rooms.must_be_kind_of Array @hotel.rooms.length.must_equal 20 + @hotel.rooms.each do |room| + room.must_be_kind_of Hotel::Room + end end - it 'Creates array of reservations' do - @hotel.reservations.must_equal [] + it 'Can be initialized with 0 rooms' do + hotel = Hotel::Hotel.new(0) + hotel.rooms.must_equal [] + end + + it 'Can be initialized with 1 room' do + hotel = Hotel::Hotel.new(1) + hotel.rooms.length.must_equal 1 + hotel.rooms[0].must_be_kind_of Hotel::Room + end + + it 'raises ArgumentError if passed anything but an Integer' do + proc { + Hotel::Hotel.new('hi') + }.must_raise ArgumentError + + proc { + Hotel::Hotel.new(nil) + }.must_raise ArgumentError + + proc { + Hotel::Hotel.new(4.0) + }.must_raise ArgumentError end end - describe '#all_rooms' do + describe 'rooms' do # As an administrator, I can access the list of all of the rooms in the hotel it 'Returns an array of all room numbers' do - all_rooms = @hotel.all_rooms + all_rooms = @hotel.rooms all_rooms.must_be_kind_of Array all_rooms.each do |room| room.must_be_kind_of Hotel::Room end end + + it 'returns an empty array if there are no rooms' do + all_rooms = Hotel::Hotel.new(0).rooms + all_rooms.must_equal [] + end + + it 'returns a single-element array if there is 1 room' do + all_rooms = Hotel::Hotel.new(1).rooms + all_rooms.length.must_equal 1 + all_rooms[0].must_be_kind_of Hotel::Room + end end describe '#room' do From e70a665560fc1b7d1a29acc90c7ac9657f098cdd Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 13:28:31 -0700 Subject: [PATCH 075/131] add validate_order method --- lib/date_range.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index 88967aced..49c332b93 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -25,6 +25,12 @@ def self.overlap?(first_start, first_end, second_start, second_end) false end + def self.validate_order(first, second) + unless first < second + raise(InvalidDatesError, 'Start date must be at least 1 day before end date') + end + end + def self.validate(input) return input if input.class == Date Date.parse(input) @@ -33,7 +39,7 @@ def self.validate(input) def self.find_range(start_date, end_date, flag = false) start_date = validate(start_date) end_date = validate(end_date) - raise(InvalidDatesError, 'Start date must be before end date') unless start_date < end_date + validate_order(start_date, end_date) dates = [] while start_date < end_date dates << start_date From 8cc9530f9e0b62554d6d815286444eb7b5ac816e Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 13:29:15 -0700 Subject: [PATCH 076/131] validate input for #find_available_rooms, reorder methods --- lib/hotel.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index b5d8636fd..a09144eea 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -35,6 +35,14 @@ def make_reservation(checkin, checkout, block = false) reservation end + def make_block(start_date, end_date, num_rooms, discount) + rooms = find_available_rooms(start_date, end_date)[0...num_rooms] + raise(NoRoomError, "Not enough available rooms for amount #{num_rooms}") if rooms.length < num_rooms + block = Block.new(start_date, end_date, rooms, discount) + @blocks << block + block + end + def view_reservations(date) date = DateRange.validate(date) reservations = [] @@ -45,6 +53,7 @@ def view_reservations(date) end def find_available_rooms(checkin, checkout, block_id = false) + DateRange.validate_order(checkin, checkout) if block_id unless block(block_id).includes_dates?(checkin, checkout) raise(InvalidDatesError, "Dates (#{checkin}, #{checkout}) do not fall within provided block #{block(block_id).id}") @@ -60,14 +69,6 @@ def find_available_rooms(checkin, checkout, block_id = false) rooms end - def make_block(start_date, end_date, num_rooms, discount) - rooms = find_available_rooms(start_date, end_date)[0...num_rooms] - raise(NoRoomError, "Not enough available rooms for amount #{num_rooms}") if rooms.length < num_rooms - block = Block.new(start_date, end_date, rooms, discount) - @blocks << block - block - end - def block_availability?(checkin, checkout, block_id) find_available_rooms(checkin, checkout, block_id) != [] end From c3ea60ff0dc5bf3a91cba95c90b853e6bd858191 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 13:41:58 -0700 Subject: [PATCH 077/131] removed unnecessary Reservation ID --- lib/reservation.rb | 8 ++++---- specs/reservation_spec.rb | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 51c440ce9..703e882af 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -8,7 +8,7 @@ def initialize(room, checkin, checkout, block = false) @checkin = Date.parse(checkin) @checkout = Date.parse(checkout) @dates = DateRange.range_to(@checkin, @checkout) - @id = create_id + # @id = create_id @block = block get_total end @@ -24,8 +24,8 @@ def includes_dates?(checkfirst, checklast) private - def create_id - format('R%.2d%.2d%.4d', @checkin.month, @checkin.day, rand(9999)) - end + # def create_id + # format('R%.2d%.2d%.4d', @checkin.month, @checkin.day, rand(9999)) + # end end end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index b6744fae5..0ea48cada 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -17,11 +17,11 @@ @reservation.dates.first.must_be_kind_of Date end - it 'has 9-character @id value' do - @reservation.id.must_be_kind_of String - @reservation.id.length.must_equal 9 - @reservation.id[0..4].must_equal 'R0905' - end + # it 'has 9-character @id value' do + # @reservation.id.must_be_kind_of String + # @reservation.id.length.must_equal 9 + # @reservation.id[0..4].must_equal 'R0905' + # end it 'has @total_cost value, which is rate * num of nights' do # As an administrator, I can get the total cost for a given reservation From c89fc53c2e5074b84fe689ecbc51e3c854824866 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 13:45:13 -0700 Subject: [PATCH 078/131] add InvalidBlockError to #find_available_rooms --- lib/exceptions.rb | 3 + lib/hotel.rb | 8 +- specs/hotel_spec.rb | 269 ++++++++++++++++++++++++++------------------ 3 files changed, 167 insertions(+), 113 deletions(-) diff --git a/lib/exceptions.rb b/lib/exceptions.rb index 0a472736a..a2fe8e79e 100644 --- a/lib/exceptions.rb +++ b/lib/exceptions.rb @@ -3,3 +3,6 @@ class NoRoomError < StandardError class InvalidDatesError < StandardError end + +class InvalidBlockError < StandardError +end diff --git a/lib/hotel.rb b/lib/hotel.rb index a09144eea..45791d69b 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -55,6 +55,9 @@ def view_reservations(date) def find_available_rooms(checkin, checkout, block_id = false) DateRange.validate_order(checkin, checkout) if block_id + unless block_exists?(block_id) + raise(InvalidBlockError, "No such block: #{block_id}") + end unless block(block_id).includes_dates?(checkin, checkout) raise(InvalidDatesError, "Dates (#{checkin}, #{checkout}) do not fall within provided block #{block(block_id).id}") end @@ -84,7 +87,6 @@ def block(id) end # private - def find_rooms_not_in_blocks(start_date, end_date) rooms = @rooms.dup @blocks.each do |block| @@ -94,5 +96,9 @@ def find_rooms_not_in_blocks(start_date, end_date) end rooms end + + def block_exists?(block_id) + block(block_id) != nil + end end end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index b09577b6f..b7c7e2d9e 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -47,152 +47,184 @@ end describe 'rooms' do - # As an administrator, I can access the list of all of the rooms in the hotel - it 'Returns an array of all room numbers' do - all_rooms = @hotel.rooms - all_rooms.must_be_kind_of Array - all_rooms.each do |room| - room.must_be_kind_of Hotel::Room + describe 'rooms' do + # As an administrator, I can access the list of all of the rooms in the hotel + it 'Returns an array of all room numbers' do + all_rooms = @hotel.rooms + all_rooms.must_be_kind_of Array + all_rooms.each do |room| + room.must_be_kind_of Hotel::Room + end end - end - it 'returns an empty array if there are no rooms' do - all_rooms = Hotel::Hotel.new(0).rooms - all_rooms.must_equal [] - end + it 'returns an empty array if there are no rooms' do + all_rooms = Hotel::Hotel.new(0).rooms + all_rooms.must_equal [] + end - it 'returns a single-element array if there is 1 room' do - all_rooms = Hotel::Hotel.new(1).rooms - all_rooms.length.must_equal 1 - all_rooms[0].must_be_kind_of Hotel::Room + it 'returns a single-element array if there is 1 room' do + all_rooms = Hotel::Hotel.new(1).rooms + all_rooms.length.must_equal 1 + all_rooms[0].must_be_kind_of Hotel::Room + end end - end - describe '#room' do - it 'returns the Room with corresponding number' do - room = @hotel.room(4) - room.must_be_kind_of Hotel::Room - room.number.must_equal 4 - end + describe '#room' do + it 'returns the Room with corresponding number' do + room = @hotel.room(4) + room.must_be_kind_of Hotel::Room + room.number.must_equal 4 + end - it 'returns nil if room is not found' do - @hotel.room(1000).must_equal nil + it 'returns nil if room is not found' do + assert_nil @hotel.room(1000) + assert_nil @hotel.room('hi') + assert_nil @hotel.room(5.5) + assert_nil @hotel.room(nil) + assert_nil @hotel.room(true) + assert_nil @hotel.room([4,0]) + end end - end - describe 'find_available_rooms' do - # As an administrator, I can view a list of rooms that are not reserved for a given date range - it 'returns an array of rooms' do - rooms = @hotel.find_available_rooms('2017-09-05', '2017-09-09') - rooms.must_be_kind_of Array - end + describe 'find_available_rooms' do + # As an administrator, I can view a list of rooms that are not reserved for a given date range + it 'returns an array of rooms' do + rooms = @hotel.find_available_rooms('2017-09-05', '2017-09-09') + rooms.must_be_kind_of Array + rooms.each do |room| + room.must_be_kind_of Hotel::Room + end + end - it 'returns only available rooms' do - @hotel.make_reservation('2017-10-14', '2017-10-18') - @hotel.make_reservation('2017-10-14', '2017-10-18') - @hotel.make_reservation('2018-10-14', '2018-10-18') - rooms = @hotel.find_available_rooms('2017-10-14', '2017-10-18') + it 'returns only available rooms' do + @hotel.make_reservation('2017-10-14', '2017-10-18') + @hotel.make_reservation('2017-10-14', '2017-10-18') + @hotel.make_reservation('2018-10-14', '2018-10-18') + rooms = @hotel.find_available_rooms('2017-10-14', '2017-10-18') + rooms2 = @hotel.find_available_rooms('2017-11-14', '2017-11-18') - rooms.length.must_equal 18 - end + rooms.length.must_equal 18 + rooms2.length.must_equal 20 + end - it 'will not return rooms in a block' do - # skip - @hotel.make_reservation('2017-10-14', '2017-10-18') - @hotel.make_block('2017-10-10', '2017-10-16', 5, 20) - rooms = @hotel.find_available_rooms('2017-10-14','2017-10-15') + it 'will not return rooms in a block' do + @hotel.make_reservation('2017-10-14', '2017-10-18') + @hotel.make_block('2017-10-10', '2017-10-16', 5, 20) + @hotel.make_block('2017-11-10', '2017-11-16', 5, 20) + rooms = @hotel.find_available_rooms('2017-10-14','2017-10-15') - rooms.length.must_equal 14 - end + rooms.length.must_equal 14 + end - it 'will return rooms in a block when provided block ID' do - # skip - block = @hotel.make_block('2017-10-10', '2017-10-16', 5, 20) - rooms = @hotel.find_available_rooms('2017-10-14','2017-10-15', block.id) + it 'will return rooms in a block when provided block ID' do + block = @hotel.make_block('2017-10-10', '2017-10-16', 5, 20) + rooms = @hotel.find_available_rooms('2017-10-14','2017-10-15', block.id) - rooms.length.must_equal 5 - end + rooms.length.must_equal 5 + end - it 'raises an error if dates do not fall within given block' do - block = @hotel.make_block('2017-08-03', '2017-08-08', 5, 20) + it 'raises an error if block is not found' do + proc { + @hotel.find_available_rooms('2017-10-14','2017-10-15', 'B10141991') + }.must_raise InvalidBlockError - proc { - @hotel.find_available_rooms('2017-10-14', '2017-10-15', block.id) - }.must_raise InvalidDatesError + end + + it 'raises an error if dates do not fall within given block' do + block = @hotel.make_block('2017-08-03', '2017-08-08', 5, 20) + + proc { + @hotel.find_available_rooms('2017-10-14', '2017-10-15', block.id) + }.must_raise InvalidDatesError + end + + it 'raises an error if dates are out of order' do + proc { + @hotel.find_available_rooms('2017-08-23', '2017-08-08') + }.must_raise InvalidDatesError + end + + it 'raises an error if dates do not span at least 1 night' do + proc { + @hotel.find_available_rooms('2017-08-08', '2017-08-08') + }.must_raise InvalidDatesError + end end end - describe '#make_reservation' do - before do - @reservation1 = @hotel.make_reservation('2017-09-05', '2017-09-08') - end - it 'creates a reservation and adds it to the @reservations array' do - # As an administrator, I can reserve a room for a given date range - @reservation1.must_be_kind_of Hotel::Reservation - @reservation1.checkout.strftime.must_equal '2017-09-08' - end + describe 'reservations' do + describe '#make_reservation' do + before do + @reservation1 = @hotel.make_reservation('2017-09-05', '2017-09-08') + end + it 'creates a reservation and adds it to the @reservations array' do + # As an administrator, I can reserve a room for a given date range + @reservation1.must_be_kind_of Hotel::Reservation + @reservation1.checkout.strftime.must_equal '2017-09-08' + end - it 'will reserve the first available room' do - # As an administrator, I can reserve an available room for a given date range - reservation2 = @hotel.make_reservation('2017-09-05', '2017-09-08') - @reservation1.room.wont_equal reservation2.room - end + it 'will reserve the first available room' do + # As an administrator, I can reserve an available room for a given date range + reservation2 = @hotel.make_reservation('2017-09-05', '2017-09-08') + @reservation1.room.wont_equal reservation2.room + end - it 'will book a room again after a reservation ends' do - reservation2 = @hotel.make_reservation('2018-09-05', '2018-09-08') + it 'will book a room again after a reservation ends' do + reservation2 = @hotel.make_reservation('2018-09-05', '2018-09-08') - @reservation1.room.must_equal reservation2.room - end + @reservation1.room.must_equal reservation2.room + end - it 'can book two consecutive reservations to the same room' do - # A reservation is allowed start on the same day that another reservation for the same room ends - reservation2 = @hotel.make_reservation('2017-09-08', '2017-09-11') + it 'can book two consecutive reservations to the same room' do + # A reservation is allowed start on the same day that another reservation for the same room ends + reservation2 = @hotel.make_reservation('2017-09-08', '2017-09-11') - @reservation1.room.must_equal reservation2.room - end + @reservation1.room.must_equal reservation2.room + end - it 'will not book a room that is part of a block' do - # - If a room is set aside in a block, it is not available for reservation by the general public - block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) - reservation = @hotel.make_reservation('2017-08-04', '2017-08-05') + it 'will not book a room that is part of a block' do + # - If a room is set aside in a block, it is not available for reservation by the general public + block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) + reservation = @hotel.make_reservation('2017-08-04', '2017-08-05') - block.rooms.wont_include reservation.room - end + block.rooms.wont_include reservation.room + end - it 'will book room in block if provided a block ID' do - # - As an administrator, I can reserve a room from within a block of rooms - block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) - reservation = @hotel.make_reservation('2017-08-04', '2017-08-05', block.id) + it 'will book room in block if provided a block ID' do + # - As an administrator, I can reserve a room from within a block of rooms + block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) + reservation = @hotel.make_reservation('2017-08-04', '2017-08-05', block.id) - block.rooms.must_include reservation.room - end + block.rooms.must_include reservation.room + end - it 'raises NoRoomError if no rooms are available' do - # Your code should raise an exception when asked to reserve a room that is not available - proc { - 21.times { @hotel.make_reservation('2017-09-05', '2017-09-08') } - }.must_raise NoRoomError - end + it 'raises NoRoomError if no rooms are available' do + # Your code should raise an exception when asked to reserve a room that is not available + proc { + 21.times { @hotel.make_reservation('2017-09-05', '2017-09-08') } + }.must_raise NoRoomError + end - it 'raises NoRoomError if all rooms are in a block' do - @hotel.make_block('2017-09-05', '2017-09-08', 19, 20) + it 'raises NoRoomError if all rooms are in a block' do + @hotel.make_block('2017-09-05', '2017-09-08', 19, 20) - proc { - @hotel.make_reservation('2017-09-05', '2017-09-08') - }.must_raise NoRoomError + proc { + @hotel.make_reservation('2017-09-05', '2017-09-08') + }.must_raise NoRoomError + end end - end - describe '#view_reservations' do - # As an administrator, I can access the list of reservations for a specific date - it 'returns an array of Reservations' do - @hotel.make_reservation('2017-10-14', '2017-10-18') - reservations = @hotel.view_reservations('2017-10-14') + describe '#view_reservations' do + # As an administrator, I can access the list of reservations for a specific date + it 'returns an array of Reservations' do + @hotel.make_reservation('2017-10-14', '2017-10-18') + reservations = @hotel.view_reservations('2017-10-14') - reservations.must_be_kind_of Array - reservations.length.must_equal 1 - reservations.each do |reservation| - reservation.must_be_kind_of Hotel::Reservation + reservations.must_be_kind_of Array + reservations.length.must_equal 1 + reservations.each do |reservation| + reservation.must_be_kind_of Hotel::Reservation + end end end end @@ -272,6 +304,19 @@ }.must_raise InvalidDatesError end end + + describe 'block_exists?' do + it 'returns true if block w/ given ID exists' do + @hotel.block_exists?(@block.id).must_equal true + end + + it 'returns false if block w/ given ID does not exist' do + @hotel.block_exists?('B09051234').must_equal false + @hotel.block_exists?(2).must_equal false + @hotel.block_exists?(nil).must_equal false + @hotel.block_exists?('hello').must_equal false + end + end end end From 20c543e50e9ba53c7a2d42a456801f3141ff1289 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 14:21:03 -0700 Subject: [PATCH 079/131] #validate_order will raise exception if given invalid input --- lib/date_range.rb | 11 +++++++++-- specs/date_range_spec.rb | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index 49c332b93..51a73d249 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -26,14 +26,21 @@ def self.overlap?(first_start, first_end, second_start, second_end) end def self.validate_order(first, second) + first = validate(first) + second = validate(second) unless first < second raise(InvalidDatesError, 'Start date must be at least 1 day before end date') end end def self.validate(input) - return input if input.class == Date - Date.parse(input) + if input.class == Date + return input + elsif input.class == String + return Date.parse(input) + else + raise(InvalidDatesError, "Input #{input.class} cannot be converted into Date") + end end def self.find_range(start_date, end_date, flag = false) diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index 2dca86ae4..aeb940b20 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -92,7 +92,7 @@ it 'raises an exception if input is neither Date or String' do proc { DateRange.validate(2017_10_14) - }.must_raise TypeError + }.must_raise InvalidDatesError end end end From 0021d7707c2ee5b1b0312184b3496a1f3f59e4c8 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 14:23:21 -0700 Subject: [PATCH 080/131] changed InvalidDatesError to ArgumentError to align with Date class --- lib/date_range.rb | 2 +- specs/date_range_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index 51a73d249..d06ebee35 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -39,7 +39,7 @@ def self.validate(input) elsif input.class == String return Date.parse(input) else - raise(InvalidDatesError, "Input #{input.class} cannot be converted into Date") + raise(ArgumentError, "Input #{input.class} cannot be converted into Date") end end diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index aeb940b20..4515f4b0f 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -92,7 +92,7 @@ it 'raises an exception if input is neither Date or String' do proc { DateRange.validate(2017_10_14) - }.must_raise InvalidDatesError + }.must_raise ArgumentError end end end From 37ce94ce83b87e529daccef524563451e08ee5aa Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 14:31:22 -0700 Subject: [PATCH 081/131] edge testing for #find_available_rooms --- specs/hotel_spec.rb | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index b7c7e2d9e..10c134c35 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -101,10 +101,14 @@ @hotel.make_reservation('2017-10-14', '2017-10-18') @hotel.make_reservation('2018-10-14', '2018-10-18') rooms = @hotel.find_available_rooms('2017-10-14', '2017-10-18') - rooms2 = @hotel.find_available_rooms('2017-11-14', '2017-11-18') rooms.length.must_equal 18 - rooms2.length.must_equal 20 + end + + it 'returns an empty array if no rooms are available' do + 20.times {@hotel.make_reservation('2017-10-14', '2017-10-18')} + rooms = @hotel.find_available_rooms('2017-10-14', '2017-10-18') + rooms.must_equal [] end it 'will not return rooms in a block' do @@ -116,6 +120,13 @@ rooms.length.must_equal 14 end + it 'returns an empty array if all rooms are in a block' do + @hotel.make_block('2017-10-10', '2017-10-16', 20, 20) + rooms = @hotel.find_available_rooms('2017-10-14','2017-10-15') + + rooms.must_equal [] + end + it 'will return rooms in a block when provided block ID' do block = @hotel.make_block('2017-10-10', '2017-10-16', 5, 20) rooms = @hotel.find_available_rooms('2017-10-14','2017-10-15', block.id) @@ -123,6 +134,16 @@ rooms.length.must_equal 5 end + it 'raises an error if passed invalid dates' do + proc { + @hotel.find_available_rooms(1,2) + }.must_raise ArgumentError + + proc { + @hotel.find_available_rooms('tomorrow','next friday') + }.must_raise ArgumentError + end + it 'raises an error if block is not found' do proc { @hotel.find_available_rooms('2017-10-14','2017-10-15', 'B10141991') From 113069bb0a73834c252dcef2ca6c099592be10d2 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 14:38:19 -0700 Subject: [PATCH 082/131] rename InvalidBlockError to NoBlockError --- lib/exceptions.rb | 2 +- lib/hotel.rb | 2 +- specs/hotel_spec.rb | 32 +++++++++++++++++++++++++------- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/lib/exceptions.rb b/lib/exceptions.rb index a2fe8e79e..5f3c8e733 100644 --- a/lib/exceptions.rb +++ b/lib/exceptions.rb @@ -4,5 +4,5 @@ class NoRoomError < StandardError class InvalidDatesError < StandardError end -class InvalidBlockError < StandardError +class NoBlockError < StandardError end diff --git a/lib/hotel.rb b/lib/hotel.rb index 45791d69b..96fc7d022 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -56,7 +56,7 @@ def find_available_rooms(checkin, checkout, block_id = false) DateRange.validate_order(checkin, checkout) if block_id unless block_exists?(block_id) - raise(InvalidBlockError, "No such block: #{block_id}") + raise(NoBlockError, "No such block: #{block_id}") end unless block(block_id).includes_dates?(checkin, checkout) raise(InvalidDatesError, "Dates (#{checkin}, #{checkout}) do not fall within provided block #{block(block_id).id}") diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 10c134c35..fde3d0783 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -147,7 +147,7 @@ it 'raises an error if block is not found' do proc { @hotel.find_available_rooms('2017-10-14','2017-10-15', 'B10141991') - }.must_raise InvalidBlockError + }.must_raise NoBlockError end @@ -176,31 +176,31 @@ describe 'reservations' do describe '#make_reservation' do before do - @reservation1 = @hotel.make_reservation('2017-09-05', '2017-09-08') + @reservation = @hotel.make_reservation('2017-09-05', '2017-09-08') end it 'creates a reservation and adds it to the @reservations array' do # As an administrator, I can reserve a room for a given date range - @reservation1.must_be_kind_of Hotel::Reservation - @reservation1.checkout.strftime.must_equal '2017-09-08' + @reservation.must_be_kind_of Hotel::Reservation + @reservation.checkout.strftime.must_equal '2017-09-08' end it 'will reserve the first available room' do # As an administrator, I can reserve an available room for a given date range reservation2 = @hotel.make_reservation('2017-09-05', '2017-09-08') - @reservation1.room.wont_equal reservation2.room + @reservation.room.wont_equal reservation2.room end it 'will book a room again after a reservation ends' do reservation2 = @hotel.make_reservation('2018-09-05', '2018-09-08') - @reservation1.room.must_equal reservation2.room + @reservation.room.must_equal reservation2.room end it 'can book two consecutive reservations to the same room' do # A reservation is allowed start on the same day that another reservation for the same room ends reservation2 = @hotel.make_reservation('2017-09-08', '2017-09-11') - @reservation1.room.must_equal reservation2.room + @reservation.room.must_equal reservation2.room end it 'will not book a room that is part of a block' do @@ -219,6 +219,24 @@ block.rooms.must_include reservation.room end + it 'raises ArgumentError if passed invalid dates' do + proc { + @hotel.make_reservation('cat','bug') + }.must_raise ArgumentError + end + + it 'raises InvalidDatesError if dates are out of order' do + proc { + reservation = @hotel.make_reservation('2017-09-08', '2017-09-05') + }.must_raise InvalidDatesError + end + + it 'raises NoBlockError if passed invalid block' do + proc { + @hotel.make_reservation('2017-09-05', '2017-09-08', 'catbug') + }.must_raise NoBlockError + end + it 'raises NoRoomError if no rooms are available' do # Your code should raise an exception when asked to reserve a room that is not available proc { From 3876d7701113ea5fc54c80b377d803d4fb5d1001 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 14:42:58 -0700 Subject: [PATCH 083/131] edge tests for #make_reservation' --- specs/hotel_spec.rb | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index fde3d0783..959351823 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -47,7 +47,7 @@ end describe 'rooms' do - describe 'rooms' do + describe '@rooms' do # As an administrator, I can access the list of all of the rooms in the hotel it 'Returns an array of all room numbers' do all_rooms = @hotel.rooms @@ -86,7 +86,7 @@ end end - describe 'find_available_rooms' do + describe '#find_available_rooms' do # As an administrator, I can view a list of rooms that are not reserved for a given date range it 'returns an array of rooms' do rooms = @hotel.find_available_rooms('2017-09-05', '2017-09-09') @@ -142,6 +142,10 @@ proc { @hotel.find_available_rooms('tomorrow','next friday') }.must_raise ArgumentError + + proc { + @hotel.find_available_rooms('2017-02-30','2017-04-98') + }.must_raise ArgumentError end it 'raises an error if block is not found' do @@ -223,6 +227,14 @@ proc { @hotel.make_reservation('cat','bug') }.must_raise ArgumentError + + proc { + @hotel.make_reservation(1,2) + }.must_raise ArgumentError + + proc { + @hotel.make_reservation('2019-02-40','2019-02-45') + }.must_raise ArgumentError end it 'raises InvalidDatesError if dates are out of order' do @@ -231,7 +243,7 @@ }.must_raise InvalidDatesError end - it 'raises NoBlockError if passed invalid block' do + it 'raises NoBlockError if passed nonexistent block' do proc { @hotel.make_reservation('2017-09-05', '2017-09-08', 'catbug') }.must_raise NoBlockError @@ -310,7 +322,7 @@ end end - describe 'find_rooms_not_in_blocks' do + describe '#find_rooms_not_in_blocks' do it 'returns array of rooms' do rooms = @hotel.find_rooms_not_in_blocks('2017-10-14', '2017-10-18') rooms.must_be_kind_of Array @@ -324,7 +336,7 @@ end end - describe 'block_availability?' do + describe '#block_availability?' do # - As an administrator, I can check whether a given block has any rooms available it 'returns true if there are unbooked rooms within block for given dates' do check = @hotel.block_availability?('2017-08-05', '2017-08-07', @block.id) @@ -344,7 +356,7 @@ end end - describe 'block_exists?' do + describe '#block_exists?' do it 'returns true if block w/ given ID exists' do @hotel.block_exists?(@block.id).must_equal true end From 94abb1ee03f16f6ca1bbba45819bcf305bc17cda Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 15:10:57 -0700 Subject: [PATCH 084/131] reformat comments / add TODO --- specs/reservation_spec.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 0ea48cada..dc266bb6e 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -17,19 +17,20 @@ @reservation.dates.first.must_be_kind_of Date end - # it 'has 9-character @id value' do - # @reservation.id.must_be_kind_of String - # @reservation.id.length.must_equal 9 - # @reservation.id[0..4].must_equal 'R0905' - # end - it 'has @total_cost value, which is rate * num of nights' do # As an administrator, I can get the total cost for a given reservation @reservation.total_cost.must_equal 400 (@reservation.total_cost % @reservation.dates.length).must_equal 0 end - #TODO: @total_cost for blocks + # TODO: various date formats 'August 31st, 2017' + # TODO: @total_cost discount for blocks + + # it 'has 9-character @id value' do + # @reservation.id.must_be_kind_of String + # @reservation.id.length.must_equal 9 + # @reservation.id[0..4].must_equal 'R0905' + # end end describe '#includes_dates?' do From ba9026af6a52880a067ce2d16707bad8c6895810 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 15:11:10 -0700 Subject: [PATCH 085/131] edge testing for reservations --- specs/hotel_spec.rb | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 959351823..4697085e5 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -182,6 +182,7 @@ before do @reservation = @hotel.make_reservation('2017-09-05', '2017-09-08') end + it 'creates a reservation and adds it to the @reservations array' do # As an administrator, I can reserve a room for a given date range @reservation.must_be_kind_of Hotel::Reservation @@ -277,6 +278,45 @@ reservation.must_be_kind_of Hotel::Reservation end end + + it 'returns all Reservations' do + 10.times { @hotel.make_reservation('2017-10-14', '2017-10-18') } + reservations = @hotel.view_reservations('2017-10-14') + + reservations.length.must_equal 10 + reservations.each do |reservation| + reservation.must_be_kind_of Hotel::Reservation + end + end + + it 'returns Reservations inside and outside of blocks' do + block = @hotel.make_block('2017-08-03', '2017-08-10', 10, 25) + @hotel.make_reservation('2017-08-03', '2017-08-10', block.id) + @hotel.make_reservation('2017-08-03', '2017-08-10') + reservations = @hotel.view_reservations('2017-08-06') + + reservations.length.must_equal 2 + end + + it 'returns an empty array when there are no reservations' do + @hotel.view_reservations('2000-01-01').must_equal [] + end + + it 'wont display rooms in blocks that are not reserved' do + @block = @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) + + @hotel.view_reservations('2017-08-06').must_equal [] + end + + it 'raises an ArgumentError when given invalid dates' do + proc { + @hotel.view_reservations('coffee') + }.must_raise ArgumentError + + proc { + @hotel.view_reservations('9999-99-99') + }.must_raise ArgumentError + end end end From 8af2eb4d5c90d6acfe9f4c15c2cd6dc2d3dc5680 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 15:20:11 -0700 Subject: [PATCH 086/131] add InvalidDiscountError --- lib/exceptions.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/exceptions.rb b/lib/exceptions.rb index 5f3c8e733..340666426 100644 --- a/lib/exceptions.rb +++ b/lib/exceptions.rb @@ -6,3 +6,5 @@ class InvalidDatesError < StandardError class NoBlockError < StandardError end + +class InvalidDiscountError < StandardError From 2a690db9963f74708d5c1f5bfc0bed64649525d0 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 15:20:32 -0700 Subject: [PATCH 087/131] edge tests for #make_block --- specs/hotel_spec.rb | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 4697085e5..a0e745ad8 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -355,11 +355,34 @@ end end - it 'raises an error when there are not enough rooms to fill a block' do + it 'raises NoRoomError when there are not enough rooms to fill a block' do proc { @hotel.make_block('2017-08-03', '2017-08-07', 11, 20) }.must_raise NoRoomError end + + it 'raises ArgumentError error when passed invalid dates' do + proc { + @hotel.make_block('Augustish', 'Later', 5, 25) + }.must_raise ArgumentError + + proc { + @hotel.make_block('2017-14-14', '2017-15-15', 5, 25) + }.must_raise ArgumentError + end + + it 'raises InvalidDatesError when dates are out of order' do + proc { + @hotel.make_block('2017-09-07', '2017-09-05', 5, 25) + }.must_raise InvalidDatesError + end + + it 'raises InvalidDiscountError when passed discount greater than 100%' do + proc { + @hotel.make_block('2017-09-07', '2017-09-010', 5, 125) + }.must_raise InvalidDiscountError + end + end describe '#find_rooms_not_in_blocks' do From 3ae88199dfc075add0c1de6922411f625e9b6f71 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 15:21:07 -0700 Subject: [PATCH 088/131] renamed InvalidDatesError to DatesError and InvalidDiscountError to DiscountError --- lib/date_range.rb | 2 +- lib/exceptions.rb | 4 ++-- lib/hotel.rb | 2 +- specs/date_range_spec.rb | 6 +++--- specs/hotel_spec.rb | 20 ++++++++++---------- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index d06ebee35..64d16731a 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -29,7 +29,7 @@ def self.validate_order(first, second) first = validate(first) second = validate(second) unless first < second - raise(InvalidDatesError, 'Start date must be at least 1 day before end date') + raise(DatesError, 'Start date must be at least 1 day before end date') end end diff --git a/lib/exceptions.rb b/lib/exceptions.rb index 340666426..748ed57b4 100644 --- a/lib/exceptions.rb +++ b/lib/exceptions.rb @@ -1,10 +1,10 @@ class NoRoomError < StandardError end -class InvalidDatesError < StandardError +class DatesError < StandardError end class NoBlockError < StandardError end -class InvalidDiscountError < StandardError +class DiscountError < StandardError diff --git a/lib/hotel.rb b/lib/hotel.rb index 96fc7d022..95a8f1921 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -59,7 +59,7 @@ def find_available_rooms(checkin, checkout, block_id = false) raise(NoBlockError, "No such block: #{block_id}") end unless block(block_id).includes_dates?(checkin, checkout) - raise(InvalidDatesError, "Dates (#{checkin}, #{checkout}) do not fall within provided block #{block(block_id).id}") + raise(DatesError, "Dates (#{checkin}, #{checkout}) do not fall within provided block #{block(block_id).id}") end rooms = block(block_id).rooms else diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index 4515f4b0f..13b16c323 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -7,10 +7,10 @@ end describe 'self.range_to' do - it 'raises InvalidDatesError if start date is after end date' do + it 'raises DatesError if start date is after end date' do proc { DateRange.range_to(@after, @before) - }.must_raise InvalidDatesError + }.must_raise DatesError end it 'returns an array of Dates' do @@ -35,7 +35,7 @@ it 'raises ArgumentError if start date is after end date' do proc { DateRange.range_with(@after, @before) - }.must_raise InvalidDatesError + }.must_raise DatesError end it 'returns an array of Dates' do diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index a0e745ad8..18b83a56a 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -160,19 +160,19 @@ proc { @hotel.find_available_rooms('2017-10-14', '2017-10-15', block.id) - }.must_raise InvalidDatesError + }.must_raise DatesError end it 'raises an error if dates are out of order' do proc { @hotel.find_available_rooms('2017-08-23', '2017-08-08') - }.must_raise InvalidDatesError + }.must_raise DatesError end it 'raises an error if dates do not span at least 1 night' do proc { @hotel.find_available_rooms('2017-08-08', '2017-08-08') - }.must_raise InvalidDatesError + }.must_raise DatesError end end end @@ -238,10 +238,10 @@ }.must_raise ArgumentError end - it 'raises InvalidDatesError if dates are out of order' do + it 'raises DatesError if dates are out of order' do proc { reservation = @hotel.make_reservation('2017-09-08', '2017-09-05') - }.must_raise InvalidDatesError + }.must_raise DatesError end it 'raises NoBlockError if passed nonexistent block' do @@ -371,16 +371,16 @@ }.must_raise ArgumentError end - it 'raises InvalidDatesError when dates are out of order' do + it 'raises DatesError when dates are out of order' do proc { @hotel.make_block('2017-09-07', '2017-09-05', 5, 25) - }.must_raise InvalidDatesError + }.must_raise DatesError end - it 'raises InvalidDiscountError when passed discount greater than 100%' do + it 'raises DiscountError when passed discount greater than 100%' do proc { @hotel.make_block('2017-09-07', '2017-09-010', 5, 125) - }.must_raise InvalidDiscountError + }.must_raise DiscountError end end @@ -415,7 +415,7 @@ it 'raises an exception if the dates do not fall within the block' do proc { @hotel.block_availability?('2017-10-14','2017-10-15', @block.id) - }.must_raise InvalidDatesError + }.must_raise DatesError end end From 9c43bda98ad396bb1b2290d43003b2eb11a0296e Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 15:31:45 -0700 Subject: [PATCH 089/131] input validation for Block.discount_rate --- lib/block.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/block.rb b/lib/block.rb index 69e968ee1..fdc8ac446 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -7,7 +7,7 @@ def initialize(start_date, end_date, rooms, discount_rate) @end_date = Date.parse(end_date) @dates = DateRange.range_to(@start_date, @end_date) @rooms = rooms - @discount_rate = (100 - discount_rate) / 100 + @discount_rate = get_discount_rate(discount_rate) @id = create_id end @@ -18,5 +18,11 @@ def create_id def includes_dates?(checkfirst, checklast) DateRange.overlap?(checkfirst, checklast, @start_date, @end_date) end + + def get_discount_rate(input) + raise(ArgumentError, "Discount must be number: #{input.class}") unless input.class == (Integer || Float) + raise(DiscountError, "Discount must be between 0-100%: #{input}") unless 0 < input && input < 100 + return (100 - input) / 100 + end end end From 5adc193efc9bc159150e8bfa28e8cc46c9b06bb8 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 15:32:25 -0700 Subject: [PATCH 090/131] add missing end --- lib/exceptions.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/exceptions.rb b/lib/exceptions.rb index 748ed57b4..86b31c1ed 100644 --- a/lib/exceptions.rb +++ b/lib/exceptions.rb @@ -8,3 +8,4 @@ class NoBlockError < StandardError end class DiscountError < StandardError +end From 3244b40d7655eb6e15a3a99eeb8cbeab40c34a44 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 15:41:40 -0700 Subject: [PATCH 091/131] clarify error messages --- lib/block.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index fdc8ac446..2c24e94b6 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -20,8 +20,8 @@ def includes_dates?(checkfirst, checklast) end def get_discount_rate(input) - raise(ArgumentError, "Discount must be number: #{input.class}") unless input.class == (Integer || Float) - raise(DiscountError, "Discount must be between 0-100%: #{input}") unless 0 < input && input < 100 + raise(ArgumentError, "Discount must be number: was #{input.class}") unless input.class == (Integer || Float) + raise(DiscountError, "Discount must be between 0-100%: was #{input}") unless 0 < input && input < 100 return (100 - input) / 100 end end From 9b838838be84e2d1c2834b3d8b7fbded51d263f8 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 15:53:08 -0700 Subject: [PATCH 092/131] add descriptions for exceptions defining their use scenarios --- lib/exceptions.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/exceptions.rb b/lib/exceptions.rb index 86b31c1ed..ee83bb621 100644 --- a/lib/exceptions.rb +++ b/lib/exceptions.rb @@ -1,11 +1,16 @@ class NoRoomError < StandardError + # Raised when there are not enough available rooms for request end class DatesError < StandardError + # Raised when dates are in wrong order, out of range, etc + # NOT raised for invalid date input (use ArgumentError) end class NoBlockError < StandardError + # Raised when provided block does not exist/cannot be found end class DiscountError < StandardError + # Raised when discount is not number from 0-100 end From 03f59e9647c2e0c3f3e5ffbfb1df8a8d1c833272 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 15:53:37 -0700 Subject: [PATCH 093/131] input validation for #make_block num_rooms --- lib/hotel.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/hotel.rb b/lib/hotel.rb index 95a8f1921..6ee6cc0ad 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -36,6 +36,7 @@ def make_reservation(checkin, checkout, block = false) end def make_block(start_date, end_date, num_rooms, discount) + raise(ArgumentError,"Number of rooms must be Integer: is #{num_rooms.class}") unless num_rooms.class == Integer rooms = find_available_rooms(start_date, end_date)[0...num_rooms] raise(NoRoomError, "Not enough available rooms for amount #{num_rooms}") if rooms.length < num_rooms block = Block.new(start_date, end_date, rooms, discount) From 6b2cbdf3073c2a0632c4e73f6989ae651a146a90 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Fri, 8 Sep 2017 16:00:18 -0700 Subject: [PATCH 094/131] edge tests for #make_block --- specs/hotel_spec.rb | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 18b83a56a..1f5369fd8 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -244,6 +244,12 @@ }.must_raise DatesError end + it 'raises DatesError if reservation does not span at least 1 night' do + proc { + @hotel.make_reservation('2017-10-14','2017-10-14') + }.must_raise DatesError + end + it 'raises NoBlockError if passed nonexistent block' do proc { @hotel.make_reservation('2017-09-05', '2017-09-08', 'catbug') @@ -331,6 +337,12 @@ @block.must_be_kind_of Hotel::Block end + it 'can make a block for 1 night' do + block = @hotel.make_block('2017-08-03', '2017-08-04', 10, 20) + + block.dates.length.must_equal 1 + end + it 'adds to @blocks array' do @hotel.blocks.length.must_equal 1 end @@ -377,12 +389,43 @@ }.must_raise DatesError end + it 'raises DatesError when dates do not span at least 1 night' do + proc { + @hotel.make_block('2017-08-03', '2017-08-03', 10, 20) + }.must_raise DatesError + end + it 'raises DiscountError when passed discount greater than 100%' do proc { - @hotel.make_block('2017-09-07', '2017-09-010', 5, 125) + @hotel.make_block('2017-09-07', '2017-09-10', 5, 125) + }.must_raise DiscountError + end + + it 'raises DiscountError when passed discount below 0%' do + proc { + @hotel.make_block('2017-09-07', '2017-09-10', 5, -25) }.must_raise DiscountError end + it 'raises ArgumentError when passed invalid discount' do + proc { + @hotel.make_block('2017-09-07', '2017-09-10', 5, 'free') + }.must_raise ArgumentError + end + + it 'raises error when passed invalid rooms number' do + proc { + @hotel.make_block('2017-09-07', '2017-09-10', true, 25) + }.must_raise ArgumentError + + proc { + @hotel.make_block('2017-09-07', '2017-09-10', 0.5, 25) + }.must_raise ArgumentError + + proc { + @hotel.make_block('2017-09-07', '2017-09-10', 'hello', 25) + }.must_raise ArgumentError + end end describe '#find_rooms_not_in_blocks' do From 77fd3168129c40ae7532ef2983651afe60c7ad5f Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 14:19:23 -0700 Subject: [PATCH 095/131] edge tests for #find_rooms_not_in_blocks and #block_availability? --- lib/hotel.rb | 3 ++ specs/hotel_spec.rb | 78 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 6ee6cc0ad..c06da34c5 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -37,8 +37,11 @@ def make_reservation(checkin, checkout, block = false) def make_block(start_date, end_date, num_rooms, discount) raise(ArgumentError,"Number of rooms must be Integer: is #{num_rooms.class}") unless num_rooms.class == Integer + rooms = find_available_rooms(start_date, end_date)[0...num_rooms] + raise(NoRoomError, "Not enough available rooms for amount #{num_rooms}") if rooms.length < num_rooms + block = Block.new(start_date, end_date, rooms, discount) @blocks << block block diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 1f5369fd8..00f7cc461 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -224,6 +224,13 @@ block.rooms.must_include reservation.room end + it 'raises DatesError if reservation does not fall fully within block' do + block = @hotel.make_block('2017-08-03', '2017-08-08', 5, 10) + proc { + @hotel.make_reservation('2017-08-06', '2017-08-10', block.id) + }.must_raise DatesError + end + it 'raises ArgumentError if passed invalid dates' do proc { @hotel.make_reservation('cat','bug') @@ -436,9 +443,54 @@ it 'returns rooms that are not in block' do rooms = @hotel.find_rooms_not_in_blocks('2017-08-05', '2017-08-07') + rooms.each do |room| @block.rooms.wont_include room end + + rooms.length.must_equal 10 + end + + it 'returns rooms that are reserved, but not in blocks' do + @hotel.make_reservation('2017-08-03', '2017-08-07') + + rooms = @hotel.find_rooms_not_in_blocks('2017-08-05', '2017-08-07') + + rooms.length.must_equal 10 + end + + it 'returns empty array if all rooms are in block' do + @hotel.make_block('2017-08-03', '2017-08-07', 10, 20) + + rooms = @hotel.find_rooms_not_in_blocks('2017-08-03', '2017-08-07') + + rooms.must_equal [] + end + + it 'raises DatesError if dates are out of order' do + proc { + @hotel.find_rooms_not_in_blocks('2017-09-15', '2017-09-05') + }.must_raise DatesError + end + + it 'raises ArgumentError if passed invalid date' do + proc { + @hotel.find_rooms_not_in_blocks('sea','HAWKS') + }.must_raise ArgumentError + + proc { + @hotel.find_rooms_not_in_blocks('2017-08-06','HAWKS') + }.must_raise ArgumentError + + proc { + @hotel.find_rooms_not_in_blocks('2017-08-06','HAWKS') + }.must_raise ArgumentError + end + + it 'raises DatesError if dates do not span at least 1 night' do + proc { + @hotel.find_rooms_not_in_blocks('2017-08-06','2017-08-06') + }.must_raise DatesError end end @@ -455,11 +507,35 @@ check.must_equal false end - it 'raises an exception if the dates do not fall within the block' do + it 'raises NoBlockError if block cannot be found' do + proc { + @hotel.block_availability?('2017-10-14', '2017-10-15', 'bad block') + }.must_raise NoBlockError + end + + it 'raises DatesError if the dates do not fall within the block' do proc { @hotel.block_availability?('2017-10-14','2017-10-15', @block.id) }.must_raise DatesError end + + it 'raises DatesError if the dates are out of order' do + proc { + @hotel.block_availability?('2017-11-14','2017-10-15', @block.id) + }.must_raise DatesError + end + + it 'raises DatesError if the dates do not span at least 1 night' do + proc { + @hotel.block_availability?('2017-10-14','2017-10-14', @block.id) + }.must_raise DatesError + end + + it 'raises ArgumentError if passed invalid dates' do + proc { + @hotel.block_availability?('sea','HAWKS') + }.must_raise ArgumentError + end end describe '#block_exists?' do From 795c4460e2dba4bfc57ccd21c29419e11606596c Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 14:30:48 -0700 Subject: [PATCH 096/131] add #include_all? method --- lib/date_range.rb | 15 +++++++++++++++ specs/date_range_spec.rb | 20 ++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/lib/date_range.rb b/lib/date_range.rb index 64d16731a..21ee3c43c 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -25,6 +25,21 @@ def self.overlap?(first_start, first_end, second_start, second_end) false end + def self.include_all?(search_start, search_end, contain_start, contain_end) + search_start = validate(search_start) + search_end = validate(search_end) + contain_start = validate(contain_start) + contain_end = validate(contain_end) + + search_dates = DateRange.range_to(search_start, search_end) + contain_dates = DateRange.range_to(contain_start, contain_end) + + search_dates.each do |search_date| + return false unless contain_dates.include? search_date + end + true + end + def self.validate_order(first, second) first = validate(first) second = validate(second) diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index 13b16c323..3b3e42aec 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -78,6 +78,26 @@ end end + describe '#include_all?' do + it 'returns true if all searched dates fall within container range' do + include_all = DateRange.include_all?('2017-10-10', '2017-10-14', @before, @after) + + include_all.must_equal true + end + + it 'returns false if no searched dates fall within container range' do + include_all = DateRange.include_all?('2017-11-10', '2017-11-14', @before, @after) + + include_all.must_equal false + end + + it 'returns false for partial overlap' do + include_all = DateRange.include_all?('2017-10-10', '2017-11-14', @before, @after) + + include_all.must_equal false + end + end + describe 'self.validate' do it 'returns input unchanged if input is a Date object' do DateRange.validate(@before).must_equal @before From dce26c59e22f6dfe8304c65a74c8ed5d163bea1a Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 14:44:57 -0700 Subject: [PATCH 097/131] add #include_all_dates? method --- lib/block.rb | 4 ++++ specs/block_spec.rb | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/lib/block.rb b/lib/block.rb index 2c24e94b6..d40a8da21 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -19,6 +19,10 @@ def includes_dates?(checkfirst, checklast) DateRange.overlap?(checkfirst, checklast, @start_date, @end_date) end + def includes_all_dates?(checkfirst, checklast) + DateRange.include_all?(checkfirst, checklast, @start_date, @end_date) + end + def get_discount_rate(input) raise(ArgumentError, "Discount must be number: was #{input.class}") unless input.class == (Integer || Float) raise(DiscountError, "Discount must be between 0-100%: was #{input}") unless 0 < input && input < 100 diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 3a10c53bb..692cd70d0 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -19,6 +19,44 @@ end describe 'includes_dates?' do - #TODO: test includes_dates? + it 'returns true if block includes provided dates' do + includes_dates = @block.includes_dates?('2017-08-03', '2017-08-07') + + includes_dates.must_equal true + end + + it 'returns false if block does not include provided dates' do + includes_dates = @block.includes_dates?('2017-10-14', '2017-10-18') + + includes_dates.must_equal false + end + + it 'returns true for partial overlap' do + includes_dates = @block.includes_dates?('2017-08-03', '2017-08-10') + + includes_dates.must_equal true + end + + # TODO: test exceptions + end + + describe 'includes_all_dates?' do + it 'returns true if block includes provided dates' do + includes_all_dates = @block.includes_all_dates?('2017-08-03', '2017-08-07') + + includes_all_dates.must_equal true + end + + it 'returns false if block does not include provided dates' do + includes_all_dates = @block.includes_all_dates?('2017-10-14', '2017-10-18') + + includes_all_dates.must_equal false + end + + it 'returns true for partial overlap' do + includes_all_dates = @block.includes_all_dates?('2017-08-03', '2017-08-10') + + includes_all_dates.must_equal false + end end end From 586ddbeb87b629b9cd679ed78b77f59e46ffa819 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 14:46:21 -0700 Subject: [PATCH 098/131] add date confirmation for #make_reservation in block --- lib/hotel.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/hotel.rb b/lib/hotel.rb index c06da34c5..606a11df0 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -30,6 +30,11 @@ def make_reservation(checkin, checkout, block = false) if room_num.nil? raise(NoRoomError, "No available rooms for dates #{checkin} - #{checkout}") end + if block + raise(DatesError) unless block(block).includes_all_dates?(checkin, checkout) + # binding.pry + end + reservation = Reservation.new(room_num, checkin, checkout, block) @reservations << reservation reservation From 9198637bc6e4e007234d1ff1ce25e8554c3c8e3a Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 14:48:01 -0700 Subject: [PATCH 099/131] remove TODO --- specs/hotel_spec.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 00f7cc461..661cfaa3c 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -552,5 +552,3 @@ end end end - -# TODO: lots and lots of edge case testing From dbd91fb5739ee5e83308e07f92d0cdc17fb7993e Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:04:40 -0700 Subject: [PATCH 100/131] #initialize validates instead of parses date input - can take Date or String --- lib/reservation.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 703e882af..f4c782002 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -5,8 +5,8 @@ class Reservation def initialize(room, checkin, checkout, block = false) @room = room - @checkin = Date.parse(checkin) - @checkout = Date.parse(checkout) + @checkin = DateRange.validate(checkin) + @checkout = DateRange.validate(checkout) @dates = DateRange.range_to(@checkin, @checkout) # @id = create_id @block = block From d8425e4eab633b925a5a50637d6446951f8a5d69 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:05:40 -0700 Subject: [PATCH 101/131] --amend --- specs/reservation_spec.rb | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index dc266bb6e..54938011f 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -23,7 +23,21 @@ (@reservation.total_cost % @reservation.dates.length).must_equal 0 end - # TODO: various date formats 'August 31st, 2017' + it 'factors block discount into total if part of block' do + block = @hotel.make_block('2017-08-03', '2017-08-08', 10, 25) + reservation = @hotel.make_reservation('2017-08-03', '2017-08-08', block.id) + reservation.total_cost.must_equal 750 + end + + it 'can be initialized with various date formats (Date or String)' do + date1 = Date.new(2017, 9, 5) + date2 = Date.new(2017, 9, 10) + Hotel::Reservation.new(@room, date1, date2, @hotel) + Hotel::Reservation.new(@room, '2017-09-05', '2017-09-10', @hotel) + Hotel::Reservation.new(@room, 'September 5th, 2017', 'September 10th, 2017', @hotel) + Hotel::Reservation.new(@room, '5/9/17', '10/9/17, 2017', @hotel) + end + # TODO: @total_cost discount for blocks # it 'has 9-character @id value' do From 20a11133aa0bf0f7c0bb74f08991a70f0d80a688 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:06:27 -0700 Subject: [PATCH 102/131] remembered why @reservation has to take hotel parameter --- lib/reservation.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index f4c782002..7e75215db 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -3,11 +3,12 @@ class Reservation require_relative 'date_range' attr_reader :total_cost, :dates, :checkin, :checkout, :id, :hotel, :room - def initialize(room, checkin, checkout, block = false) + def initialize(room, checkin, checkout, hotel, block = false) @room = room @checkin = DateRange.validate(checkin) @checkout = DateRange.validate(checkout) @dates = DateRange.range_to(@checkin, @checkout) + @hotel = hotel # @id = create_id @block = block get_total From c93eaab3548dde5e0bc0264daba1533db4cdfedc Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:22:58 -0700 Subject: [PATCH 103/131] add reader method for @discount_rate and convert output into Float --- lib/block.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index d40a8da21..b664da126 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -1,6 +1,6 @@ module Hotel class Block - attr_reader :rooms, :id, :start_date, :end_date, :dates + attr_reader :rooms, :id, :start_date, :end_date, :dates, :discount_rate def initialize(start_date, end_date, rooms, discount_rate) @start_date = Date.parse(start_date) @@ -26,7 +26,7 @@ def includes_all_dates?(checkfirst, checklast) def get_discount_rate(input) raise(ArgumentError, "Discount must be number: was #{input.class}") unless input.class == (Integer || Float) raise(DiscountError, "Discount must be between 0-100%: was #{input}") unless 0 < input && input < 100 - return (100 - input) / 100 + return (100.0 - input) / 100 end end end From 563f64937d78d06f7902de20db8318a3a9757264 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:24:46 -0700 Subject: [PATCH 104/131] #make_reservation passes hotel as argument --- lib/hotel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 606a11df0..8bf3760e5 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -35,7 +35,7 @@ def make_reservation(checkin, checkout, block = false) # binding.pry end - reservation = Reservation.new(room_num, checkin, checkout, block) + reservation = Reservation.new(room_num, checkin, checkout, self, block) @reservations << reservation reservation end From dce178ccbdcdb1a70490de7ecc84dae3a1f3c815 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:25:07 -0700 Subject: [PATCH 105/131] implement block discount in #get_total --- lib/reservation.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 7e75215db..4b9dac508 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -1,22 +1,25 @@ +require 'pry' + module Hotel class Reservation require_relative 'date_range' - attr_reader :total_cost, :dates, :checkin, :checkout, :id, :hotel, :room + attr_reader :total_cost, :dates, :checkin, :checkout, :id, :hotel, :room, :block def initialize(room, checkin, checkout, hotel, block = false) @room = room @checkin = DateRange.validate(checkin) @checkout = DateRange.validate(checkout) @dates = DateRange.range_to(@checkin, @checkout) - @hotel = hotel - # @id = create_id - @block = block + @block = block ? hotel.block(block) : false get_total end def get_total + # puts "block is #{@block}" num_nights = @dates.length @total_cost = @room.cost * num_nights + @total_cost *= @block.discount_rate if @block + return @total_cost end def includes_dates?(checkfirst, checklast) From 1758ca8bf98e16e7de2d2075b540e99e234eb3e6 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:25:40 -0700 Subject: [PATCH 106/131] remove unused #create_id method --- lib/reservation.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 4b9dac508..a140eba2b 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -25,11 +25,5 @@ def get_total def includes_dates?(checkfirst, checklast) DateRange.overlap?(checkfirst, checklast, @checkin, @checkout) end - - private - - # def create_id - # format('R%.2d%.2d%.4d', @checkin.month, @checkin.day, rand(9999)) - # end end end From 218b77ecadea59df6b61d26a3f398f5c9f11dd26 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:38:08 -0700 Subject: [PATCH 107/131] moved Reservation date validation from Hotel to Reservation.initialize --- lib/hotel.rb | 5 ----- lib/reservation.rb | 7 ++++++- specs/reservation_spec.rb | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 8bf3760e5..f9dfbfcde 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -30,11 +30,6 @@ def make_reservation(checkin, checkout, block = false) if room_num.nil? raise(NoRoomError, "No available rooms for dates #{checkin} - #{checkout}") end - if block - raise(DatesError) unless block(block).includes_all_dates?(checkin, checkout) - # binding.pry - end - reservation = Reservation.new(room_num, checkin, checkout, self, block) @reservations << reservation reservation diff --git a/lib/reservation.rb b/lib/reservation.rb index a140eba2b..1dd1e56d9 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -10,7 +10,12 @@ def initialize(room, checkin, checkout, hotel, block = false) @checkin = DateRange.validate(checkin) @checkout = DateRange.validate(checkout) @dates = DateRange.range_to(@checkin, @checkout) - @block = block ? hotel.block(block) : false + if block + @block = hotel.block(block) + raise(DatesError) unless @block.includes_all_dates?(checkin, checkout) + else + @block = false + end get_total end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 54938011f..41e316b67 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -38,13 +38,11 @@ Hotel::Reservation.new(@room, '5/9/17', '10/9/17, 2017', @hotel) end - # TODO: @total_cost discount for blocks - - # it 'has 9-character @id value' do - # @reservation.id.must_be_kind_of String - # @reservation.id.length.must_equal 9 - # @reservation.id[0..4].must_equal 'R0905' - # end + it 'raises DatesError if dates are out of order' do + proc { + Hotel::Reservation.new(@room, '2017-09-15', '2017-09-07', @hotel) + }.must_raise DatesError + end end describe '#includes_dates?' do @@ -57,5 +55,7 @@ overlap = @reservation.includes_dates?('2017-10-14', '2017-10-15') overlap.must_equal false end + + # TODO: exceptions end end From 15a5121527bb6ee7a64830948653c4a591c3b3b1 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:50:36 -0700 Subject: [PATCH 108/131] removed comments --- lib/reservation.rb | 1 - specs/reservation_spec.rb | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 1dd1e56d9..7a1a6bdcc 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -20,7 +20,6 @@ def initialize(room, checkin, checkout, hotel, block = false) end def get_total - # puts "block is #{@block}" num_nights = @dates.length @total_cost = @room.cost * num_nights @total_cost *= @block.discount_rate if @block diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 41e316b67..158ab4a8d 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -43,6 +43,20 @@ Hotel::Reservation.new(@room, '2017-09-15', '2017-09-07', @hotel) }.must_raise DatesError end + + it 'raises DatesError if dates do not span at least 1 night' do + proc { + Hotel::Reservation.new(@room, '2017-09-05', '2017-09-05', @hotel) + }.must_raise DatesError + + + end + + it 'raises ArgumentError if passed invalid dates' do + proc { + Hotel::Reservation.new(@room, 'sea', 'HAWKS', @hotel) + }.must_raise ArgumentError + end end describe '#includes_dates?' do @@ -56,6 +70,27 @@ overlap.must_equal false end - # TODO: exceptions + it 'returns true for partial overlap' do + overlap = @reservation.includes_dates?('2017-09-06', '2017-09-20') + overlap.must_equal true + end + + it 'raises DatesError if dates are out of order' do + proc { + @reservation.includes_dates?('2017-09-15', '2017-09-07') + }.must_raise DatesError + end + + it 'raises DatesError if dates do not span at least 1 night' do + proc { + @reservation.includes_dates?('2017-09-05', '2017-09-05') + }.must_raise DatesError + end + + it 'raises ArgumentError if passed invalid dates' do + proc { + @reservation.includes_dates?('sea', 'HAWKS') + }.must_raise ArgumentError + end end end From fe28cff911c70a02dcd6ea0b8ed58614d7bf8ca9 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:54:39 -0700 Subject: [PATCH 109/131] block discount can be 0% or 100% --- lib/block.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/block.rb b/lib/block.rb index b664da126..596f2f3cc 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -25,7 +25,7 @@ def includes_all_dates?(checkfirst, checklast) def get_discount_rate(input) raise(ArgumentError, "Discount must be number: was #{input.class}") unless input.class == (Integer || Float) - raise(DiscountError, "Discount must be between 0-100%: was #{input}") unless 0 < input && input < 100 + raise(DiscountError, "Discount must be between 0-100%: was #{input}") unless 0 <= input && input <= 100 return (100.0 - input) / 100 end end From 7279cbd1b4c4bf7b0152ad2c4af92e40cce23e41 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:56:11 -0700 Subject: [PATCH 110/131] discount can be float, discounts to 0% --- lib/block.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index 596f2f3cc..1a781f5b7 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -2,7 +2,7 @@ module Hotel class Block attr_reader :rooms, :id, :start_date, :end_date, :dates, :discount_rate - def initialize(start_date, end_date, rooms, discount_rate) + def initialize(start_date, end_date, rooms, discount_rate = 0) @start_date = Date.parse(start_date) @end_date = Date.parse(end_date) @dates = DateRange.range_to(@start_date, @end_date) @@ -24,7 +24,7 @@ def includes_all_dates?(checkfirst, checklast) end def get_discount_rate(input) - raise(ArgumentError, "Discount must be number: was #{input.class}") unless input.class == (Integer || Float) + raise(ArgumentError, "Discount must be number: was #{input.class}") unless (input.class == Integer) || (input.class == Float) raise(DiscountError, "Discount must be between 0-100%: was #{input}") unless 0 <= input && input <= 100 return (100.0 - input) / 100 end From 399d9242cf2be67b357154818ad8919c216541e2 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:57:59 -0700 Subject: [PATCH 111/131] discount defaults to 0 --- lib/block.rb | 2 +- lib/hotel.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index 1a781f5b7..892ca6599 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -2,7 +2,7 @@ module Hotel class Block attr_reader :rooms, :id, :start_date, :end_date, :dates, :discount_rate - def initialize(start_date, end_date, rooms, discount_rate = 0) + def initialize(start_date, end_date, rooms, discount_rate) @start_date = Date.parse(start_date) @end_date = Date.parse(end_date) @dates = DateRange.range_to(@start_date, @end_date) diff --git a/lib/hotel.rb b/lib/hotel.rb index f9dfbfcde..05b35632a 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -35,7 +35,7 @@ def make_reservation(checkin, checkout, block = false) reservation end - def make_block(start_date, end_date, num_rooms, discount) + def make_block(start_date, end_date, num_rooms, discount = 0) raise(ArgumentError,"Number of rooms must be Integer: is #{num_rooms.class}") unless num_rooms.class == Integer rooms = find_available_rooms(start_date, end_date)[0...num_rooms] From 4cdd9c7bdbb955f5be082d5a146cd41d1320df3a Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:58:08 -0700 Subject: [PATCH 112/131] discount defaults to 0 --- lib/block.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/block.rb b/lib/block.rb index 892ca6599..1a781f5b7 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -2,7 +2,7 @@ module Hotel class Block attr_reader :rooms, :id, :start_date, :end_date, :dates, :discount_rate - def initialize(start_date, end_date, rooms, discount_rate) + def initialize(start_date, end_date, rooms, discount_rate = 0) @start_date = Date.parse(start_date) @end_date = Date.parse(end_date) @dates = DateRange.range_to(@start_date, @end_date) From 1aed3591dbc9ae0a113cf1885647a07134fbbb34 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 15:59:43 -0700 Subject: [PATCH 113/131] edge tests for #get_total --- lib/reservation.rb | 1 - specs/reservation_spec.rb | 42 +++++++++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 7a1a6bdcc..63c801e5b 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -23,7 +23,6 @@ def get_total num_nights = @dates.length @total_cost = @room.cost * num_nights @total_cost *= @block.discount_rate if @block - return @total_cost end def includes_dates?(checkfirst, checklast) diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb index 158ab4a8d..3359a097c 100644 --- a/specs/reservation_spec.rb +++ b/specs/reservation_spec.rb @@ -23,12 +23,6 @@ (@reservation.total_cost % @reservation.dates.length).must_equal 0 end - it 'factors block discount into total if part of block' do - block = @hotel.make_block('2017-08-03', '2017-08-08', 10, 25) - reservation = @hotel.make_reservation('2017-08-03', '2017-08-08', block.id) - reservation.total_cost.must_equal 750 - end - it 'can be initialized with various date formats (Date or String)' do date1 = Date.new(2017, 9, 5) date2 = Date.new(2017, 9, 10) @@ -59,6 +53,42 @@ end end + describe 'get_total' do + it 'factors block discount into total if part of block' do + block = @hotel.make_block('2017-08-03', '2017-08-08', 10, 25) + reservation = @hotel.make_reservation('2017-08-03', '2017-08-08', block.id) + reservation.total_cost.must_equal 750 + end + + it 'returns total without discount if not part of block' do + @reservation.total_cost.must_equal 400 + end + + it 'can have 0% (no) discount in block' do + block = @hotel.make_block('2017-08-03', '2017-08-08', 10, 0) + reservation = @hotel.make_reservation('2017-08-03', '2017-08-08', block.id) + reservation.total_cost.must_equal 1000 + end + + it 'can have 100% (gratis) discount in block' do + block = @hotel.make_block('2017-08-03', '2017-08-08', 10, 100) + reservation = @hotel.make_reservation('2017-08-03', '2017-08-08', block.id) + reservation.total_cost.must_equal 0 + end + + it 'can have float as discount in block' do + block = @hotel.make_block('2017-08-03', '2017-08-08', 10, 12.5) + reservation = @hotel.make_reservation('2017-08-03', '2017-08-08', block.id) + reservation.total_cost.must_equal 875 + end + + it 'defaults to 0% (no) discount' do + block = @hotel.make_block('2017-08-03', '2017-08-08', 10) + reservation = @hotel.make_reservation('2017-08-03', '2017-08-08', block.id) + reservation.total_cost.must_equal 1000 + end + end + describe '#includes_dates?' do it 'returns true if provided date range overlaps' do overlap = @reservation.includes_dates?('2017-09-06', '2017-09-07') From b525ab61992cf655bcafa969a7575998f2a50106 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 16:01:09 -0700 Subject: [PATCH 114/131] renamed Room.cost to Room.rate --- lib/reservation.rb | 2 +- lib/room.rb | 6 +++--- specs/room_spec.rb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/reservation.rb b/lib/reservation.rb index 63c801e5b..fefed8936 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -21,7 +21,7 @@ def initialize(room, checkin, checkout, hotel, block = false) def get_total num_nights = @dates.length - @total_cost = @room.cost * num_nights + @total_cost = @room.rate * num_nights @total_cost *= @block.discount_rate if @block end diff --git a/lib/room.rb b/lib/room.rb index 297cb49ef..42ec1eb81 100644 --- a/lib/room.rb +++ b/lib/room.rb @@ -1,10 +1,10 @@ module Hotel class Room - attr_reader :number, :cost + attr_reader :number, :rate - def initialize(number, cost) + def initialize(number, rate) @number = number - @cost = cost + @rate = rate end end end diff --git a/specs/room_spec.rb b/specs/room_spec.rb index 7cbfd962f..d278cf4cc 100644 --- a/specs/room_spec.rb +++ b/specs/room_spec.rb @@ -14,7 +14,7 @@ end it 'has a cost' do - @room.cost.must_equal 200 + @room.rate.must_equal 200 end end end From d6964ce3bad0181028f96f72114e77d5293c716d Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 16:06:08 -0700 Subject: [PATCH 115/131] did not need Block.includes_dates? method - replaced all with Block.includes_all_dates? which was renamed to Block.includes_dates? --- lib/block.rb | 4 ---- lib/reservation.rb | 2 +- specs/block_spec.rb | 24 +----------------------- 3 files changed, 2 insertions(+), 28 deletions(-) diff --git a/lib/block.rb b/lib/block.rb index 1a781f5b7..dd1e2caf9 100644 --- a/lib/block.rb +++ b/lib/block.rb @@ -16,10 +16,6 @@ def create_id end def includes_dates?(checkfirst, checklast) - DateRange.overlap?(checkfirst, checklast, @start_date, @end_date) - end - - def includes_all_dates?(checkfirst, checklast) DateRange.include_all?(checkfirst, checklast, @start_date, @end_date) end diff --git a/lib/reservation.rb b/lib/reservation.rb index fefed8936..317a746eb 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -12,7 +12,7 @@ def initialize(room, checkin, checkout, hotel, block = false) @dates = DateRange.range_to(@checkin, @checkout) if block @block = hotel.block(block) - raise(DatesError) unless @block.includes_all_dates?(checkin, checkout) + raise(DatesError) unless @block.includes_dates?(checkin, checkout) else @block = false end diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 692cd70d0..2f653a809 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -34,29 +34,7 @@ it 'returns true for partial overlap' do includes_dates = @block.includes_dates?('2017-08-03', '2017-08-10') - includes_dates.must_equal true - end - - # TODO: test exceptions - end - - describe 'includes_all_dates?' do - it 'returns true if block includes provided dates' do - includes_all_dates = @block.includes_all_dates?('2017-08-03', '2017-08-07') - - includes_all_dates.must_equal true - end - - it 'returns false if block does not include provided dates' do - includes_all_dates = @block.includes_all_dates?('2017-10-14', '2017-10-18') - - includes_all_dates.must_equal false - end - - it 'returns true for partial overlap' do - includes_all_dates = @block.includes_all_dates?('2017-08-03', '2017-08-10') - - includes_all_dates.must_equal false + includes_dates.must_equal false end end end From 860bc5ef64febcdd806e41eebaa60b50c00934e4 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 16:13:29 -0700 Subject: [PATCH 116/131] edge tests for #initialize --- specs/block_spec.rb | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 2f653a809..4c8c85465 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -3,7 +3,8 @@ describe 'Block' do before do # - To create a block you need a date range, collection of rooms and a discounted room rate - @block = Hotel::Block.new('2017-08-03', '2017-08-07', 5, 20) + @hotel = Hotel::Hotel.new(20) + @block = @hotel.make_block('2017-08-03', '2017-08-07', 5, 20) end describe 'initialize' do @@ -13,9 +14,38 @@ it 'has 9-character @id value' do @block.id.must_be_kind_of String - @block.id.length.must_equal 9 + @block.id.length.must_equal 9r @block.id[0..4].must_equal 'B0803' end + + it 'has array of Room objects' do + @block.rooms.must_be_kind_of Array + @block.rooms.each do |room| + room.must_be_kind_of Hotel::Room + end + end + + it 'raises ArgumentError if passed invalid dates' do + proc { + Hotel::Block.new('sea','HAWKS', 5, 20) + }.must_raise ArgumentError + end + + it 'raises DatesError if dates are out of order' do + proc { + Hotel::Block.new('2017-08-08', '2017-08-03', 5, 20) + }.must_raise DatesError + end + + it 'raises DatesError if dates do not span at least 1 night' do + proc { + Hotel::Block.new('2017-08-06', '2017-08-06', 5, 20) + }.must_raise DatesError + end + + it 'has 0 >= n >= 1 discount_rate value' do + @block.discount_rate.must_equal 0.8 + end end describe 'includes_dates?' do @@ -37,4 +67,8 @@ includes_dates.must_equal false end end + + describe 'get_discount_rate' do + + end end From fda801534274ecbec9ee97f91ac40316aaee3d87 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 16:16:29 -0700 Subject: [PATCH 117/131] tentatively removing unused #range_with --- lib/date_range.rb | 27 ++++++++++----------------- specs/date_range_spec.rb | 2 +- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index 21ee3c43c..5390639e2 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -1,12 +1,18 @@ module DateRange require 'date' + def self.range_to(start_date, end_date) - find_range(start_date, end_date) + start_date = validate(start_date) + end_date = validate(end_date) + validate_order(start_date, end_date) + dates = [] + while start_date < end_date + dates << start_date + start_date += 1 + end + dates end - def self.range_with(start_date, end_date) - find_range(start_date, end_date, :inclusive) - end def self.overlap?(first_start, first_end, second_start, second_end) first_start = validate(first_start) @@ -57,17 +63,4 @@ def self.validate(input) raise(ArgumentError, "Input #{input.class} cannot be converted into Date") end end - - def self.find_range(start_date, end_date, flag = false) - start_date = validate(start_date) - end_date = validate(end_date) - validate_order(start_date, end_date) - dates = [] - while start_date < end_date - dates << start_date - start_date += 1 - end - dates << end_date if flag == :inclusive - dates - end end diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index 3b3e42aec..e66822fea 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -31,7 +31,7 @@ end end - describe 'self.range_with' do + xdescribe 'self.range_with' do it 'raises ArgumentError if start date is after end date' do proc { DateRange.range_with(@after, @before) From 07fb17f3eb1181e0ff55a1a8484ed84a1cc261ca Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 16:25:39 -0700 Subject: [PATCH 118/131] edge tests for #includes_dates? --- specs/block_spec.rb | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 4c8c85465..296aedcfd 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -66,9 +66,32 @@ includes_dates.must_equal false end - end - describe 'get_discount_rate' do + it 'raises ArgumentError if passed invalid dates' do + proc { + @block.includes_dates?('sea','HAWKS') + }.must_raise ArgumentError + end + it 'raises DatesError if dates are out of order' do + proc { + @block.includes_dates?('2017-08-08', '2017-08-03') + }.must_raise DatesError + end + + it 'raises DatesError if dates do not span at least 1 night' do + proc { + @block.includes_dates?('2017-08-06', '2017-08-06') + }.must_raise DatesError + end + end + + xdescribe 'get_discount_rate' do + it 'converts percentage number into equivalent Float' do + @block.get_discount_rate(80).must_equal 0.2 + @block.get_discount_rate(75).must_equal 0.25 + @block.get_discount_rate(10).must_equal 0.9 + @block.get_discount_rate(12.5).must_equal 0.875r + end end end From 0fc3390c4250d56ed2864723ee8abf868e0b4778 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 16:28:24 -0700 Subject: [PATCH 119/131] edge tests for #get_discount_rate --- specs/block_spec.rb | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/specs/block_spec.rb b/specs/block_spec.rb index 296aedcfd..5e1bdc99a 100644 --- a/specs/block_spec.rb +++ b/specs/block_spec.rb @@ -86,12 +86,41 @@ end end - xdescribe 'get_discount_rate' do + describe 'get_discount_rate' do it 'converts percentage number into equivalent Float' do @block.get_discount_rate(80).must_equal 0.2 @block.get_discount_rate(75).must_equal 0.25 @block.get_discount_rate(10).must_equal 0.9 @block.get_discount_rate(12.5).must_equal 0.875r end + + it 'can convert 0 or 100' do + @block.get_discount_rate(0).must_equal 1 + @block.get_discount_rate(100).must_equal 0 + end + + it 'raises DiscountError if given discount that is not 0-100' do + proc { + @block.get_discount_rate(125) + }.must_raise DiscountError + + proc { + @block.get_discount_rate(-25) + }.must_raise DiscountError + end + + it 'raises ArgumentError if given discount that is not a number' do + proc { + @block.get_discount_rate('hello') + }.must_raise ArgumentError + + proc { + @block.get_discount_rate(true) + }.must_raise ArgumentError + + proc { + @block.get_discount_rate(nil) + }.must_raise ArgumentError + end end end From 836a997481ad2c4d1bf620cfdaae33f206aeac3e Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 16:37:03 -0700 Subject: [PATCH 120/131] removed unnecessary methods to consolidate self.range_to --- lib/date_range.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/date_range.rb b/lib/date_range.rb index 5390639e2..37d7d9cfd 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -13,7 +13,6 @@ def self.range_to(start_date, end_date) dates end - def self.overlap?(first_start, first_end, second_start, second_end) first_start = validate(first_start) first_end = validate(first_end) From e299acff706a4ace0b09ba7c360bfafe97e12388 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 16:37:28 -0700 Subject: [PATCH 121/131] edge tests for #range_to, #overlap? and #include_all? --- specs/date_range_spec.rb | 91 +++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index e66822fea..f49aa1a23 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -7,12 +7,6 @@ end describe 'self.range_to' do - it 'raises DatesError if start date is after end date' do - proc { - DateRange.range_to(@after, @before) - }.must_raise DatesError - end - it 'returns an array of Dates' do dates = DateRange.range_to(@before, @after) @@ -29,30 +23,23 @@ dates.first.strftime.must_equal '2017-10-01' dates.last.strftime.must_equal '2017-10-13' end - end - xdescribe 'self.range_with' do - it 'raises ArgumentError if start date is after end date' do + it 'raises DatesError if start date is after end date' do proc { - DateRange.range_with(@after, @before) + DateRange.range_to(@after, @before) }.must_raise DatesError end - it 'returns an array of Dates' do - dates = DateRange.range_with(@before, @after) - - dates.must_be_kind_of Array - - dates.each do |date| - date.must_be_kind_of Date - end + it 'raises DatesError if dates do not span at least 1 night' do + proc { + DateRange.range_to(@before, @before) + }.must_raise DatesError end - it 'includes all dates up to AND including the end date' do - dates = DateRange.range_with(@before, @after) - - dates.first.strftime.must_equal '2017-10-01' - dates.last.strftime.must_equal '2017-10-14' + it 'raises ArgumentError if passed invalid dates' do + proc { + DateRange.range_to('sea', 'HAWKS') + }.must_raise ArgumentError end end @@ -76,9 +63,35 @@ overlap = DateRange.overlap?('2017-09-06', '2017-09-10', '2017-09-10', '2017-09-20') overlap.must_equal false end + + it 'raises DatesError if either start date is after end date' do + proc { + DateRange.overlap?(@after, @before, @before, @after) + }.must_raise DatesError + + proc { + DateRange.overlap?(@before, @after, @after, @before) + }.must_raise DatesError + end + + it 'raises DatesError if either dates do not span at least 1 night' do + proc { + DateRange.overlap?(@before, @before, @before, @after) + }.must_raise DatesError + + proc { + DateRange.overlap?(@before, @after, @before, @before) + }.must_raise DatesError + end + + it 'raises ArgumentError if passed invalid dates' do + proc { + DateRange.overlap?(@before, @after, 'before', 'after') + }.must_raise ArgumentError + end end - describe '#include_all?' do + describe 'self.include_all?' do it 'returns true if all searched dates fall within container range' do include_all = DateRange.include_all?('2017-10-10', '2017-10-14', @before, @after) @@ -96,6 +109,32 @@ include_all.must_equal false end + + it 'raises DatesError if either start date is after end date' do + proc { + DateRange.include_all?(@after, @before, @before, @after) + }.must_raise DatesError + + proc { + DateRange.include_all?(@before, @after, @after, @before) + }.must_raise DatesError + end + + it 'raises DatesError if either dates do not span at least 1 night' do + proc { + DateRange.include_all?(@before, @before, @before, @after) + }.must_raise DatesError + + proc { + DateRange.include_all?(@before, @after, @before, @before) + }.must_raise DatesError + end + + it 'raises ArgumentError if passed invalid dates' do + proc { + DateRange.include_all?(@before, @after, 'before', 'after') + }.must_raise ArgumentError + end end describe 'self.validate' do @@ -115,4 +154,8 @@ }.must_raise ArgumentError end end + + describe 'self.validate_order' do + + end end From be990e7aa61cf2d7beec28c29e67f77fafaa595a Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 16:42:07 -0700 Subject: [PATCH 122/131] self.validate_order returns true if input is correct --- lib/date_range.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/date_range.rb b/lib/date_range.rb index 37d7d9cfd..1fb3462b8 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -51,6 +51,7 @@ def self.validate_order(first, second) unless first < second raise(DatesError, 'Start date must be at least 1 day before end date') end + true end def self.validate(input) From 5a91bf47298d8c7965f3398cfe259f6ef936e465 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 16:48:01 -0700 Subject: [PATCH 123/131] edge tests for #validate_order --- specs/date_range_spec.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index f49aa1a23..82c92df43 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -138,6 +138,7 @@ end describe 'self.validate' do + # TODO: edge tests it 'returns input unchanged if input is a Date object' do DateRange.validate(@before).must_equal @before end @@ -156,6 +157,26 @@ end describe 'self.validate_order' do + it 'returns true if it is two dates in correct order' do + DateRange.validate_order(@before, @after).must_equal true + end + it 'raises DatesError if input is two dates in incorrect order' do + proc { + DateRange.validate_order(@after, @before) + }.must_raise DatesError + end + + it 'raises DatesError if input dates do not span at least 1 night' do + proc { + DateRange.validate_order(@after, @after) + }.must_raise DatesError + end + + it 'raises ArgumentError if passed invalid dates' do + proc { + DateRange.validate_order('sea', 'HAWKS') + }.must_raise ArgumentError + end end end From 00b65d8cac395ccf2c5bbfadab8017e895a618c3 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 10 Sep 2017 16:49:15 -0700 Subject: [PATCH 124/131] edge tests for #validate --- specs/date_range_spec.rb | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index 82c92df43..9f3f96359 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -138,7 +138,6 @@ end describe 'self.validate' do - # TODO: edge tests it 'returns input unchanged if input is a Date object' do DateRange.validate(@before).must_equal @before end @@ -149,10 +148,20 @@ date.month.must_equal 10 end - it 'raises an exception if input is neither Date or String' do + it 'raises ArgumentError if input is neither Date or String' do proc { DateRange.validate(2017_10_14) }.must_raise ArgumentError + + proc { + DateRange.validate(true) + }.must_raise ArgumentError + end + + it 'raises ArgumentError if passed invalid String format' do + proc { + DateRange.validate('my birthday') + }.must_raise ArgumentError end end From 450c168d4023106920e9b8beb9342dd0abcdf630 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Mon, 11 Sep 2017 08:52:48 -0700 Subject: [PATCH 125/131] add test for block dates logic --- specs/hotel_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index 661cfaa3c..a30b07807 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -374,6 +374,12 @@ end end + it 'can begin a block the day another block ends' do + block2 = @hotel.make_block('2017-08-07', '2017-08-10', 10, 20) + + @block.rooms.must_equal block2.rooms + end + it 'raises NoRoomError when there are not enough rooms to fill a block' do proc { @hotel.make_block('2017-08-03', '2017-08-07', 11, 20) From de2755e294164e0a082113b52000dade0fde99b8 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Mon, 11 Sep 2017 08:52:58 -0700 Subject: [PATCH 126/131] add design.md to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5e1422c9c..250b680c9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ /test/tmp/ /test/version_tmp/ /tmp/ +design.md # Used by dotenv library to load environment variables. # .env From da4f5b5171492125f57745edc6bf93959cd8ab9d Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 28 Sep 2017 12:21:04 -0700 Subject: [PATCH 127/131] ShoppingCart design activity --- design-activity.md | 103 +++++++++++++++++++++++++++++++++++++++++++ specs/spec_helper.rb | 2 + 2 files changed, 105 insertions(+) create mode 100644 design-activity.md diff --git a/design-activity.md b/design-activity.md new file mode 100644 index 000000000..3b4fbb5d2 --- /dev/null +++ b/design-activity.md @@ -0,0 +1,103 @@ +### Activity +##### What classes does each implementation include? Are the lists the same? + +Yes, they are the same. Both implementations have: + * CartEntry + * ShoppingCart + * Order + + +##### Write down a sentence to describe each class. + +Implementation A: +* CartEntry + * Contains basic pricing info entry +* ShoppingCart + * Contains CartEntry objects +* Order + * Contains and totals a ShoppingCart object + +Implementation B: +* CartEntry + * Manages all pricing info of a single entry +* ShoppingCart + * Contains and totals CartEntry objects +* Order + * Contains and totals ShoppingCart, accounting for sales tax + +##### How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper. +* Order _has a_ ShoppingCart +* ShoppingCart _has many_ CartEntries + +##### What data does each class store? How (if at all) does this differ between the two implementations? +Implementation A: +* CartEntry + * Unit price + * Unit quantity +* ShoppingCart + * List of CartEntries +* Order + * ShoppingCart + * Total price of all CartEntries in ShoppingCart + +Implementation B: +* CartEntry + * Unit price + * Unit quantity + * Total entry price +* ShoppingCart + * List of CartEntries + * Total of all CartEntry prices +* Order + * ShoppingCart + * Total price of ShoppingCart with tax + +##### What methods does each class have? How (if at all) does this differ between the two implementations? +Implementation A: +* CartEntry + * #unit_price + * #quantity +* ShoppingCart + * #entries +* Order + * #cart + * #total_price + +Implementation B: +* CartEntry + * #price +* ShoppingCart + * #price +* Order + * #total_price + +Implementation A uses attr_accessor methods to make all of the data contained within each class publicly accessible. Implementation B keeps this data private and uses a #price method on CartEntry and ShoppingCart classes to return only the necessary information (in this case, price). + +##### Consider the Order#totalprice 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? + +Implementation A requires the Order#total_price method to dig through the ShoppingCart class and into the CartEntry class to directly access its variables, while Implementation B takes the returned value of ShoppingCart#price and performs its logic around that. + +##### Does totalprice directly manipulate the instance variables of other classes? + +Implementation A directly reads the instance variables of the ShoppingCart and CartEntry classes, though it does not modify them. Implementation B does not directly read or modify any other class' instance variables. + +##### If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify? + +Implementation B would be easier to modify, as this change would only affect the CartEntry class, which could be updated to modify price based on quantity. In Implementation A, this would require the Order#total_price method to perform this additional logic within the same method where it is already calculating the total _and_ applying sales tax. + +##### Which implementation better adheres to the single responsibility principle? + +Implementation B better adheres to this principle, as each class manages and encapsulates its relevant information. + +##### Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? + +### Revisiting Hotel + +#### Class +##### What is this class's responsibility? +##### You should be able to describe it in a single sentence. +##### Is this class responsible for exactly one thing? +##### Does this class take on any responsibility that should be delegated to "lower level" classes? +##### Is there code in other classes that directly manipulates this class's instance variables? diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb index 01810940f..c9d0edfe5 100644 --- a/specs/spec_helper.rb +++ b/specs/spec_helper.rb @@ -1,9 +1,11 @@ require 'simplecov' SimpleCov.start +gem 'minitest', '>= 5.0.0' require 'minitest/autorun' require 'minitest/reporters' require 'minitest/skip_dsl' +require 'minitest/pride' require_relative '../lib/hotel.rb' require_relative '../lib/block.rb' # require_relative '../lib/date_range.rb' From 7253647003d184177d7d15a55c1941eafb368f56 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 28 Sep 2017 13:09:20 -0700 Subject: [PATCH 128/131] remove unnecessary input validation in #initialize --- lib/hotel.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/hotel.rb b/lib/hotel.rb index 05b35632a..6ffaed60e 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -14,10 +14,6 @@ class Hotel def initialize(num_rooms) @rooms = [] - unless num_rooms.class == Integer - raise(ArgumentError, "Number of rooms parameter must be Integer: #{num_rooms}") - end - num_rooms.times do |i| @rooms << Room.new(i + 1, ROOM_COST) end From 007a5d1529a3ae4fe4dfbc3cb6d0bef196a1ba88 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Thu, 28 Sep 2017 13:10:01 -0700 Subject: [PATCH 129/131] complete Revisiting Hotel portion --- design-activity.md | 48 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/design-activity.md b/design-activity.md index 3b4fbb5d2..faa76fe0b 100644 --- a/design-activity.md +++ b/design-activity.md @@ -94,10 +94,52 @@ Implementation B better adheres to this principle, as each class manages and enc ##### Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? ### Revisiting Hotel +#### Block +##### What is this class's responsibility? (You should be able to describe it in a single sentence.) +Contains & manages necessary information for a block reservation +##### Is this class responsible for exactly one thing? +Yes +##### Does this class take on any responsibility that should be delegated to "lower level" classes? +No +##### Is there code in other classes that directly manipulates this class's instance variables? +No - Reservation reads the #discount_rate variable but does not manipulate it + +#### Hotel +##### What is this class's responsibility? (You should be able to describe it in a single sentence.) +Contains and manages all types of reservations +##### Is this class responsible for exactly one thing? +Yes +##### Does this class take on any responsibility that should be delegated to "lower level" classes? +No? Room rates are currently set by the ROOM_COST constant (as room cost is always 200/night) within the Hotel class, while theoretically if these were to change they would have to come from somewhere else, but would probably still be accessed/assigned within the Hotel#initialize method. +##### Is there code in other classes that directly manipulates this class's instance variables? +No + +#### Reservation +##### What is this class's responsibility? (You should be able to describe it in a single sentence.) +Contains & manages necessary information for a room reservation +##### Is this class responsible for exactly one thing? +Yes +##### Does this class take on any responsibility that should be delegated to "lower level" classes? +No +##### Is there code in other classes that directly manipulates this class's instance variables? +No + +#### Room +##### What is this class's responsibility? (You should be able to describe it in a single sentence.) +Contain basic data on a given room +##### Is this class responsible for exactly one thing? +Yes +##### Does this class take on any responsibility that should be delegated to "lower level" classes? +No +##### Is there code in other classes that directly manipulates this class's instance variables? +No -#### Class -##### What is this class's responsibility? -##### You should be able to describe it in a single sentence. +#### DateRange (module) +##### What is this class's responsibility? (You should be able to describe it in a single sentence.) +Provide necessary methods for working with ranges of dates ##### Is this class responsible for exactly one thing? +Yes ##### Does this class take on any responsibility that should be delegated to "lower level" classes? +No? One method (#validate) might be better off being added to the Date class ##### Is there code in other classes that directly manipulates this class's instance variables? +No (n/a) From a84a19d80247a3d446f82ed73ca10d671d432047 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 1 Oct 2017 18:53:48 -0700 Subject: [PATCH 130/131] REFACTOR: moved DateRange.validate method to Date class --- design-activity.md | 2 +- lib/date_range.rb | 26 ++++++++++++++------------ lib/hotel.rb | 2 +- lib/reservation.rb | 4 ++-- specs/date_range_spec.rb | 10 +++++----- specs/hotel_spec.rb | 8 ++++---- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/design-activity.md b/design-activity.md index faa76fe0b..bf61d2755 100644 --- a/design-activity.md +++ b/design-activity.md @@ -140,6 +140,6 @@ Provide necessary methods for working with ranges of dates ##### Is this class responsible for exactly one thing? Yes ##### Does this class take on any responsibility that should be delegated to "lower level" classes? -No? One method (#validate) might be better off being added to the Date class +Not necessarily, but one method (#validate) might be better off being added to the Date class, as it only deals with one date and not a range ##### Is there code in other classes that directly manipulates this class's instance variables? No (n/a) diff --git a/lib/date_range.rb b/lib/date_range.rb index 1fb3462b8..98f2c674f 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -2,8 +2,8 @@ module DateRange require 'date' def self.range_to(start_date, end_date) - start_date = validate(start_date) - end_date = validate(end_date) + start_date = Date.validate(start_date) + end_date = Date.validate(end_date) validate_order(start_date, end_date) dates = [] while start_date < end_date @@ -14,10 +14,10 @@ def self.range_to(start_date, end_date) end def self.overlap?(first_start, first_end, second_start, second_end) - first_start = validate(first_start) - first_end = validate(first_end) - second_start = validate(second_start) - second_end = validate(second_end) + first_start = Date.validate(first_start) + first_end = Date.validate(first_end) + second_start = Date.validate(second_start) + second_end = Date.validate(second_end) first_dates = DateRange.range_to(first_start, first_end) second_dates = DateRange.range_to(second_start, second_end) @@ -31,10 +31,10 @@ def self.overlap?(first_start, first_end, second_start, second_end) end def self.include_all?(search_start, search_end, contain_start, contain_end) - search_start = validate(search_start) - search_end = validate(search_end) - contain_start = validate(contain_start) - contain_end = validate(contain_end) + search_start = Date.validate(search_start) + search_end = Date.validate(search_end) + contain_start = Date.validate(contain_start) + contain_end = Date.validate(contain_end) search_dates = DateRange.range_to(search_start, search_end) contain_dates = DateRange.range_to(contain_start, contain_end) @@ -46,14 +46,16 @@ def self.include_all?(search_start, search_end, contain_start, contain_end) end def self.validate_order(first, second) - first = validate(first) - second = validate(second) + first = Date.validate(first) + second = Date.validate(second) unless first < second raise(DatesError, 'Start date must be at least 1 day before end date') end true end +end +class Date def self.validate(input) if input.class == Date return input diff --git a/lib/hotel.rb b/lib/hotel.rb index 6ffaed60e..8cfe30c9f 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -44,7 +44,7 @@ def make_block(start_date, end_date, num_rooms, discount = 0) end def view_reservations(date) - date = DateRange.validate(date) + date = Date.validate(date) reservations = [] @reservations.each do |reservation| reservations << reservation if reservation.dates.include?(date) diff --git a/lib/reservation.rb b/lib/reservation.rb index 317a746eb..ab5c32291 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -7,8 +7,8 @@ class Reservation def initialize(room, checkin, checkout, hotel, block = false) @room = room - @checkin = DateRange.validate(checkin) - @checkout = DateRange.validate(checkout) + @checkin = Date.validate(checkin) + @checkout = Date.validate(checkout) @dates = DateRange.range_to(@checkin, @checkout) if block @block = hotel.block(block) diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index 9f3f96359..1f70aa9a2 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -139,28 +139,28 @@ describe 'self.validate' do it 'returns input unchanged if input is a Date object' do - DateRange.validate(@before).must_equal @before + Date.validate(@before).must_equal @before end it 'returns a Date object if input is a String' do - date = DateRange.validate('2017-10-14') + date = Date.validate('2017-10-14') date.must_be_kind_of Date date.month.must_equal 10 end it 'raises ArgumentError if input is neither Date or String' do proc { - DateRange.validate(2017_10_14) + Date.validate(2017_10_14) }.must_raise ArgumentError proc { - DateRange.validate(true) + Date.validate(true) }.must_raise ArgumentError end it 'raises ArgumentError if passed invalid String format' do proc { - DateRange.validate('my birthday') + Date.validate('my birthday') }.must_raise ArgumentError end end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index a30b07807..23f5c5ae7 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -31,18 +31,18 @@ hotel.rooms[0].must_be_kind_of Hotel::Room end - it 'raises ArgumentError if passed anything but an Integer' do + it 'raises NoMethodError if passed anything but an Integer' do proc { Hotel::Hotel.new('hi') - }.must_raise ArgumentError + }.must_raise NoMethodError proc { Hotel::Hotel.new(nil) - }.must_raise ArgumentError + }.must_raise NoMethodError proc { Hotel::Hotel.new(4.0) - }.must_raise ArgumentError + }.must_raise NoMethodError end end From e65e5ea1c4350bf16d1c126353a007da33eb4e11 Mon Sep 17 00:00:00 2001 From: Kate Evans-Spitzer Date: Sun, 1 Oct 2017 18:53:48 -0700 Subject: [PATCH 131/131] REFACTOR: moved DateRange.validate method to Date class --- design-activity.md | 52 +++------------------------------------- lib/date_range.rb | 26 ++++++++++---------- lib/hotel.rb | 2 +- lib/reservation.rb | 4 ++-- specs/date_range_spec.rb | 10 ++++---- specs/hotel_spec.rb | 8 +++---- 6 files changed, 29 insertions(+), 73 deletions(-) diff --git a/design-activity.md b/design-activity.md index faa76fe0b..db74ece3e 100644 --- a/design-activity.md +++ b/design-activity.md @@ -94,52 +94,6 @@ Implementation B better adheres to this principle, as each class manages and enc ##### Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? ### Revisiting Hotel -#### Block -##### What is this class's responsibility? (You should be able to describe it in a single sentence.) -Contains & manages necessary information for a block reservation -##### Is this class responsible for exactly one thing? -Yes -##### Does this class take on any responsibility that should be delegated to "lower level" classes? -No -##### Is there code in other classes that directly manipulates this class's instance variables? -No - Reservation reads the #discount_rate variable but does not manipulate it - -#### Hotel -##### What is this class's responsibility? (You should be able to describe it in a single sentence.) -Contains and manages all types of reservations -##### Is this class responsible for exactly one thing? -Yes -##### Does this class take on any responsibility that should be delegated to "lower level" classes? -No? Room rates are currently set by the ROOM_COST constant (as room cost is always 200/night) within the Hotel class, while theoretically if these were to change they would have to come from somewhere else, but would probably still be accessed/assigned within the Hotel#initialize method. -##### Is there code in other classes that directly manipulates this class's instance variables? -No - -#### Reservation -##### What is this class's responsibility? (You should be able to describe it in a single sentence.) -Contains & manages necessary information for a room reservation -##### Is this class responsible for exactly one thing? -Yes -##### Does this class take on any responsibility that should be delegated to "lower level" classes? -No -##### Is there code in other classes that directly manipulates this class's instance variables? -No - -#### Room -##### What is this class's responsibility? (You should be able to describe it in a single sentence.) -Contain basic data on a given room -##### Is this class responsible for exactly one thing? -Yes -##### Does this class take on any responsibility that should be delegated to "lower level" classes? -No -##### Is there code in other classes that directly manipulates this class's instance variables? -No - -#### DateRange (module) -##### What is this class's responsibility? (You should be able to describe it in a single sentence.) -Provide necessary methods for working with ranges of dates -##### Is this class responsible for exactly one thing? -Yes -##### Does this class take on any responsibility that should be delegated to "lower level" classes? -No? One method (#validate) might be better off being added to the Date class -##### Is there code in other classes that directly manipulates this class's instance variables? -No (n/a) +Overall, I feel that I did a pretty good job of adhering to the single responsibility principle. The only thing that bothers me about my design is that the price of each room comes from a constant variable defined within the Hotel class, but since the current spec of the project is for all of the hotel's rooms to have a price of 200, I still think it makes the most sense for the time being. How I would refactor the code to account for varying room types would vary depending on how the rooms' prices were being determined, so there's nothing to change at the moment. + +The change I _did_ make was to remove the #validate method from the DateRange class. My thought process behind the change was that the method (which converts valid input into a Date object if it isn't already one) only interacts with one date, and therefore should be part of the Date class, not DateRange. diff --git a/lib/date_range.rb b/lib/date_range.rb index 1fb3462b8..98f2c674f 100644 --- a/lib/date_range.rb +++ b/lib/date_range.rb @@ -2,8 +2,8 @@ module DateRange require 'date' def self.range_to(start_date, end_date) - start_date = validate(start_date) - end_date = validate(end_date) + start_date = Date.validate(start_date) + end_date = Date.validate(end_date) validate_order(start_date, end_date) dates = [] while start_date < end_date @@ -14,10 +14,10 @@ def self.range_to(start_date, end_date) end def self.overlap?(first_start, first_end, second_start, second_end) - first_start = validate(first_start) - first_end = validate(first_end) - second_start = validate(second_start) - second_end = validate(second_end) + first_start = Date.validate(first_start) + first_end = Date.validate(first_end) + second_start = Date.validate(second_start) + second_end = Date.validate(second_end) first_dates = DateRange.range_to(first_start, first_end) second_dates = DateRange.range_to(second_start, second_end) @@ -31,10 +31,10 @@ def self.overlap?(first_start, first_end, second_start, second_end) end def self.include_all?(search_start, search_end, contain_start, contain_end) - search_start = validate(search_start) - search_end = validate(search_end) - contain_start = validate(contain_start) - contain_end = validate(contain_end) + search_start = Date.validate(search_start) + search_end = Date.validate(search_end) + contain_start = Date.validate(contain_start) + contain_end = Date.validate(contain_end) search_dates = DateRange.range_to(search_start, search_end) contain_dates = DateRange.range_to(contain_start, contain_end) @@ -46,14 +46,16 @@ def self.include_all?(search_start, search_end, contain_start, contain_end) end def self.validate_order(first, second) - first = validate(first) - second = validate(second) + first = Date.validate(first) + second = Date.validate(second) unless first < second raise(DatesError, 'Start date must be at least 1 day before end date') end true end +end +class Date def self.validate(input) if input.class == Date return input diff --git a/lib/hotel.rb b/lib/hotel.rb index 6ffaed60e..8cfe30c9f 100644 --- a/lib/hotel.rb +++ b/lib/hotel.rb @@ -44,7 +44,7 @@ def make_block(start_date, end_date, num_rooms, discount = 0) end def view_reservations(date) - date = DateRange.validate(date) + date = Date.validate(date) reservations = [] @reservations.each do |reservation| reservations << reservation if reservation.dates.include?(date) diff --git a/lib/reservation.rb b/lib/reservation.rb index 317a746eb..ab5c32291 100644 --- a/lib/reservation.rb +++ b/lib/reservation.rb @@ -7,8 +7,8 @@ class Reservation def initialize(room, checkin, checkout, hotel, block = false) @room = room - @checkin = DateRange.validate(checkin) - @checkout = DateRange.validate(checkout) + @checkin = Date.validate(checkin) + @checkout = Date.validate(checkout) @dates = DateRange.range_to(@checkin, @checkout) if block @block = hotel.block(block) diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb index 9f3f96359..1f70aa9a2 100644 --- a/specs/date_range_spec.rb +++ b/specs/date_range_spec.rb @@ -139,28 +139,28 @@ describe 'self.validate' do it 'returns input unchanged if input is a Date object' do - DateRange.validate(@before).must_equal @before + Date.validate(@before).must_equal @before end it 'returns a Date object if input is a String' do - date = DateRange.validate('2017-10-14') + date = Date.validate('2017-10-14') date.must_be_kind_of Date date.month.must_equal 10 end it 'raises ArgumentError if input is neither Date or String' do proc { - DateRange.validate(2017_10_14) + Date.validate(2017_10_14) }.must_raise ArgumentError proc { - DateRange.validate(true) + Date.validate(true) }.must_raise ArgumentError end it 'raises ArgumentError if passed invalid String format' do proc { - DateRange.validate('my birthday') + Date.validate('my birthday') }.must_raise ArgumentError end end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb index a30b07807..23f5c5ae7 100644 --- a/specs/hotel_spec.rb +++ b/specs/hotel_spec.rb @@ -31,18 +31,18 @@ hotel.rooms[0].must_be_kind_of Hotel::Room end - it 'raises ArgumentError if passed anything but an Integer' do + it 'raises NoMethodError if passed anything but an Integer' do proc { Hotel::Hotel.new('hi') - }.must_raise ArgumentError + }.must_raise NoMethodError proc { Hotel::Hotel.new(nil) - }.must_raise ArgumentError + }.must_raise NoMethodError proc { Hotel::Hotel.new(4.0) - }.must_raise ArgumentError + }.must_raise NoMethodError end end