-
Notifications
You must be signed in to change notification settings - Fork 40
Time - Yaz #37
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?
Time - Yaz #37
Changes from all commits
2446ce0
3aa96d6
b444395
5d85ff3
2dad181
d30f7d9
07a200f
e0bd4f0
b730bc2
a09d065
093c309
6aa96a4
c22e16d
0169121
6e549b9
0ebed56
feaf784
be30060
f0fe0af
37b5c9e
e7c6b57
d2a9a6e
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,47 @@ | ||
| module Hotel | ||
| class Block < DateRange | ||
| attr_reader :reservations, :rate | ||
| def initialize(start_date, end_date, rooms, rate) | ||
| if rooms.length > 5 | ||
| raise ArgumentError.new("Blocks can only be made for 5 rooms or less.") | ||
| end | ||
| super(start_date, end_date) | ||
| range = DateRange.new(start_date, end_date) | ||
| if rooms.any? { |room| !(room.available?(range))} | ||
| raise ArgumentError.new("One or more of the rooms is not available at given date range.") | ||
| end | ||
| @rate = rate | ||
| @reservations = [] | ||
| @available_rooms = rooms | ||
| @available_rooms.each do |room| | ||
| room.add(self) | ||
| end | ||
| end | ||
|
|
||
| def reserve(room) | ||
| if !(@available_rooms.include?(room)) | ||
| raise ArgumentError.new("Room #{room.id} is not in this Block.") | ||
| end | ||
| if @available_rooms.all?{|r| r == nil} | ||
| raise ArgumentError.new("All rooms in block are already reserved.") | ||
| end | ||
| new_res = Reservation.new(start_date, end_date, room.id, rate) | ||
| self.reservations << new_res | ||
|
|
||
| # finds the block in room's reservations, turns it into a reservation | ||
| i = room.reservations.find_index {|reservation| | ||
| reservation.nights == self.nights | ||
| } | ||
| room.reservations[i] = new_res | ||
| j = @available_rooms.find_index {|r| | ||
| r == room | ||
| } | ||
| @available_rooms[j] = nil | ||
| end | ||
|
|
||
| def available_rooms | ||
| return @available_rooms.find_all {|room| room != nil} | ||
| end | ||
|
|
||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| require 'date' | ||
| module Hotel | ||
| class InvalidDateError < StandardError | ||
|
|
||
| end | ||
| class DateRange | ||
| attr_reader :start_date, :end_date, :nights | ||
|
|
||
| def initialize(start_date, end_date) | ||
| if !(start_date.instance_of?(Date) || end_date.instance_of?(Date)) | ||
| raise InvalidDateError.new("End and start dates must be instances of Date.") | ||
| else | ||
| @start_date = start_date | ||
| @end_date = end_date | ||
| end | ||
| if @end_date - @start_date <= 0 | ||
| raise InvalidDateError.new("End date must be after start date.") | ||
| end | ||
| @nights = Array.new((@end_date - @start_date).to_i) | ||
| @nights[0] = @start_date | ||
| index = 1 | ||
|
|
||
| while @nights.last == nil | ||
| @nights[index] = @start_date + index | ||
| index += 1 | ||
| end | ||
|
|
||
| end | ||
|
|
||
| def overlap?(other) | ||
|
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 like your design choice to have Reservation and Block inherit from DateRange. I think I understand your logic here. Front_desk will invoke |
||
| other.nights.each do |night| | ||
| if self.include? night | ||
| return true | ||
| end | ||
| end | ||
| return false | ||
| end | ||
|
|
||
|
|
||
| def include?(date) | ||
| return nights.include? date | ||
| end | ||
|
|
||
| def num_nights | ||
| return nights.length | ||
| end | ||
|
|
||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| module Hotel | ||
| class FrontDesk | ||
| attr_reader :rooms | ||
| def initialize | ||
| @rooms = [] | ||
| # Refactor: custom range - rooms. Rooms include Comparable, and implement succ and <=> | ||
| # See range doc | ||
| (1..20).each do |n| | ||
| @rooms << Room.new(n) | ||
| end | ||
| end | ||
|
|
||
| def reserve_room(start_date, end_date) | ||
| date_range = Hotel::DateRange.new(start_date, end_date) | ||
| room = find_room(date_range) | ||
| return room.add(date_range) | ||
| end | ||
|
|
||
| def get_avail_rooms(start_date, end_date) | ||
| date_range = Hotel::DateRange.new(start_date, end_date) | ||
| avail_rooms = rooms.find_all { |room| | ||
| room.available?(date_range) | ||
| } | ||
| return avail_rooms | ||
| end | ||
|
|
||
| def get_reservations(date) | ||
| reservations_at_date = [] | ||
| rooms.each do |room| | ||
| room.reservations.each do |reservation| | ||
| if reservation.include?(date) && reservation.class != Block | ||
| reservations_at_date << reservation | ||
| end | ||
| end | ||
| end | ||
| return reservations_at_date | ||
| end | ||
|
|
||
| private | ||
|
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. Nice use of a private helper method. |
||
| def find_room(date_range) | ||
| room = rooms.find {|r| | ||
| r.reservations.length == 0 | ||
| } | ||
| if room == nil | ||
| room = rooms.find {|r| | ||
| r.available?(date_range) | ||
| } | ||
| end | ||
| if room == nil | ||
| raise ArgumentError.new("No rooms are availble in that date range.") | ||
| end | ||
| return room | ||
| end | ||
|
|
||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| require_relative 'date_range' | ||
| module Hotel | ||
| class Reservation < DateRange | ||
| attr_reader :cost, :room | ||
| def initialize(start_date, end_date, room, rate= 200) | ||
| super(start_date, end_date) | ||
| @room = room | ||
| @cost = self.num_nights * rate | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| module Hotel | ||
| class Room | ||
| attr_reader :id, :reservations, :room_rate | ||
|
|
||
| def initialize(id, room_rate=200) | ||
| @id = id | ||
| @reservations = [] | ||
| @room_rate = room_rate | ||
| end | ||
|
|
||
| # is available for a specific reservation or a general date range | ||
| def available?(date_range) | ||
| if reservations.length == 0 | ||
| return true | ||
| end | ||
| if reservations.any? {|r| r.overlap?(date_range)} | ||
| return false | ||
| else | ||
| return true | ||
| end | ||
| end | ||
|
|
||
| def add(date_range) | ||
| if date_range.class != Reservation && date_range.class != Block | ||
| reservation = Reservation.new(date_range.start_date, date_range.end_date, self.id, room_rate) | ||
| else | ||
| reservation = date_range | ||
| end | ||
| if self.available?(reservation) | ||
| @reservations << reservation | ||
| else | ||
| raise ArgumentError.new("Room #{self.id} isn't available for that reservation.") | ||
| end | ||
| return reservation | ||
| end | ||
|
|
||
| def get_reservations(start_date, end_date) | ||
| range = DateRange.new(start_date, end_date) | ||
| resv_within = reservations.find_all {|reservation| | ||
| reservation.nights.all? {|night| range.include?(night)} | ||
| } | ||
| return resv_within | ||
| end | ||
|
|
||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| * Create consistent convention for when to use date_range or start_date, end_date as parameters | ||
| * Create RoomNotAvailableError Class | ||
| * Map out everywhere that Room#availble? is used - there is redundancy here. | ||
| * Figure out why block_test.rb is not included in coverage file |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| require_relative "test_helper" | ||
|
|
||
| describe Hotel::Block do | ||
|
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. These tests are really comprehensive. Nice work! |
||
| before do | ||
| @fd = Hotel::FrontDesk.new | ||
| @rooms = @fd.rooms.slice(0,5) | ||
| @start = Date.new(2020, 01, 01) | ||
| @end = Date.new(2020, 01, 07) | ||
| @rate = 153 | ||
| end | ||
|
|
||
| describe "constructor" do | ||
| describe "has all the expected state" do | ||
| it "rooms" do | ||
| block = Hotel::Block.new(@start, @end, @rooms, @rate) | ||
| expect(block.available_rooms).must_be_kind_of Array | ||
| avail_rooms = block.available_rooms | ||
| avail_rooms.each_with_index do |room, i| | ||
| expect(room).must_equal @rooms[i] | ||
| end | ||
| end | ||
| it "reservations" do | ||
| block = Hotel::Block.new(@start, @end, @rooms, @rate) | ||
| expect(block.reservations).must_be_kind_of Array | ||
| end | ||
| end | ||
| it "raises error if a room in rooms is not available" do | ||
| @rooms[4].add(Hotel::Reservation.new(@start, @end, 5, 150)) | ||
| expect{Hotel::Block.new(@start, @end, @rooms, @rate)}.must_raise ArgumentError | ||
| end | ||
| it "raises an error if rooms is > 5" do | ||
| @rooms << Hotel::Room.new(6) | ||
| expect{Hotel::Block.new(@start, @end, @rooms, @rate)}.must_raise ArgumentError | ||
| end | ||
| it "reflects changes in rooms included in block" do | ||
| block = Hotel::Block.new(@start, @end, @rooms, @rate) | ||
| @rooms.each do |room| | ||
| expect(room.reservations.include?(block)).must_equal true | ||
| end | ||
| end | ||
|
|
||
| end | ||
|
|
||
| describe "reserve(room)" do | ||
| it "raises error if attempting to reserve a room not in block" do | ||
| block = Hotel::Block.new(@start, @end, @rooms, @rate) | ||
| expect{block.reserve(Hotel::Room.new(20))}.must_raise ArgumentError | ||
| end | ||
|
|
||
| it "reflects changes in class state: reservations" do | ||
| block = Hotel::Block.new(@start, @end, @rooms, @rate) | ||
| @rooms.each do |room| | ||
| block.reserve(room) | ||
| end | ||
| block.reservations.each_with_index do |reservation, i| | ||
| expect(reservation.room).must_equal i + 1 | ||
| end | ||
| end | ||
|
|
||
| it "reserved room no longer has the block in their reservations, but a reservation instead" do | ||
| block = Hotel::Block.new(@start, @end, @rooms, @rate) | ||
| @rooms.each do |room| | ||
| block.reserve(room) | ||
| expect(room.reservations.any?(Hotel::Block)).must_equal false | ||
| end | ||
|
|
||
| end | ||
| it "won't let another block be formed on the same rooms with overlapping range" do | ||
| Hotel::Block.new(@start, @end, @rooms, @rate) | ||
| start2 = Date.new(2020, 01, 03) | ||
| end2 = Date.new(2020, 01, 15) | ||
| expect{Hotel::Block.new(start2, end2, @rooms, @rate)}.must_raise ArgumentError | ||
| end | ||
| it "won't erase another block in making room's block>reservation change" do | ||
| block = Hotel::Block.new(@start, @end, @rooms, @rate) | ||
| start2 = Date.new(2020, 02, 01) | ||
| end2 = Date.new(2020, 02, 28) | ||
| block2 = Hotel::Block.new(start2, end2, @rooms, @rate) | ||
| @rooms.each do |room| | ||
| block.reserve(room) | ||
| expect(room.reservations.find{|r| r.class == Hotel::Block}).must_equal block2 | ||
| end | ||
| end | ||
| it "removes room from available_rooms" do | ||
| block = Hotel::Block.new(@start, @end, @rooms, @rate) | ||
| @rooms.each_with_index do |room, i| | ||
| block.reserve(room) | ||
| expect(block.available_rooms.any?{|r| r == room }).must_equal false | ||
| end | ||
| end | ||
| it "effectively adds discounted rate to reservation" do | ||
| block = Hotel::Block.new(@start, @end, @rooms, @rate) | ||
| @rooms.each_with_index do |room, i| | ||
| block.reserve(room) | ||
| end | ||
| block.reservations.each do |r| | ||
| expect(r.cost % 153 == 0).must_equal true | ||
| end | ||
| end | ||
| it "raises error if all rooms are booked" do | ||
| block = Hotel::Block.new(@start, @end, @rooms, @rate) | ||
| @rooms.each_with_index do |room, i| | ||
| block.reserve(room) | ||
| end | ||
| expect{block.reserve(@rooms[0])}.must_raise ArgumentError | ||
| 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.
Nice use of a custom exception.