-
Notifications
You must be signed in to change notification settings - Fork 45
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
Carets- Julia Meier- Hotel #43
base: master
Are you sure you want to change the base?
Changes from all commits
a94a144
2f7d797
26db587
9f29417
7dee76c
69acd00
e9e19fb
72eafc8
5b382e5
6a2a97e
a2a3b62
34b7b36
2816d6c
5ae6a02
b6a86ed
fea6898
25dee3d
c6daf3c
e235d39
9edb3ee
e72c1cd
10533e1
c235d6c
436d51b
fe89f75
288e71d
245ac65
92ea61a
f886d28
fbc9594
eac82f0
305b2e4
54308c2
bf4cd7e
b1b8d9b
41f3657
1cb8178
4e79788
1ca1e06
702a62b
f2aac8b
379b9ff
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,9 @@ | ||
require 'rake/testtask' | ||
|
||
Rake::TestTask.new do |t| | ||
t.libs = ["lib"] | ||
t.warning = true | ||
t.test_files = FileList['specs/*_spec.rb'] | ||
end | ||
|
||
task default: :test |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<!-- design-activity.md --> | ||
|
||
What classes does each implementation include? Are the lists the same? | ||
Both implementations use these classes: CartEntry, ShoppingCart, Order. | ||
|
||
Write down a sentence to describe each class. | ||
Implementation A: | ||
CartEntry - stores the unit price and quantity for an item | ||
ShoppingCart - stores an array of CartEntry objects | ||
Order - creates a new ShoppingCart object and calculates the total cost, including tax, of the items in the ShoppingCart. | ||
|
||
Implementation B: | ||
CartEntry - stores the unit price and quantity for an item (same as A) | ||
ShoppingCart - stores an array of CartEntry objects and calculates the total cost of the items, independent of sales tax. | ||
Order - creates a new ShoppingCart object and calculates the total cost of the items in the Shopping Cart by calling the ShoppingCart.price method and applying a sales tax. | ||
|
||
How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper. | ||
See attached photo called "shopping_cart_diagram.JPG" (photo of doodle diagram). | ||
|
||
What data does each class store? How (if at all) does this differ between the two implementations? | ||
CartEntry- stores unit_price and quantity data for each CartEntry object. | ||
ShoppingCart- stores array of entries objects. | ||
Order- stores cart object but no data. | ||
|
||
What methods does each class have? How (if at all) does this differ between the two implementations? | ||
Implementation A includes initialize methods for all three classes; only the Order class has an additional method, which calculates the total price of an order. Implementation B differs in that all classes have an additional method that calculates price. | ||
|
||
Consider the Order#total_price method. In each implementation: | ||
Is logic to compute the price delegated to "lower level" classes like ShoppingCart and CartEntry, or is it retained in Order? | ||
In Implementation A, the logic to compute price is retained by the Order class. In Implementation B, it is delegated to the ShoppingCart class and the Order class. | ||
|
||
Does total_price directly manipulate the instance variables of other classes? | ||
In Implementation A, total_pice manipulates instance variables of other classes, but Implementation B does not. | ||
|
||
If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify? | ||
Implementation B would be easier to modify because the user can do a cost comparison of the price of the item at the item level, since there is a price method in the CartEntry class. If bulk ordering is being considered, it might help to add another class that stores the bulk ordering requirements for a specific item. For example, there may be different prices for an item that is ordered in quantities of 1-25 vs. 26-100. | ||
|
||
Which implementation better adheres to the single responsibility principle? | ||
Implementation B. | ||
|
||
Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? | ||
Implementation B. | ||
|
||
|
||
Notes on Changes I've made to Hotel: | ||
-created new names that make more sense if the future data structure changes: i.e. "array_of_rooms" was changed to "rooms", and "array_of_reservations" was changed to "reservations." etc. | ||
-changed MyHotel class to be called simply Hotel | ||
-in Block class, removed :check-in-date and :check-out attr_readers as they were not being used/referenced | ||
-moved "find_reservations_by_date" method from Hotel class to Reservations class. Per Chris' suggestion, changed method to first calculate the date outside of the loop that generates the available rooms. changed corresponding tests. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#block.rb | ||
|
||
require 'awesome_print' | ||
require 'date' | ||
require 'pry' | ||
|
||
module Hotel_Chain | ||
class Block | ||
|
||
attr_reader :party_name, :room_rate, :reservations | ||
|
||
def initialize(party_name, check_in_date, check_out_date, room_rate, reservations) | ||
@party_name = party_name | ||
@check_in_date = Date.strptime(check_in_date, "%m/%d/%Y") | ||
@check_out_date = Date.strptime(check_out_date, "%m/%d/%Y") | ||
@room_rate = room_rate | ||
@reservations = reservations #array of reservation objects | ||
end | ||
|
||
end #end of class | ||
end #end of module |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#custom_exceptions.rb | ||
|
||
class WrongDateFormatError < ArgumentError | ||
def initialize | ||
super ("You've entered the date in the wrong format. Please use MM/DD/YY") | ||
end | ||
end | ||
|
||
class ReservationNotAvailableError < ArgumentError | ||
def initialize | ||
super ("A reservation is not available for the date range you have entered.") | ||
end | ||
end | ||
|
||
class NoPartyByThatNameError < ArgumentError | ||
def initialize | ||
super ("There is no block of rooms reserved under that name. Please make sure you have the exact party name.") | ||
end | ||
end | ||
|
||
class AllBlockRoomsAssignedError < ArgumentError | ||
def initialize | ||
super ("All the reservations made for that block of room have been assigned. You may check to see if there is a room available at the standard rate.") | ||
end | ||
end | ||
|
||
class ExceededRoomLimitForBlocksError < ArgumentError | ||
def initialize | ||
super ("There is a 5-room maximum limit for block reservations.") | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
#Hotel.rb | ||
require 'awesome_print' | ||
require 'date' | ||
require 'pry' | ||
|
||
module Hotel_Chain | ||
class Hotel | ||
|
||
attr_reader :rooms, :reservations, :blocks | ||
|
||
def initialize(no_of_rooms = 20) | ||
@rooms = Array.new(no_of_rooms) | ||
no_of_rooms.times do |room| | ||
@rooms[room] = Room.new(room+1) | ||
@reservations = [] | ||
@blocks = [] #an array of block objects | ||
end | ||
end | ||
|
||
def list_rooms | ||
list_array = [] | ||
i = 0 | ||
@rooms.each do |object| | ||
list_array << "#{i+1}. Room #{object.room_id} - $#{object.rate}/night" | ||
i += 1 | ||
end | ||
return list_array | ||
end | ||
|
||
def find_reservations_by_date(date) | ||
reservations_on_date = [] | ||
@reservations.each do |reservation| | ||
if (reservation.check_in_date...reservation.check_out_date).cover?(Date.strptime(date, "%m/%d/%Y")) | ||
reservations_on_date << reservation | ||
end | ||
end | ||
return reservations_on_date | ||
end | ||
|
||
def print_reservations_by_date(date) | ||
array = [] | ||
reservations_on_date = self.find_reservations_by_date(date) | ||
reservations_on_date.each do |reservation| | ||
array << "Room #{reservation.room.room_id} is reserved from #{reservation.check_in_date} to #{reservation.check_out_date}" | ||
end | ||
return array | ||
end | ||
|
||
def store_reservation(check_in_date, check_out_date) | ||
available_rooms = [] | ||
#ap "STORE_RESERVATION START: reservations: #{reservations}" | ||
if @reservations.length == 0 #i.e. there are no reservations at all | ||
new_reservation = Hotel_Chain::Reservation.new(check_in_date, check_out_date) | ||
new_reservation.room = @rooms[0] | ||
@reservations << new_reservation | ||
return new_reservation | ||
elsif @reservations.length > 0 | ||
available_rooms = find_rooms_available(check_in_date, check_out_date) | ||
if available_rooms.length == 0 | ||
raise ReservationNotAvailableError | ||
else | ||
new_reservation = Hotel_Chain::Reservation.new(check_in_date, check_out_date) | ||
new_reservation.room = available_rooms[0] | ||
@reservations << new_reservation | ||
return new_reservation | ||
end | ||
end | ||
end | ||
|
||
def find_rooms_available(check_in_date, check_out_date) | ||
unavailable_rooms = [] | ||
|
||
check_in = Date.strptime(check_in_date, "%m/%d/%Y") | ||
check_out = Date.strptime(check_out_date, "%m/%d/%Y") | ||
|
||
@rooms.each do |room| | ||
@reservations.each do |reservation| | ||
# checks for unavailable rooms | ||
if room.room_id == reservation.room.room_id && reservation.block_reserved == true | ||
unavailable_rooms << room | ||
elsif room.room_id == reservation.room.room_id && reservation.check_in_date < check_in && (reservation.check_out_date < check_out && reservation.check_out_date > check_in) | ||
unavailable_rooms << room | ||
elsif room.room_id == reservation.room.room_id && (reservation.check_in_date < check_out && reservation.check_in_date > check_in) && reservation.check_out_date > check_out | ||
unavailable_rooms << room | ||
elsif room.room_id == reservation.room.room_id && (reservation.check_in_date > check_in && reservation.check_in_date < check_out) && (reservation.check_out_date < check_out && reservation.check_out_date > check_in) | ||
unavailable_rooms << room | ||
elsif room.room_id == reservation.room.room_id && reservation.check_in_date < check_in && reservation.check_out_date > check_out | ||
unavailable_rooms << room | ||
elsif room.room_id == reservation.room.room_id && reservation.check_in_date == check_in | ||
unavailable_rooms << room | ||
elsif room.room_id == reservation.room.room_id && (reservation.check_in_date > check_in && reservation.check_in_date < check_out) && reservation.check_out_date == check_out | ||
unavailable_rooms << room | ||
end | ||
end | ||
end | ||
final_available_rooms = @rooms - unavailable_rooms | ||
return final_available_rooms | ||
end | ||
|
||
|
||
def reserve_block(party_name, check_in, check_out, no_of_rooms, room_rate) | ||
if no_of_rooms > 5 | ||
raise ExceededRoomLimitForBlocksError | ||
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. Good use of a custom Error. |
||
end | ||
|
||
local_reservation_array = [] | ||
available_rooms = find_rooms_available(check_in, check_out) | ||
|
||
if available_rooms.length < no_of_rooms | ||
raise ArgumentError.new("There are not enough rooms available to reserve that block") | ||
else | ||
no_of_rooms.times do |room| | ||
new_reservation = store_reservation(check_in, check_out) | ||
new_reservation.room.rate = room_rate | ||
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. room rate should be passed in when you create the reservation. |
||
new_reservation.block_reserved = true | ||
new_reservation.status = "unassigned" | ||
@reservations << new_reservation | ||
local_reservation_array << new_reservation | ||
end | ||
end | ||
|
||
#I want the block object to have these attributes for ease of reference. | ||
new_block = Block.new(party_name, check_in, check_out, room_rate, local_reservation_array) | ||
@blocks << new_block | ||
return new_block | ||
end | ||
|
||
def find_unassigned_block_reservations(party_name) | ||
#if the block has the party name, then return that block | ||
this_block = nil | ||
@blocks.each do |block| | ||
if block.party_name == party_name | ||
this_block = block | ||
end | ||
end | ||
|
||
if this_block == nil | ||
raise NoPartyByThatNameError | ||
end | ||
|
||
unassigned_reservations = [] | ||
this_block.reservations.each do |reservation| | ||
if reservation.status == "unassigned" | ||
unassigned_reservations << reservation | ||
end | ||
end | ||
|
||
if unassigned_reservations.empty? | ||
raise AllBlockRoomsAssignedError | ||
end | ||
|
||
return unassigned_reservations | ||
end | ||
|
||
def assign_block_reservation(party_name) | ||
unassigned_reservations = find_unassigned_block_reservations(party_name) | ||
unassigned_reservations[0].status = "assigned" | ||
return unassigned_reservations[0] | ||
end | ||
|
||
#this can be used to find if there is a block reservation party name in the system | ||
def match_block_partyname(party_name) | ||
reserved_under = [] | ||
@blocks.each do |block| | ||
if (block.party_name.downcase).match(party_name.downcase) | ||
reserved_under << block.party_name | ||
ap block.party_name | ||
end | ||
end | ||
return reserved_under | ||
end | ||
|
||
#Allow a user to set different rates for different rooms | ||
def create_custom_rate(check_in_date, check_out_date, rate) | ||
new_reservation = store_reservation(check_in_date, check_out_date) | ||
new_reservation.room.rate = rate | ||
return new_reservation | ||
end | ||
|
||
end #end of class | ||
end #end of module |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#reservation.rb | ||
|
||
require 'awesome_print' | ||
require 'date' | ||
|
||
module Hotel_Chain | ||
class Reservation | ||
|
||
attr_accessor :check_in_date, :check_out_date, :room, :HOTEL, :cost, :status, :block_reserved | ||
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. You have a lot of You should either have a method that does the calculation for the cost of the reservation or set the cost in the |
||
|
||
HOTEL = Hotel_Chain::Hotel.new | ||
|
||
#A new reservation object can be initialized by providing the check_in_date and check_out_date | ||
#Initialization converts the admin's date inputs to convert to Ruby Date objects, and stores them in instance variables. | ||
#After a reservation is created, this program randomly assigns a room object (without checking to see if it's available). | ||
#I may also like to have the program assign a reservation_id (this info can live in a spreadsheet)- then I will need a method to look up a reservation by reservation_id | ||
#reservation_ID would be set as default value of 0 here and then set in the store_reservation method based on existing reservations. | ||
def initialize(check_in_date, check_out_date, status = "assigned") | ||
begin | ||
@check_in_date = Date.strptime(check_in_date, "%m/%d/%Y") | ||
@check_out_date = Date.strptime(check_out_date, "%m/%d/%Y") | ||
@room = HOTEL.rooms.sample | ||
@status = "assigned" #all reservations default to "assigned", unless they are reservations made in a block | ||
@block_reserved = false #defaults to false. the reserve_block method changes this to true. | ||
rescue ArgumentError | ||
raise WrongDateFormatError | ||
end | ||
end | ||
|
||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#Room.rb | ||
require 'awesome_print' | ||
|
||
module Hotel_Chain | ||
class Room | ||
|
||
attr_reader :room_id | ||
attr_accessor :rate | ||
|
||
def initialize(room_id, rate = 200) | ||
@room_id = room_id | ||
@rate = rate | ||
end | ||
|
||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#block_spec.rb | ||
|
||
require_relative 'spec_helper.rb' | ||
require 'date' | ||
require 'pry' | ||
|
||
describe "The Block class" do | ||
|
||
before do | ||
@hotel = Hotel_Chain::Hotel.new | ||
end | ||
|
||
describe "Initializing the Block" do | ||
|
||
it "can be initialized" do | ||
block_A = Hotel_Chain::Block.new("Mary Smith", "9/25/17", "9/29/17", 150, []) | ||
block_A.class.must_be_kind_of Class | ||
end | ||
|
||
end #end describe | ||
end #final 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.
This method seems overly complicated.