-
Notifications
You must be signed in to change notification settings - Fork 40
Space - Jessica Stone #26
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?
Changes from all commits
d8c93e9
71c9caf
0ceda41
be9f6d6
27b51b5
798e577
f1ddfa1
9df7fce
26a9550
eae3b18
61c9760
755861d
d92ed09
9ec6a03
5e5fe70
d4ea6fd
7ebca35
f8324cb
0fa22ae
8ee037e
730c888
4105abd
4c58c8d
ab5c470
14c712f
b4d5c7c
531d217
0d8ecde
89fcd73
56e666b
42d626d
a3a6dd7
d345f85
bce125a
df07947
f5f42f5
91e1c51
78cc449
11fcfcf
fcb013d
761bbe8
577bc02
4376d09
4328403
f9299c4
e9fc699
ce23e8c
3d6486a
3386b4c
28afae8
7a49c9b
861ea42
0cb23f2
3912efa
8fa06b7
2ed69e3
6c20c08
be9f83d
b06b044
59b25a1
ca2be75
46952a9
5564f70
ace8f03
0d9ab3d
255e74f
178deff
5442afb
578031d
556e2bf
68c81de
d6daf7f
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 |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| guard :minitest, bundler: false, autorun: false, rubygems: false do | ||
| # with Minitest::Spec | ||
| guard :minitest, bundler: false, autorun: true, rubygems: false do | ||
| # With Minitest Reporters | ||
| watch(%r{^test/(.*)_test\.rb$}) | ||
| watch(%r{^lib/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" } | ||
| watch(%r{^test/test_helper\.rb$}) { 'test' } | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| require 'date' | ||
|
|
||
| module Hotel | ||
| class DateRange | ||
| attr_reader :start_date, :end_date, :range | ||
|
|
||
| def initialize(start_date, end_date) | ||
| @start_date = start_date | ||
| @end_date = end_date | ||
| validate_date() | ||
|
|
||
| @range = (start_date..end_date).to_a | ||
| end | ||
|
|
||
| def total_nights | ||
| return @end_date - @start_date | ||
| end | ||
|
|
||
| def validate_date() | ||
| unless (@start_date.is_a? Date) && (@end_date.is_a? Date) | ||
| raise ArgumentError.new("Invalid date provided: must be instance of Date") | ||
| end | ||
|
|
||
| if @start_date < Date.today | ||
| raise ArgumentError.new("Invalid date provided: start_date must be prior to today's date") | ||
| elsif @end_date < @start_date | ||
| raise ArgumentError.new("Invalid date provided: end_date must be prior to start_date") | ||
| end | ||
| end | ||
|
|
||
| def overlap?(date_range) | ||
| # if check-out date of one matches check-in date of the other, dates do not overlap | ||
| return false if (@range[-1] == date_range.range[0]) || (@range[0] == date_range.range[-1]) | ||
|
|
||
| # if any dates are in both ranges, dates overlap | ||
| return (@range & date_range.range).any? ? true : false | ||
| end | ||
|
|
||
| end | ||
|
|
||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| module Hotel | ||
| class HotelBlock | ||
| attr_reader :date_range, :rooms, :discount_rate, :id | ||
|
|
||
| def initialize(date_range, rooms, discount_rate, id) | ||
| @date_range = date_range | ||
| @rooms = rooms | ||
| raise ArgumentError.new("Max of 5 rooms can be reserved in a block") if rooms.length > 5 | ||
| @discount_rate = discount_rate | ||
| calculate_discounted_rate() | ||
| @id = id | ||
| end | ||
|
|
||
| def calculate_discounted_rate() | ||
| if @discount_rate > 1 | ||
| @discount_rate *= 0.01 | ||
| end | ||
| @rooms.each do |room| | ||
| room.cost -= (room.cost * @discount_rate) | ||
| end | ||
| end | ||
|
|
||
| def check_availability | ||
| available_rooms = [] | ||
| find_reservations.each do |reservation| | ||
| available_rooms << reservation.room_number if reservation.available == true | ||
| end | ||
| return available_rooms | ||
| end | ||
|
|
||
| def find_reservations | ||
| reservations = [] | ||
| @rooms.each do |room| | ||
| reservations << room.reservations.find { |reservation| reservation.hotel_block == @id } | ||
| end | ||
| return reservations | ||
| end | ||
|
|
||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| require_relative "hotel_block" | ||
|
|
||
| module Hotel | ||
| class HotelManager | ||
| attr_reader :rooms, :blocks, :total_reservations | ||
|
|
||
| def initialize | ||
| @rooms = [] | ||
| @blocks = [] | ||
| @total_reservations = 0 | ||
| end | ||
|
|
||
| def initialize_rooms(num) | ||
| if num.class != Integer | ||
| raise ArgumentError.new("Integer value must be provided. Value provided: '#{num}'") | ||
| else | ||
| num.times do |i| | ||
| room = Hotel::Room.new((i + 1), 200) | ||
| @rooms << room | ||
| end | ||
| end | ||
| end | ||
|
|
||
| def list_all_rooms | ||
| return @rooms | ||
| end | ||
|
|
||
| def reserve_room(date_range, room = nil) | ||
| picked_room = "" | ||
| if !room | ||
| available_rooms = list_available_rooms(date_range) | ||
| raise ArgumentError.new("No rooms available") if available_rooms == [] | ||
| picked_room = available_rooms[0] | ||
| else | ||
| picked_room = find_room(room) | ||
| end | ||
|
|
||
| @total_reservations += 1 | ||
| reservation = Reservation.new(date_range, @total_reservations, picked_room.number, picked_room.cost) | ||
|
|
||
| find_room(reservation.room_number).reservations << reservation | ||
|
Comment on lines
+39
to
+41
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. A very small design thing to consider in the future: Since your
I would personally achieve this by doing the |
||
| return reservation | ||
| end | ||
|
|
||
| def reserve_block(date_range, rooms, discount_rate) | ||
| check_availability = check_block_availability(date_range, rooms) | ||
|
|
||
| add_block_rooms(date_range, check_availability, discount_rate) | ||
|
|
||
| block = Hotel::HotelBlock.new(date_range, check_availability, discount_rate, @blocks.length + 1) | ||
| @blocks << block | ||
|
|
||
| return block | ||
| end | ||
|
|
||
| def add_block_rooms(date_range, rooms, discount_rate) | ||
| rooms.each do |room| | ||
| @total_reservations += 1 | ||
| reservation = Hotel::Reservation.new(date_range, @total_reservations, room.number, room.cost * (1 + discount_rate), @blocks.length + 1, true) | ||
| room.reservations << reservation | ||
| end | ||
| end | ||
|
|
||
| # check whether a given block has any rooms available | ||
| def check_block_availability(date_range, rooms) | ||
| available_rooms = list_available_rooms(date_range) | ||
|
|
||
| raise ArgumentError.new("Not all rooms have availability") if !(rooms - available_rooms).empty? | ||
|
|
||
| return rooms | ||
| end | ||
|
|
||
| # reserve a specific room from a hotel block | ||
| def reserve_block_room(room, block) | ||
| found_block = find_block(block) | ||
| found_room = find_room(room) | ||
| found_reservation = found_room.reservations.find { |reservation| reservation.hotel_block == block} | ||
| found_reservation.available == false | ||
| return found_reservation | ||
| end | ||
|
|
||
| def find_block(id) | ||
| found_block = @blocks.find { |block| block.id == id } | ||
| return found_block | ||
| end | ||
|
|
||
| def find_room(id) | ||
| found_room = @rooms.find { |room| room.number == id } | ||
| return found_room | ||
| end | ||
|
|
||
| def list_reservations_by_room(room, date_range) | ||
| reservation_list = [] | ||
| found_room = find_room(room) | ||
|
|
||
| found_room.reservations.each do |reservation| | ||
| if reservation.date_range.overlap?(date_range) == true | ||
| reservation_list << reservation | ||
| end | ||
| end | ||
|
|
||
| return reservation_list | ||
| end | ||
|
|
||
| def list_reservations_by_date(date) | ||
| reservation_list = [] | ||
|
|
||
| @rooms.each do |room| | ||
| room.reservations.each do |reservation| | ||
| if reservation.date_range.range.include?(date) | ||
| reservation_list << reservation | ||
| end | ||
| end | ||
| end | ||
|
|
||
| return reservation_list | ||
| end | ||
|
|
||
| def list_available_rooms(date_range) | ||
| available_rooms = [] | ||
|
|
||
| @rooms.length.times do |i| | ||
| room = find_room(i + 1) | ||
| available = room.check_availability(date_range) | ||
| available_rooms << room if available | ||
| end | ||
|
|
||
| return available_rooms | ||
| end | ||
|
|
||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| module Hotel | ||
| class Reservation | ||
| attr_reader :date_range, :id, :room_number, :nights, :cost, :hotel_block | ||
|
|
||
| attr_accessor :total_cost, :available | ||
|
|
||
| def initialize(date_range, id = 0, room_number = 0, cost = 0, hotel_block = nil, available = nil) | ||
| @date_range = date_range | ||
| @id = id | ||
| @cost = cost | ||
| @nights = date_range.total_nights | ||
| @total_cost = calculate_cost() | ||
| @room_number = room_number | ||
| @hotel_block = hotel_block || false | ||
| @available = available || false | ||
| end | ||
|
|
||
| def calculate_cost() | ||
| return @cost * @nights | ||
| end | ||
|
|
||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| module Hotel | ||
| class Room | ||
| attr_reader :reservations, :number, :cost | ||
| attr_writer :cost | ||
|
|
||
| def initialize(number, cost, reservations = []) | ||
| @number = number | ||
| @cost = cost | ||
| @reservations = [] | ||
| end | ||
|
|
||
| def check_availability(date_range) | ||
| return true if @reservations.empty? | ||
| @reservations.each do |reservation| | ||
| # return false if dates overlap, else continue | ||
| reservation.date_range.overlap?(date_range) ? (return false) : next | ||
| end | ||
| return true | ||
| end | ||
|
|
||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| - Structure | ||
| - think about holding array of Reservations in HotelManager instead of array of Rooms Would need to rewrite methods but this would probably reduce amount of loops being used | ||
|
|
||
| - HotelManager | ||
| - move line 77 into a find_reservations method | ||
| - line 28 reserve_room: move room picker into its own method | ||
| - line 56 - add_block_rooms method name is not clear. Rename this to say what this method does (add block reservations to rooms) | ||
| - see if these can be moved into HotelBlock class | ||
| - add_block_room | ||
| - check_block_availability | ||
| - reserve_block_room | ||
| - list_reservations_by_room & list_reservations_by_date have a similar loop: look into making this into a reusable method | ||
| - and/or, look into combining these methods (list_reservations)room = nil, date_range = nil, date = nil) | ||
|
|
||
| - HotelBlock | ||
| - store reservations instead of rooms to reduce layers | ||
| - can get rid of find_reservations method by doing this | ||
|
|
||
| - Reservation | ||
| - Room also holds cost - remove cost & keep only total_cost in Reservation | ||
| - Change @room_number to @room and hold instance of room | ||
| - move nights to DateRange and call from there | ||
|
|
||
| - DateRange | ||
| - hold nights in DateRange and remove from Reservation, and call from DateRange | ||
|
|
||
| - Room | ||
| - remove reservations from Room if moved into HotelManager | ||
| - check_availability would need to be moved into HotelManager as well |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| require_relative "test_helper" | ||
|
|
||
| describe "DateRange" do | ||
| before do | ||
| @date_range = Hotel::DateRange.new(Date.new(2020,5,3), Date.new(2020,5,5)) | ||
| end | ||
|
|
||
| describe "initialize" do | ||
| it "creates an instance of DateRange" do | ||
| expect(@date_range).must_be_kind_of Hotel::DateRange | ||
| expect(@date_range).must_respond_to :start_date | ||
| expect(@date_range).must_respond_to :end_date | ||
| expect(@date_range).must_respond_to :range | ||
| end | ||
| end | ||
|
|
||
| describe "total_nights" do | ||
| it "should return correct total of nights for given dates" do | ||
| expect(@date_range.total_nights).must_equal 2 | ||
| end | ||
| end | ||
|
|
||
| describe "validate_date" do | ||
| it "should return instance of DateRange if start_date and end_date are Date instances" do | ||
| expect(@date_range).must_be_kind_of Hotel::DateRange | ||
| end | ||
|
|
||
| it "should raise ArgumentError if one or both of start_date and end_date are not Date instances" do | ||
| date1 = Date.new(2020,5,3) | ||
| date2 = "October 24" | ||
|
|
||
| expect{ Hotel::DateRange.new(date1, date2) }.must_raise ArgumentError | ||
| end | ||
|
|
||
| it "should raise ArgumentError if start_date is before today" do | ||
| date1 = Date.new(2020,2,3) | ||
| date2 = Date.new(2020,5,5) | ||
|
|
||
| expect{ Hotel::DateRange.new(date1, date2) }.must_raise ArgumentError | ||
| end | ||
|
|
||
| it "should raise ArgumentError if end_date is before start_date" do | ||
| date1 = Date.new(2020,5,3) | ||
| date2 = Date.new(2020,5,1) | ||
|
|
||
| expect{ Hotel::DateRange.new(date1, date2) }.must_raise ArgumentError | ||
| end | ||
| end | ||
|
|
||
| describe "overlap?" do | ||
| it "should return true if dates overlap" do | ||
| date_range = Hotel::DateRange.new(Date.new(2020,5,4), Date.new(2020,5,6)) | ||
| expect(@date_range.overlap?(date_range)).must_equal true | ||
| end | ||
|
|
||
| it "should return false if dates do not overlap" do | ||
| date_range = Hotel::DateRange.new(Date.new(2020,5,7), Date.new(2020,5,9)) | ||
| expect(@date_range.overlap?(date_range)).must_equal false | ||
| end | ||
|
|
||
| it "returns false when check-out day of reservation is same as check-in day of new reservation" do | ||
| date_range = Hotel::DateRange.new(Date.new(2020,5,5), Date.new(2020,5,9)) | ||
| expect(@date_range.overlap?(date_range)).must_equal false | ||
| end | ||
|
|
||
| it "returns false when check-in day of reservation is same as check-out day of new reservation" do | ||
| date_range = Hotel::DateRange.new(Date.new(2020,5,1), Date.new(2020,5,3)) | ||
| expect(@date_range.overlap?(date_range)).must_equal false | ||
| 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 case of the optional parameter! Makes total sense