diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..6e8273414 Binary files /dev/null and b/.DS_Store differ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..a5dbfbb6a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Listen for rdebug-ide", + "type": "Ruby", + "request": "attach", + "remoteHost": "127.0.0.1", + "remotePort": "1234", + "remoteWorkspaceRoot": "${workspaceRoot}" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 0036110d9..e76f80e9e 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,6 @@ This project is both a culmination of our Intro to Ruby unit and our first stage **It is expected that you will not be able to complete all requirements.** The three waves are organized by difficulty and relevance to the learning goals, and should be tackled in order. -### Hints - -We have included some [optional design scaffolding](https://github.com/AdaGold/hotel/blob/design-scaffolding/design-scaffolding-notes.md) for this project, to help you get started if you don't know where to start, or to provide inspiration if you're a little stuck. Any student should feel free to use this scaffolding in whatever way is most helpful to them. However, **we recommend that you spend at least 1 full day thinking about design before reaching for this scaffolding**, to get practice thinking about this type of problem independently. - ## Getting Started We will use the same project structure we used for the previous project. Library code (such as classes) should be in files in the `lib` folder, and tests should be in files in the `test` folder. @@ -103,7 +99,7 @@ Spend **no more than 1 hour** answering those questions and adjusting your proje ## Functional Requirements -### Wave One: Tracking Reservations +### Wave 1: Tracking Reservations In this wave, write the functionality for the system to track valid reservations, so that a user of the hotel system can make and find valid bookings for their hotel. @@ -145,7 +141,7 @@ Remember: Your job is to only build the classes that store information and handl -### Wave Two: Room Availability +### Wave 2: Room Availability #### User Stories @@ -158,7 +154,7 @@ Remember: Your job is to only build the classes that store information and handl - A reservation is allowed start on the same day that another reservation for the same room ends -### Wave Three: Hotel Blocks +### Wave 3: Hotel Blocks If you are not familiar with what a block of hotel rooms, here is a brief description: diff --git a/feedback.md b/feedback.md index 4893f181e..05dd3c165 100644 --- a/feedback.md +++ b/feedback.md @@ -67,9 +67,9 @@ reserves a room from a block | ✔️ | Overall Feedback | Criteria | yes/no | | --- | --- | --- | -| Green (Meets/Exceeds Standards) | 14+ total in all sections | ✔️ -| Yellow (Approaches Standards) | 9-13 total in all sections | ✔️ -| Red (Not at Standard) | 0-8 total in all sections, or assignment is breaking/doesn’t run with less than 5 minutes of debugging | ✔️ +| Green (Meets/Exceeds Standards) | 14+ total in all sections | +| Yellow (Approaches Standards) | 9-13 total in all sections | +| Red (Not at Standard) | 0-8 total in all sections, or assignment is breaking/doesn’t run with less than 5 minutes of debugging | ### Additional Feedback diff --git a/lib/date_range.rb b/lib/date_range.rb new file mode 100644 index 000000000..a0d4aed8a --- /dev/null +++ b/lib/date_range.rb @@ -0,0 +1,31 @@ +require_relative 'hotel_controller' +require 'date' + +module Hotel + class DateRange + attr_accessor :start_date, :end_date + + def initialize(start_date, end_date) + @start_date = start_date + @end_date = end_date + raise ArgumentError.new("date range is incorrect") if @start_date > @end_date || @start_date == @end_date + end + + def overlap?(second_date_range) + if second_date_range.start_date >= @end_date || second_date_range.end_date <= @start_date + return false + else + return true + end + end + + def include_date_range?(date_range) + date_range.start_date.between?(@start_date, @end_date) || date_range.end_date.between?(@start_date, @end_date) + end + + def nights + return (@end_date - @start_date).to_i + end + + end +end \ No newline at end of file diff --git a/lib/hotel_controller.rb b/lib/hotel_controller.rb new file mode 100644 index 000000000..d8d328c43 --- /dev/null +++ b/lib/hotel_controller.rb @@ -0,0 +1,59 @@ +require_relative 'reservation' +require_relative 'room' +require_relative 'date_range' + +module Hotel + class HotelController + attr_reader :rooms, :get_available_rooms, :access_reservations + attr_accessor :reserve_room + def initialize + @rooms = Array.new(20) { |i| Room.new(i + 1) } + @hotel_reservations = [] + + end + + def reserve_room(room_to_reserve, date_range, hotel_block = :no) + if !room_to_reserve.check_availability(date_range) + raise ArgumentError.new("This room is not available") + else + new_reservation = Reservation.new(date_range, room_to_reserve, hotel_block) + room_to_reserve.add_reservation(new_reservation) + @hotel_reservations << new_reservation + return new_reservation + end + end + + def get_available_rooms(date_range) + rooms_available = [] + @rooms.each do |room| + if room.check_availability(date_range) + rooms_available << room + end + end + return rooms_available + end + + def access_reservations(date_range) + list_reservations = [] + + @hotel_reservations.each do |r| + if r.date_range.include_date_range?(date_range) + list_reservations << r + end + end + return list_reservations + end + + def reserve_block(date_range, rooms_to_reserve) + raise ArgumentError if !(3..5).include?(rooms_to_reserve.length) + rooms_to_reserve.each do |room| + begin + self.reserve_room(room, date_range, :yes) + rescue => exception + puts "Unable to reserve block: #{exception}" + end + end + end + + end +end \ No newline at end of file diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..8262ab673 --- /dev/null +++ b/lib/reservation.rb @@ -0,0 +1,29 @@ +require 'date' +require_relative 'date_range' + +module Hotel + class Reservation + attr_reader :date_range, :room, :price, :cost, :hotel_block + def initialize(date_range, room, price = 200, hotel_block = :no) + @date_range = date_range + @room = room + @price = price + @hotel_block = hotel_block + + if @hotel_block == :yes + @price = 180 + end + + valid_block = [:yes, :no] + raise ArgumentError if !valid_block.include?(@hotel_block) + end + + def cost + total_cost = @date_range.nights * @price + return total_cost + end + + end +end + + \ No newline at end of file diff --git a/lib/room.rb b/lib/room.rb new file mode 100644 index 000000000..07fb8c3c6 --- /dev/null +++ b/lib/room.rb @@ -0,0 +1,29 @@ +require_relative 'reservation' +require_relative 'date_range' + +module Hotel + class Room + attr_reader :id, :reservations + + def initialize(id, reservations = []) + @id = id + @reservations = [] + end + + def check_availability(date_range) # is available? #giving a date range to room and check if room is available for that day + @reservations.each do |r| + if r.date_range.overlap?(date_range) + return false + end + end + return true + end + + def add_reservation(reservation) + @reservations << reservation + end + end +end + + + diff --git a/refactors.txt b/refactors.txt new file mode 100644 index 000000000..6a2c9ff88 --- /dev/null +++ b/refactors.txt @@ -0,0 +1,4 @@ +One thing i would do differently would be to create a class for hotel blocks. +I found myself lost multiple times for not having a specific space for creating the blocks. +I would want to find a better method name for access_reservations, could not come up with a more clear name that +indicate the function. diff --git a/test/date_range_test.rb b/test/date_range_test.rb new file mode 100644 index 000000000..42d2e2798 --- /dev/null +++ b/test/date_range_test.rb @@ -0,0 +1,136 @@ +require_relative "test_helper" + +describe Hotel::DateRange do + describe "constructor" do + before do + start_date = Date.new(2017, 01, 01) + end_date = start_date + 3 + + @range = Hotel::DateRange.new(start_date, end_date) + end + + it "Can be initialized with two dates" do + start_date = Date.new(2017, 01, 01) + end_date = start_date + 3 + expect(@range.start_date).must_equal start_date + expect(@range.end_date).must_equal end_date + end + + it "is an an error for negative-lenght ranges" do + start_date = Date.today + end_date = start_date - 3 + expect { Hotel::DateRange.new(start_date, end_date) }.must_raise ArgumentError + end + + it "is an error to create a 0-length range" do + start_date = Date.today + end_date = @start_date + expect { Hotel::DateRange.new(start_date, end_date) }.must_raise ArgumentError + end + end + + describe "overlap?" do + before do + start_date = Date.new(2017, 01, 01) + end_date = start_date + 10 + + @range = Hotel::DateRange.new(start_date, end_date) + end + + it "returns true for the same range" do + start_date = @range.start_date + end_date = @range.end_date + test_range = Hotel::DateRange.new(start_date, end_date) + + expect(@range.overlap?(test_range)).must_equal true + end + + it "returns true for a contained range" do + start_date = Date.new(2017, 01, 03) + end_date = start_date + 3 + second_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(second_range)).must_equal true + + end + + it "returns true for a range that overlaps in front" do + start_date = Date.new(2016, 12, 27) + end_date = @range.start_date + 1 #end of the first range should be available for second_range night + second_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(second_range)).must_equal true + end + + it "returns true for a range that overlaps in the back" do + start_date = @range.start_date + end_date = start_date + 4 + second_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(second_range)).must_equal true + end + + it "returns true for a containing range" do + start_date = @range.start_date - 4 + end_date = @range.end_date + 3 + second_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(second_range)).must_equal true + end + + it "returns false for a range starting on the end_date date" do + start_date = @range.end_date + end_date = start_date + 3 + second_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(second_range)).must_equal false + end + + it "returns false for a range ending on the start_date date" do + start_date = Date.new(2016, 12, 27) + end_date = @range.start_date + second_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(second_range)).must_equal false + end + + it "returns false for a range completely before" do + start_date = Date.new(2016, 12, 20) + end_date = start_date + 5 + second_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(second_range)).must_equal false + end + + it "returns false for a date completely after" do + start_date = Date.new(2017, 02, 03) + end_date = start_date + 5 + second_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(second_range)).must_equal false + end + end + + describe "nights" do + it "returns the correct number of nights" do + start_date = Date.new(2017, 02, 03) + end_date = start_date + 3 + range = Hotel::DateRange.new(start_date, end_date) + expect(range.nights).must_equal 3 + + end + end + describe "include_date_range?" do + before do + start_date = Date.new(2017, 01, 01) + end_date = start_date + 3 + @range = Hotel::DateRange.new(start_date, end_date) + end + it "is included in the range" do + second_start_date = Date.new(2017, 01, 01) + second_end_date = second_start_date + 1 + second_range= Hotel::DateRange.new(second_start_date, second_end_date) + expect(@range.include_date_range?(second_range)).must_equal true + end + it "is not included in the range" do + start_date = Date.new(2016, 12, 27) + end_date = start_date + 2 + second_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.include_date_range?(second_range)).must_equal false + end + end + + +end \ No newline at end of file diff --git a/test/hotel_controller_test.rb b/test/hotel_controller_test.rb new file mode 100644 index 000000000..1ecef538b --- /dev/null +++ b/test/hotel_controller_test.rb @@ -0,0 +1,109 @@ +require_relative "test_helper" + +describe Hotel::HotelController do + before do + start_date = Date.new(2020, 01, 04) + end_date = start_date + 3 + @date_range = Hotel::DateRange.new(start_date, end_date) + @hotel_controller = Hotel::HotelController.new + + + @room_list = @hotel_controller.get_available_rooms(@date_range) + @available_room = @room_list[0] + @get_room = @hotel_controller.reserve_room(@available_room, @date_range) + + @room_list = @hotel_controller.get_available_rooms(@date_range) + end + + describe "rooms" do + it "returns a list" do + rooms = @hotel_controller.rooms + expect(rooms).must_be_kind_of Array + end + it "value is an instance of room" do + room_one = @hotel_controller.rooms[1] + expect(room_one).must_be_kind_of Hotel::Room + end + + it "array is size 20 rooms" do + length_rooms = @hotel_controller.rooms.length + expect(length_rooms).must_equal 20 + end + + it "first number of hotel id is 1" do + first_room = @hotel_controller.rooms[0].id + expect(first_room).must_equal 1 + end + + it "last number of the hotel id is 20" do + last_room = @hotel_controller.rooms[-1].id + expect(last_room).must_equal 20 + end + end + + describe "reserve a room" do + it "takes date_range object and returns a Reservation" do + expect(@get_room).must_be_kind_of Hotel::Reservation + end + it "date range is an instance of the class DateRange" do + expect(@get_room.date_range).must_be_kind_of Hotel::DateRange + end + it "raises an argument error if room is not available" do + expect { @hotel_controller.reserve_room(@available_room, @date_range) }.must_raise ArgumentError + end + end + + describe "get_available_rooms" do + it "takes a date_range and returns a list" do + expect(@room_list).must_be_kind_of Array + end + it "returns a list of instances of rooms" do + expect(@room_list[0]).must_be_kind_of Hotel::Room + end + it "return an array with all the available rooms" do + expect(@room_list.length).must_equal 19 + end + end + + describe "access reservations" do + it "returns an array" do + array = @hotel_controller.access_reservations(@date_range) + expect(array).must_be_kind_of Array + end + + it "returns an array of reservations for the date range" do + reservations = @hotel_controller.access_reservations(@date_range)[0] + expect(reservations).must_be_kind_of Hotel::Reservation + end + + it "returns only reservations within the date range" do + second_date = Date.new(2021, 01, 04) + @hotel_controller.reserve_room(@room_list[0], Hotel::DateRange.new(second_date, second_date + 3)) + + start_date = Date.new(2020, 01, 04) + end_date = start_date + 1 + date_range = Hotel::DateRange.new(start_date, end_date) + + reservations = @hotel_controller.access_reservations(date_range) + dates_valid = true + reservations.each do |r| + if !r.date_range.include_date_range?(date_range) + dates_valid = false + end + end + expect(dates_valid).must_equal true + end + end + describe "reserve a block" do + before do + start_date = Date.new(2020, 10, 21) + end_date = start_date + 4 + @date_range_block = Hotel::DateRange.new(start_date, end_date) + rooms = [@room_list[1], @room_list[2], @room_list[3]] + @reserving_block = @hotel_controller.reserve_block(@date_range_block, rooms) + end + it "returns an array" do + expect(@reserving_block).must_be_kind_of Array + end + end +end \ No newline at end of file diff --git a/test/reservation_test.rb b/test/reservation_test.rb new file mode 100644 index 000000000..998126af5 --- /dev/null +++ b/test/reservation_test.rb @@ -0,0 +1,20 @@ +require_relative "test_helper" + +describe Hotel::Reservation do + before do + start_date = Date.new(2017, 01, 01) + end_date = start_date + 3 + @date_range = Hotel::DateRange.new(start_date, end_date) + @room = 1 + @reservation = Hotel::Reservation.new(@date_range, @room) + end + + describe "cost" do + it "returns a number" do + expect(@reservation.cost).must_be_kind_of Numeric + end + it "returns the total cost for the hotel" do + expect(@reservation.cost).must_equal 600 + end + end +end \ No newline at end of file diff --git a/test/room_test.rb b/test/room_test.rb new file mode 100644 index 000000000..7832b1a5e --- /dev/null +++ b/test/room_test.rb @@ -0,0 +1,37 @@ +require_relative "test_helper" + +describe Hotel::Room do + + before do + start_date = Date.new(2020, 03, 01) + end_date = start_date + 3 + date_range = Hotel::DateRange.new(start_date, end_date) + @room = Hotel::Room.new(1) + reservation = Hotel::Reservation.new(date_range, @room) + @room.add_reservation(reservation) + + end + describe "Room class" do + + it "can be created" do + expect(@room).must_be_kind_of Hotel::Room + end + it "has an Intenger ID" do + expect(@room.id).must_be_kind_of Integer + end + end + describe "Room reservations" do + it "is an array" do + expect(@room.reservations).must_be_kind_of Array + end + it "is an array of instances of reservation" do + expect(@room.reservations[0]).must_be_kind_of Hotel::Reservation + end + it "date_range is an instance of DateRange" do + expect(@room.reservations[0].date_range).must_be_kind_of Hotel::DateRange + end + it "room is an instance of room" do + expect(@room.reservations[0].room).must_be_kind_of Hotel::Room + end + end +end \ No newline at end of file diff --git a/test/test_helper.rb b/test/test_helper.rb index c3a7695cf..84732927b 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,8 +1,25 @@ # 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" +require 'date' + + Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new # require_relative your lib files here! + +require_relative "../lib/hotel_controller" +require_relative "../lib/reservation" +require_relative "../lib/date_range" +require_relative "../lib/room" + + +