-
Notifications
You must be signed in to change notification settings - Fork 40
Space - Yieni #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Space - Yieni #25
Changes from all commits
38671be
77c0390
ddde6bf
4c84844
776f0e5
0d10b72
4048b4f
d17df05
d2b0176
e3b8311
10cb24b
159864a
83b3034
2ae449a
0fc5509
0add42f
e628002
4731ffa
6172d57
2e4bef5
0af6916
ccc6cba
72aba3b
7ff3e3f
a43b155
f7d7db6
67e8b5b
c877a90
4cacc0b
585309c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| class NoAvailableRoomError < StandardError | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| require 'date' | ||
|
|
||
| module Hotel | ||
| class DateRange | ||
| attr_reader :start_date, :end_date, :range | ||
|
|
||
| def initialize(start_date:, end_date:) | ||
| raise ArgumentError.new("start and end dates must be Date objects") if start_date.class != Date && end_date.class != Date | ||
| @start_date = start_date | ||
| @end_date = end_date | ||
| @range = (@start_date .. @end_date).to_a | ||
| raise ArgumentError.new("End date can not be before start date") if @end_date < @start_date | ||
| raise ArgumentError.new("Reservation can not be before today") if @end_date < Date.today || @start_date < Date.today | ||
|
|
||
| end | ||
|
|
||
| def overlap?(date_range) | ||
| # if the array of the combined arrays is empty, there is no overlap, so return false | ||
| # if the array is not empty, return true | ||
| overlap = (self.range & date_range.range).empty? || (date_range.start_date >= self.end_date) || (date_range.end_date <= self.start_date) ? false : true | ||
| return overlap | ||
| end | ||
|
|
||
| def nights | ||
| return @range.count - 1 | ||
| end | ||
|
|
||
|
|
||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| require_relative 'room' | ||
| require_relative 'date_range' | ||
| require_relative 'reservations' | ||
| require_relative 'hotel_block' | ||
| require_relative 'no_available_room_error' | ||
|
|
||
| module Hotel | ||
| class FrontDesk | ||
| attr_accessor :rooms, :reservations, :hotel_blocks | ||
|
|
||
| def initialize | ||
| @rooms = [] | ||
|
|
||
| (1..20).each do |room_num| | ||
| new_room = Room.new(room_number: room_num, cost: 200) | ||
| @rooms << new_room | ||
| end | ||
| @reservations = [] | ||
| @hotel_blocks = [] | ||
| end | ||
|
|
||
| def add_reservation(date_range) | ||
| available_rooms = check_block_status(date_range) | ||
|
|
||
| raise NoAvailableRoomError.new("there are no available rooms for that date")if available_rooms.empty? == true | ||
|
|
||
| chosen_room = available_rooms[0] | ||
| new_reservation = Hotel::Reservation.new(date_range: date_range, room: chosen_room) | ||
| @reservations << new_reservation | ||
| chosen_room.add_room_reservation(new_reservation) | ||
| return new_reservation | ||
| end | ||
|
|
||
| def available_rooms(date_range) | ||
| available_rooms = @rooms.reject do |room| | ||
| room.reservations.any?{|reservation| reservation.date_range.overlap?(date_range) == true} | ||
| end | ||
| return available_rooms | ||
|
|
||
| end | ||
|
|
||
| def find_reservation_with(room: nil, date_range:) | ||
| res_w_given_date = @reservations.select {|reservation| (reservation.date_range == date_range && reservation.room == room) || reservation.date_range == date_range } | ||
| return res_w_given_date | ||
| end | ||
|
|
||
| def total_cost(reservation) | ||
| if reservation.block_reservation == false | ||
| total_cost = reservation.date_range.nights * reservation.room.cost | ||
| else | ||
| total_cost = reservation.date_range.nights * reservation.room.cost * (1-reservation.room.discount_cost) | ||
| end | ||
| return total_cost | ||
| end | ||
|
|
||
| def check_block_status(date_range) | ||
| available_rooms = available_rooms(date_range) | ||
| @hotel_blocks.each do |hotel_block| | ||
| if hotel_block.date_range.overlap?(date_range) == true | ||
| hotel_block.rooms.each do |block_room| | ||
| available_rooms.delete(block_room) | ||
| end | ||
| end | ||
| end | ||
| return available_rooms | ||
| end | ||
|
|
||
| def request_block(block_count, date_range, discount_cost) | ||
| available_rooms = check_block_status(date_range) | ||
| raise NoAvailableRoomError.new("Not enough available rooms to fulfill block") if available_rooms.count < block_count | ||
|
|
||
| hotel_block = Hotel::HotelBlock.new(block_count: block_count, date_range: date_range, discount_cost: discount_cost) | ||
|
|
||
| x = 0 | ||
| until x == block_count do | ||
| available_room = available_rooms[x] | ||
| available_room.change_cost(discount_cost) | ||
| hotel_block.rooms << available_room | ||
| x += 1 | ||
| end | ||
| @hotel_blocks << hotel_block | ||
| return hotel_block | ||
| end | ||
|
|
||
| def available_rooms_in_block(hotel_block) | ||
| available_rooms = hotel_block.rooms.select{|room| room.reservations.empty? == true || room.reservations.any?{|reservation| reservation.date_range.overlap?(hotel_block.date_range) == false}} | ||
| return available_rooms | ||
| end | ||
|
|
||
| def add_reservation_to_room_in_block(hotel_block) | ||
| available_rooms = available_rooms_in_block(hotel_block) | ||
| raise NoAvailableRoomError.new("there are no available rooms left in this block")if available_rooms.empty? == true | ||
| chosen_room = available_rooms[0] | ||
| new_reservation = Hotel::Reservation.new(date_range: hotel_block.date_range, room: chosen_room) | ||
| new_reservation.block_reservation = true | ||
| @reservations << new_reservation | ||
| chosen_room.add_room_reservation(new_reservation) | ||
| return new_reservation | ||
| end | ||
|
Comment on lines
+56
to
+99
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At least a couple of these methods probably belong to |
||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| module Hotel | ||
| class HotelBlock | ||
| attr_reader :block_count, :date_range, :discount_cost | ||
| attr_accessor :rooms | ||
|
|
||
| def initialize(block_count:, date_range:, discount_cost:) | ||
| @block_count = block_count # I interpreted the user story "collection of rooms" to mean I can pass it a | ||
| #count and the count determines how many rooms to request for the block. | ||
| @date_range = date_range | ||
| @discount_cost = discount_cost | ||
| @rooms = [] | ||
|
|
||
| raise ArgumentError.new("Block count must be an integer between 2 and 5 inclusive") if @block_count.between?(2,5) == false | ||
|
|
||
| end | ||
|
|
||
| end | ||
|
|
||
|
Comment on lines
+2
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tend to get suspicious when a class only has |
||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
|
|
||
| module Hotel | ||
| class Reservation | ||
| attr_reader :date_range, :room | ||
| attr_accessor :block_reservation | ||
|
|
||
| def initialize(date_range:, room: nil) | ||
| @date_range = date_range | ||
| @room = room | ||
| @block_reservation = block_reservation | ||
| end | ||
|
|
||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
|
|
||
| module Hotel | ||
| class Room | ||
| attr_reader :room_number | ||
| attr_accessor :cost, :reservations, :discount_cost | ||
|
|
||
| def initialize(room_number:, cost:, reservations: nil) | ||
| @room_number = room_number | ||
|
|
||
| raise ArgumentError.new("There are only 20 rooms") if room_number < 1 || room_number > 20 | ||
|
|
||
| @cost = 200 | ||
| @reservations = reservations || [] | ||
| @discount_cost = 0 | ||
|
|
||
| end | ||
|
|
||
| def add_room_reservation(reservation) | ||
| @reservations << reservation | ||
| end | ||
|
|
||
| def change_cost(discount_cost) | ||
| self.discount_cost = discount_cost | ||
| return self | ||
| end | ||
|
|
||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| Possible Refactors: | ||
| 1. Only tracking reservation in either my front desk or my rooms, but not both | ||
| 2. Refactor my block check status so that time and space are not O(n**2) | ||
| 3. Write more test that cover more edge cases for the methods in my front desk | ||
| 4. Don't track discount cost in my rooms | ||
| a. figure out a better way to account for discount costs for rooms in block |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| require_relative 'test_helper' | ||
|
|
||
| describe "DateRange" do | ||
| before do | ||
| @start_date = Date.today + 2 | ||
| @end_date = Date.today + 6 | ||
| @date_range = Hotel::DateRange.new(start_date: @start_date, end_date: @end_date) | ||
| end | ||
|
|
||
| describe "initialize DateRange" do | ||
|
|
||
| it "creates a DateRange object" do | ||
| expect(@date_range).must_be_instance_of Hotel::DateRange | ||
| end | ||
|
|
||
| it "raises ArgumentError if end date is before start date" do | ||
| expect{Hotel::DateRange.new(start_date: Date.today + 6, end_date: Date.today + 2)}.must_raise ArgumentError | ||
| end | ||
|
|
||
| it "raises ArgumentError if end date and start date are not Date objects" do | ||
| expect{Hotel::DateRange.new(start_date: "March 4, 2020", end_date: "March 2, 2020")}.must_raise ArgumentError | ||
| end | ||
|
|
||
| it "creates a range of the start and end dates" do | ||
| expect(@date_range.range).must_equal (@start_date..@end_date).to_a | ||
| end | ||
| end | ||
|
|
||
| describe "overlap?" do | ||
|
|
||
| it "returns true if there is overlap between date ranges" do | ||
| date_range2 = Hotel::DateRange.new(start_date: Date.today + 2, end_date: Date.today + 4) | ||
| date_range3 = Hotel::DateRange.new(start_date: Date.today + 3, end_date: Date.today + 6) | ||
| date_range4 = Hotel::DateRange.new(start_date: Date.today + 1, end_date: Date.today + 9) | ||
| date_range5 = Hotel::DateRange.new(start_date: Date.today + 1, end_date: Date.today + 6) | ||
| expect(@date_range.overlap?(date_range2)).must_equal true | ||
| expect(@date_range.overlap?(date_range3)).must_equal true | ||
| expect(@date_range.overlap?(date_range4)).must_equal true | ||
| expect(@date_range.overlap?(date_range5)).must_equal true | ||
| end | ||
|
|
||
| it "returns false if the date is not within the range" do | ||
| date_range2 = Hotel::DateRange.new(start_date: Date.today + 6, end_date: Date.today + 9) | ||
| date_range3 = Hotel::DateRange.new(start_date: Date.today + 7, end_date: Date.today + 13) | ||
| date_range4 = Hotel::DateRange.new(start_date: Date.today + 1, end_date: Date.today + 2) | ||
| date_range5 = Hotel::DateRange.new(start_date: Date.today + 19, end_date: Date.today + 20) | ||
| date_range5 = Hotel::DateRange.new(start_date: Date.today , end_date: Date.today + 1) | ||
| expect(@date_range.overlap?(date_range2)).must_equal false | ||
| expect(@date_range.overlap?(date_range3)).must_equal false | ||
| expect(@date_range.overlap?(date_range4)).must_equal false | ||
| expect(@date_range.overlap?(date_range5)).must_equal false | ||
| end | ||
|
Comment on lines
+31
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would give these date ranges more explicit names, so that others can check your work more easily. |
||
|
|
||
| end | ||
|
|
||
| describe "nights" do | ||
|
|
||
| it "calculates the number of nights booked" do | ||
| expect(@date_range.nights).must_equal 4 | ||
| end | ||
| end | ||
|
|
||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A thought you might enjoy chewing on: how would your code change if
class DateRange < Range?