diff --git a/lib/date_range.rb b/lib/date_range.rb new file mode 100644 index 000000000..8ac4d6df2 --- /dev/null +++ b/lib/date_range.rb @@ -0,0 +1,23 @@ +require "date" + +module Hotel + class DateRange + attr_reader :start_date, :end_date + + def initialize(start_date, end_date) + raise(ArgumentError, "The end date #{end_date} is smaller or same as the start date #{start_date}.") unless end_date > start_date + @start_date = start_date + @end_date = end_date + end + + #for future refactoring- does_match_date(date) + #this method will elaborate on the current method so it takes a date and returns a true or flase depending on if that date exists/overlaps all the days in the date range + def all_dates + return (@start_date...@end_date).to_a + end + + def duration + return all_dates.length + end + end +end diff --git a/lib/front_desk.rb b/lib/front_desk.rb new file mode 100644 index 000000000..bd3c62951 --- /dev/null +++ b/lib/front_desk.rb @@ -0,0 +1,45 @@ +module Hotel + class FrontDesk + attr_reader :all_rooms, :all_reservations + + def initialize + @all_rooms = [] + 20.times do |i| + @all_rooms << Hotel::Room.new("room #{i + 1}") #instantiate Room object + end + + @all_reservations = [] + end + + def list_of_available_rooms(start_date, end_date) + return @all_rooms.select do |room| + room.is_available_during(start_date, end_date) + end + end + + def reserve_room(start_date, end_date, guest_name:, room:) + raise(ArgumentError, "This room #{room} does not exist in our hotel:(") unless @all_rooms.any? do |individual_room| + individual_room.room_number == room + end + + reservation_room = @all_rooms.find do |room_object| + room_object.room_number == room + end + raise(ArgumentError, "This room #{room} is unavailable for reservation for given dates #{start_date} - #{end_date}") unless reservation_room.is_available_during(start_date, end_date) + + new_res = Hotel::Reservation.new(start_date, end_date, guest_name: guest_name, room: room) + + reservation_room.add_reservation_to_room(new_res) + @all_reservations << new_res + return new_res + end + + def list_of_reservations(date) + return @all_reservations.select do |reservation| + reservation.reservation_dates.all_dates.any? do |day| + date == day + end + end + end + end +end diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..5db550ee6 --- /dev/null +++ b/lib/reservation.rb @@ -0,0 +1,19 @@ +module Hotel + class Reservation + attr_reader :room, :guest_name + def initialize(start_date, end_date, room:, guest_name:) + @start_date = start_date + @end_date = end_date + @room = room + @guest_name = guest_name.to_s + end + + def reservation_dates + return Hotel::DateRange.new(@start_date, @end_date) + end + + def cost + return reservation_dates.duration * 200 + end + end +end diff --git a/lib/room.rb b/lib/room.rb new file mode 100644 index 000000000..d23cf4003 --- /dev/null +++ b/lib/room.rb @@ -0,0 +1,33 @@ +module Hotel + class Room + attr_reader :room_number, :room_reservations + + def initialize(room_number) + @room_number = room_number + @room_reservations = [] + end + + def add_reservation_to_room(reservation) + raise(ArgumentError, "this reservation#{reservation} is not for #{@room_number}.") unless reservation.room == @room_number + @room_reservations << reservation + end + + #refactoring + #combine dates_unavailable and is_available_during method so the method only outputs true or false depending on it's availability + def dates_unavailable + dates_booked = @room_reservations.map do |reservation| + reservation.reservation_dates.all_dates + end + return dates_booked.flatten + end + + def is_available_during(start_date, end_date) + test_date_range = (start_date...end_date).to_a + if (dates_unavailable & test_date_range).length > 0 + return false + else + return true + end + end + end +end diff --git a/refactors.txt b/refactors.txt new file mode 100644 index 000000000..4e081a20d --- /dev/null +++ b/refactors.txt @@ -0,0 +1,13 @@ +change the method in date range to does_match(date) - this will return true or false depening if the date is included in the date range array +combine the dates_unavailable and is_available_during methods into one method +room probably doesn't need to keep track of it's reservations- only reservation should know about room since room doesn't change whereas reservation does + +overall- keep methods that belong to a class within that class to iliminate the dependency between classes + + + + + + + +write wave 3- make a block reservation class diff --git a/test/date_range_test.rb b/test/date_range_test.rb new file mode 100644 index 000000000..2eb4af1f7 --- /dev/null +++ b/test/date_range_test.rb @@ -0,0 +1,63 @@ +require_relative "test_helper" + +describe "DateRange" do + before do + @start_date = Date.new(2020, 2, 2) + @end_date = Date.new(2020, 2, 5) + @date = Hotel::DateRange.new(@start_date, @end_date) + @all_dates = [Date.new(2020, 2, 2), Date.new(2020, 2, 3), Date.new(2020, 2, 4)] + end + + describe "initialize" do + it "Should create an instance of DateRange when given a start_date and end_date" do + expect(@date).must_be_instance_of Hotel::DateRange + end + it "Should keep track of start and end date" do + expect(@date.start_date).must_equal @start_date + expect(@date.end_date).must_equal @end_date + end + it "Raises an ArgumentError if end_date is before start_date" do + start_date = Date.new(2020, 2, 2) + end_date = start_date - 3 + expect { Hotel::DateRange.new(start_date, end_date) }.must_raise ArgumentError + end + it "Raises an ArgumentError for 0-length date range" do + start_date = Date.new(2020, 2, 2) + end_date = start_date + expect { Hotel::DateRange.new(start_date, end_date) }.must_raise ArgumentError + end + end + + describe "duration" do + it "Should have the .duration method" do + expect(@date).must_respond_to :duration + end + + it "Should calculate the correct amount of durations" do + expect(@date.duration).must_equal 3 + end + end + + describe "all_dates" do + it "Should have the .all_dates method" do + expect(@date).must_respond_to :all_dates + end + + it "Should give an array of all dates" do + expect(@date.all_dates).must_equal @all_dates + expect(@date.all_dates).must_be_kind_of Array + end + + it "Should include date that exists within date range" do + expect(@date.all_dates).must_include Date.new(2020, 2, 3) + end + + it "Should not include the departure date" do + expect(@date.all_dates).wont_include @end_date + end + + it "Should include the arrival date" do + expect(@date.all_dates).must_include @start_date + end + end +end diff --git a/test/front_desk_test.rb b/test/front_desk_test.rb new file mode 100644 index 000000000..a7ca5ca21 --- /dev/null +++ b/test/front_desk_test.rb @@ -0,0 +1,114 @@ +require_relative "test_helper" + +describe "front_desk" do + before do + @pineapple_villa = Hotel::FrontDesk.new() + + @start_date = Date.new(2020, 2, 2) + @end_date = @start_date + 3 + + @spongebob_reservation = @pineapple_villa.reserve_room(@start_date, @end_date, guest_name: "spongebob squarepants", room: "room 2") + + @patrick_reservation = @pineapple_villa.reserve_room(@start_date, @end_date, guest_name: "patrick star", room: "room 1") + + @room_1 = @pineapple_villa.all_rooms.find do |room_object| + room_object.room_number == "room 1" + end + + @room_2 = @pineapple_villa.all_rooms.find do |room_object| + room_object.room_number == "room 2" + end + + @list_of_reservation_for_given_date = @pineapple_villa.list_of_reservations(@start_date) + end + + describe "initiate" do + it "Should be instantiated with no given Arguments" do + expect(@pineapple_villa).must_be_instance_of Hotel::FrontDesk + end + end + + describe "instance variable" do + it "Should have all_reservations that is an array of all hotel reservations" do + expect(@pineapple_villa).must_respond_to :all_reservations + expect(@pineapple_villa.all_reservations).must_be_kind_of Array + @pineapple_villa.all_reservations.each do |reservation| + expect(reservation).must_be_instance_of Hotel::Reservation + end + end + + it "Should have a list of all rooms" do + expect(@pineapple_villa).must_respond_to :all_rooms + expect(@pineapple_villa.all_rooms.length).must_equal 20 + end + + it "all_rooms should contain instances of Room object" do + @pineapple_villa.all_rooms.each do |room| + expect(room).must_be_instance_of Hotel::Room + end + end + end + + describe "list_of_available_rooms(start_date, end_date)" do + it "Should return an array of all available rooms given that date range" do + start_date = Date.new(2020, 2, 14) + end_date = start_date + 1 + expect(@pineapple_villa.list_of_available_rooms(start_date, end_date).length).must_equal 20 + end + + it "Should reject all the rooms reserved within the date range given" do + start_date = Date.new(2020, 2, 3) + end_date = Date.new(2020, 2, 5) + expect(@pineapple_villa.list_of_available_rooms(start_date, end_date)).wont_include @room_1 + expect(@pineapple_villa.list_of_available_rooms(start_date, end_date)).wont_include @room_2 + expect(@pineapple_villa.list_of_available_rooms(start_date, end_date).length).must_equal 18 + end + end + + describe "reserve_room" do + before do + end + it "Should create an instance of Reservation when given start_date, end_date, guest_name, room " do + expect(@spongebob_reservation).must_be_kind_of Hotel::Reservation + expect(@pineapple_villa.all_reservations).must_include @spongebob_reservation + end + + it "Should raise an ArgumentError when given a wrong room number" do + start_date = Date.new(2020, 2, 1) + end_date = Date.new(2020, 2, 3) + guest_name = "Sandy Cheeks" + room = "room 99" + expect { @pineapple_villa.reserve_room(start_date, end_date, guest_name: guest_name, room: room) }.must_raise ArgumentError + end + + it "Should raise an ArgumentError if the date range is taken for that room" do + start_date = Date.new(2020, 2, 3) + end_date = start_date + 1 + guest_name = "Sandy Cheeks" + room = "room 2" + expect { @pineapple_villa.reserve_room(start_date, end_date, guest_name: guest_name, room: room) }.must_raise ArgumentError + end + + it "should add the reservation to the rooms reservation list" do + expect(@room_1.room_reservations).must_include @patrick_reservation + expect(@room_2.room_reservations).must_include @spongebob_reservation + end + + it "the reservation list of a room must be for that room only" do + @room_1.room_reservations.each do |reservation| + expect(reservation.room).must_equal "room 1" + end + end + + it "Should add the reservation to the Hotel's total reservations" do + expect(@pineapple_villa.all_reservations).must_include @spongebob_reservation + expect(@pineapple_villa.all_reservations).must_include @patrick_reservation + end + end + + describe "list_of_reservations(date)" do + it "Should return a list of Reservations for that date" do + expect(@list_of_reservation_for_given_date).must_equal [@spongebob_reservation, @patrick_reservation] + end + end +end diff --git a/test/reservation_test.rb b/test/reservation_test.rb new file mode 100644 index 000000000..2d243f30f --- /dev/null +++ b/test/reservation_test.rb @@ -0,0 +1,49 @@ +require_relative "test_helper" + +describe "Reservation" do + before do + @start_date = Date.new(2020, 2, 2) + @end_date = @start_date + 3 + @room = "room 3" + @guest_name = "Mair Heshmati" + @reserve = Hotel::Reservation.new(@start_date, @end_date, room: @room, guest_name: @guest_name) + end + + describe "Initialize" do + it "should create an instance of Reservation" do + expect(@reserve).must_be_instance_of Hotel::Reservation + end + + it "Takes in and keeps track of the start and end date, the desired room number and guest name" do + expect(@reserve.instance_variable_get(:@start_date)).must_equal @start_date + expect(@reserve.instance_variable_get(:@end_date)).must_equal @end_date + #make sure the start and end date is being set as instance variables + + expect(@reserve).must_respond_to :room + expect(@reserve.room).must_equal @room + + expect(@reserve).must_respond_to :guest_name + expect(@reserve.guest_name).must_equal @guest_name + end + end + describe "reservation_dates" do + it "Should instantiate an instance of DateRange given start and end date" do + expect(@reserve).must_respond_to :reservation_dates + expect(@reserve.reservation_dates).must_be_instance_of Hotel::DateRange + end + + it "Should have the correct arrival date" do + expect(@reserve.reservation_dates.start_date).must_equal @start_date + end + + it "should have the correct departure date" do + expect(@reserve.reservation_dates.end_date).must_equal @end_date + end + end + + describe "cost" do + it "Calculates the correct amount of cost for reservation duration" do + expect(@reserve.cost).must_equal 600 + end + end +end diff --git a/test/room_test.rb b/test/room_test.rb new file mode 100644 index 000000000..a6732fede --- /dev/null +++ b/test/room_test.rb @@ -0,0 +1,88 @@ +require_relative "test_helper" + +describe "Room" do + before do + @my_room = Hotel::Room.new("room 1") + + @patrick_reservation = Hotel::Reservation.new( + start_date = Date.new(2020, 2, 2), + end_date = start_date + 3, + room: "room 1", + guest_name: "patrick star", + ) + + @spongebob_reservation = Hotel::Reservation.new( + start_date = Date.new(2020, 2, 5), + end_date = start_date + 1, + room: "room 1", + guest_name: "spongebob squarepants", + ) + + @my_room.add_reservation_to_room(@patrick_reservation) + @my_room.add_reservation_to_room(@spongebob_reservation) + end + + describe "Initialize" do + it "Should be initialized when given a room number" do + expect(@my_room).must_be_instance_of Hotel::Room + end + + it "Should have room_number and room_reservations (array) as instance variables" do + expect(@my_room).must_respond_to :room_number + expect(@my_room.room_number).must_equal "room 1" + + expect(@my_room).must_respond_to :room_reservations + expect(@my_room.room_reservations).must_be_kind_of Array + end + end + + describe "add_reservation_to_room(reservation)" do + it "The room_reservations should be an array of Reservation class" do + @my_room.room_reservations.each do |reservation| + expect(reservation).must_be_instance_of Hotel::Reservation + end + end + it "Should include room's reservations" do + expect(@my_room.room_reservations).must_include @spongebob_reservation + expect(@my_room.room_reservations.length).must_equal 2 + end + + it "Should add new Reservation instances to the array list of room_reservations" do + start_date = Date.new(2020, 3, 15) + end_date = start_date + 1 + squidward_reservation = Hotel::Reservation.new(start_date, end_date, room: "room 1", guest_name: "squidward tentacles") + expect(@my_room.add_reservation_to_room(squidward_reservation)).must_include squidward_reservation + expect(@my_room.room_reservations.length).must_equal 3 + end + + it "Should raise an ArgumentError if a reservation not for that room class is passed in as a parameter" do + start_date = Date.new(2020, 3, 20) + end_date = start_date + 1 + mr_krab_reservation = Hotel::Reservation.new(start_date, end_date, room: "room 6", guest_name: "my krabs") + expect { @my_room.add_reservation_to_room(mr_krab_reservation) }.must_raise ArgumentError + end + end + + describe "dates_unavailable" do + it "should return an array of all dates the room is has been reserved for" do + dates_reserved = [Date.new(2020, 2, 2), Date.new(2020, 2, 3), Date.new(2020, 2, 4), Date.new(2020, 2, 5)] + expect(@my_room.dates_unavailable).must_equal dates_reserved + end + it "Dates of reservation must be unique" do + expect(@my_room.dates_unavailable.uniq!).must_be_nil + end + end + + describe "is_available_during(start_date, end_date" do + it "Should return false if the room is reservared within that date range" do + start_date = Date.new(2020, 2, 2) + end_date = start_date + 1 + expect(@my_room.is_available_during(start_date, end_date)).must_equal false + end + it "Should return true if the room is available for the given start and end date" do + start_date = Date.new(2020, 3, 19) + end_date = start_date + 1 + expect(@my_room.is_available_during(start_date, end_date)).must_equal true + end + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index c3a7695cf..038f61672 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,8 +1,17 @@ -# Add simplecov +require 'simplecov' +SimpleCov.start do + add_filter 'test/' # Tests should not be checked for coverage. +end require "minitest" require "minitest/autorun" require "minitest/reporters" +require "minitest/skip_dsl" # skips the skips Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new -# require_relative your lib files here! +require_relative '../lib/date_range' +require_relative '../lib/room' +require_relative '../lib/reservation' +require_relative '../lib/front_desk' + +