Skip to content
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

Amy Lee -- Carets #31

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
681579e
Setup of project structure for Hotel project
ayjlee Sep 5, 2017
86e2d67
Created and tested initialize methods for Hotel::Room class
ayjlee Sep 5, 2017
09030e3
First draft of reserve room method and tests written, passing; placeh…
ayjlee Sep 6, 2017
75897f5
added Room.find_by_id method to find a room by it's room number
ayjlee Sep 6, 2017
b2cd5f1
tested that I could have multiple reservations on the same room
ayjlee Sep 6, 2017
9b1783a
get a list of all reservations on a certain date; wrote basic functio…
ayjlee Sep 6, 2017
531f35e
Added test for checking that each room has a nightly rate of 00
ayjlee Sep 6, 2017
3638f06
Wrote cost method that returns the total cost of a reservation, basic…
ayjlee Sep 6, 2017
100fffe
BENCHMARK: Wave 1 test requirements with basic test passing. More tho…
ayjlee Sep 6, 2017
f60aab0
Added a Room helper method, available_all_days?, which will be used t…
ayjlee Sep 7, 2017
107fd3a
can view a list of available rooms for a given date range and reserve…
ayjlee Sep 7, 2017
8d8ca89
Refactored reservations and making reservations to have guest_id as a…
ayjlee Sep 8, 2017
b884efd
added basic tests for making a reservation
ayjlee Sep 8, 2017
420fb74
Created Block class, which currently inherits from Reservation class.…
ayjlee Sep 8, 2017
5de0cd9
Created make_block method in BookingProgram and block_room method in …
ayjlee Sep 8, 2017
729b56f
made the reservation id a required argument to initialize a Reservati…
ayjlee Sep 8, 2017
b56ae49
Added Block to required files
ayjlee Sep 8, 2017
57c76a9
Added new BlockReservation subclass of Reservation. Block is now an i…
ayjlee Sep 8, 2017
f4a8494
Added code and logic for handling block reservations, untested.
ayjlee Sep 8, 2017
3b43cc3
Major refactor- Reservations, BlockReservation, and Blocks all hold R…
ayjlee Sep 8, 2017
7aa52b8
Renamed the Module to be the HotelBooking, and the class to Hotel to …
ayjlee Sep 8, 2017
35e687f
All waves passing, basic tests passing. Need to fix logic for Room's …
ayjlee Sep 9, 2017
6e20e8c
Refactored Room - Rooms only keep track of the IDS for reservations a…
ayjlee Sep 9, 2017
ed4d23c
Refactored all files so that all error handling happened in the Hotel…
ayjlee Sep 11, 2017
af12b8a
Finished Evaluating Responsibility Activity
ayjlee Sep 30, 2017
a4779d8
Refactored to make sure responsibility/logic to reserve a room in a b…
ayjlee Oct 2, 2017
aa4b0dd
Added comments about Hotel Design changes made to improve Single Resp…
ayjlee Oct 2, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Rakefile
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 = false
t.test_files = FileList['specs/*_spec.rb']
end

task default: :test
74 changes: 74 additions & 0 deletions design-activity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
__Hotel Design Changes Made__
I refactored my Hotel program so that all logic and responsibility for reserving a room in a block was in the Block Class instead of the Room class. This is an improvement because Blocks are a special class that have specific rooms, from which a guest can select to create a Block reservation. Room instances do not need to know if they are in a Block, but a Block must know what Rooms it includes, and which are available for booking. Rooms in a Block have special conditions under which they can be reserved, so it makes more sense to have the responsibility and logic to reserve rooms in a block reside in the more specific Block class rather than the general Room class.



1. What classes does each implementation include? Are the lists the same?

Each of the implementations has three classes: CartEntry, ShoppingCart, and Order. The lists are the same.


2. Write down a sentence to describe each class.

CartEntry seems to be any item/purchase you want to put in your cart, and must have a unit price and quantity. A ShoppingCart holds zero or more CartEntries in an array. Orders have a Shopping Cart, and calculate the total price (including Sales Tax) of all of the Cart Entries in the Cart.

3. How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper.
Orders have a ShoppingCart which can hold zero or more CartEntries.

4. What data does each class store? How (if at all) does this differ between the two implementations?

__A__
Cart Entry: @unit_price & @quantity instance variables
ShoppingCart: @entries array
Order: SALES_TAX constant, @cart variable that is an instance of ShoppingCart.

__B__
Cart Entry: @unit_price and @quantity instance variables
ShoppingCart: @entries array
Order: Constant SALES_TAX, @cart variable that is an instance of ShoppingCart


5. What methods does each class have? How (if at all) does this differ between the two implementations?

__A__
CartEntry: Initialize method, accessors for @unit_price and @quantity
ShoppingCart: Initialize method, accessor for @entries
Order: Initialize method, total_price method that calculates the sum of the prices of each entry in the @cart, and returns the total_price including SALEX_TAX.

__B__
CartEntry: Initialize method, price method that returns the price of each CartEntry
ShoppingCart: Initialize method, price method that returns the sum of the prices of each entry in the @cart.
Order: Initialize method, total_price method that returns the total price, including sales tax, of all of the items in the cart.


6. 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?

__A__
The logic to compute the price is retained in Order.

__B__
The logic to compute the price is delegated to "lower level" classes like ShoppingCart and CartEntry.

Does total_price directly manipulate the instance variables of other classes?

__A__
If I'm reading the question correctly, total_price directly manipulates instance variables of other classes in implementation A. It must access the entries array of the @cart instance, then iterate over each CartEntry instance to access the unit_price and quantity of each to calculate the price, sum up the prices of each CartEntry instance, then add the SALES_TAX to get the total_price.

__B__
No; Implementation B calls the .price method on the @cart, then adds the SALES_TAX to calculate the total_price.

7. If we decide items are cheaper if bought in bulk, how would this change the code?

We would have to add logic for the discounted bulk price (e.g. a lower unit_price or some kind of discount that is applied) if someone places a bulk order. We would also have to determine how a bulk order is placed, whether it's a subclass, or if we just add conditionals to our existing

8. Which implementation is easier to modify?

Implementation B- classes better follow single responsibility principle and logic is delegated to "low level" classes, and we can better target only the relevant classes and methods for modification without fear of messing up some other code.

9. Which implementation better adheres to the single responsibility principle?

Implementation B

10. Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled?
25 changes: 25 additions & 0 deletions lib/Block.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

module HotelBooking
class Block
attr_accessor :id, :guest, :check_in, :check_out, :room_ids, :available_rooms
attr_reader :discounted_rate

def initialize(check_in,check_out,room_ids,discounted_rate,block_id)
@check_in = check_in #ruby Date object
@check_out = check_out #ruby Date object
@room_ids = room_ids
@available_rooms = room_ids.dup
@discounted_rate = discounted_rate
@id = block_id
end

def reserve_block_room(room_id)
raise ArgumentError.new("This Block room is not available for this block reservation") if !(@available_rooms.include?(room_id))

@available_rooms.delete(room_id)
end


end

end
19 changes: 19 additions & 0 deletions lib/BlockReservation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require_relative 'Reservation'

module HotelBooking
class BlockReservation < HotelBooking::Reservation
attr_accessor :id, :guest, :check_in, :check_out, :room, :block_id
attr_reader :all_reservations, :type

def initialize(check_in,check_out,room_id, b_res_id, block_discount, guest = nil)
super(check_in,check_out,room_id, b_res_id,block_discount, guest = nil)
@rate = block_discount
@block_id = nil
@type= :block
end #end initialize

def cost
num_nights_charged * @rate
end
end
end
150 changes: 150 additions & 0 deletions lib/Booking.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@

require 'date'
require_relative 'Reservation'
require_relative 'Room'
require_relative 'Block'
module HotelBooking

class Hotel

#The Hotel class holds the data of all rooms, all reservations, and all blocks in the Hotel. It checks for valid dates before creating new reservations, block reservations, and blocks.
attr_reader :all_rooms, :all_reservations, :all_blocks
NUM_STANDARD_ROOMS = 20

def initialize
@all_rooms = HotelBooking::Hotel.setup_rooms
@all_reservations = []
@all_blocks = []
end

def available_rooms(check_in,check_out, block_id = nil)
check_valid_dates(check_in,check_out)
@all_rooms.select {|room| room.available_all_days?(check_in, check_out)}
end

def make_block(check_in,check_out,room_ids,discounted_rate)
check_in_date = Date.parse(check_in)
check_out_date = Date.parse(check_out)


#checks valid dates
check_valid_dates(check_in_date,check_out_date)

#makes sure all rooms intended for the block are available for the date range provided
check_valid_block(check_in_date,check_out_date,room_ids)

block_id = "B" + "#{@all_blocks.count + 1}"

block = HotelBooking::Block.new(check_in_date,check_out_date,room_ids,discounted_rate,block_id)

room_ids.each do |room_id|
room= find_room_by_id(room_id)
room.block_room(check_in_date,check_out_date,block_id)
end

@all_blocks << block

end

def make_reservation(check_in,check_out,room_id, guest_id=nil)

reservation_id = (@all_reservations.count + 1)
room= find_room_by_id(room_id)
check_in_date = Date.parse(check_in)
check_out_date = Date.parse(check_out)

check_valid_dates(check_in_date,check_out_date)

if available_rooms(check_in_date,check_out_date).include?(room)

reservation = HotelBooking::Reservation.new(check_in_date,check_out_date,room_id, reservation_id)

room.reserve_room(check_in_date,check_out_date,reservation_id, guest_id)

@all_reservations << reservation
else
raise ArgumentError.new("This room is already reserved for these dates")
end

end

def make_block_reservation(block_id,room_id,guest_id = nil)
block= find_block_by_id(block_id)
reservation_id = "B" + (@all_reservations.count + 1).to_s

raise ArgumentError.new("This room is not in the block") if !(block.room_ids.include?(room_id))
raise ArgumentError.new("This Block room has already been reserved") if !(block.available_rooms.include?(room_id))

block_reservation = HotelBooking::BlockReservation.new(block.check_in,block.check_out,room_id, reservation_id, block.discounted_rate)
block_reservation.block_id = block_id

block.reserve_block_room(room_id)

@all_reservations << block_reservation

end

def find_room_by_id(room_id)
@all_rooms.each {|room| return room if room.id == room_id}

raise ArgumentError.new "Sorry, we don't have a room matching that ID number."
end

def find_res_by_date(date_str)
date_object= Date.parse(date_str)
@all_reservations.select {|reservation| ((reservation.check_in)..(reservation.check_out)).include?(date_object)}
end

def find_block_by_id(block_id)

@all_blocks.each {|block| return block if block.id == block_id}
raise ArgumentError.new "Sorry, we don't have a block matching that ID number."
end

def find_available_rooms_by_block(block_id)
block= find_block_by_id(block_id)
block.available_rooms
end

def check_valid_block(check_in,check_out,room_ids)
raise ArgumentError.new("Number of rooms in a block must be 5 or under") if room_ids.count > 5

available_rooms_ids = available_rooms(check_in,check_out).map {|room| room.id}

room_ids.each do |room_id|
raise ArgumentError.new("This room is already reserved for the dates provided") if !(available_rooms_ids.include?(room_id))
end

return true

end

def check_valid_dates(check_in, check_out)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love all the small helper methods you made :D I wish that there were a better place to put this specific helper method about checking if it's a valid date that wasn't in Hotel, but I can't think of a better place at the moment.

if check_in < Date.today || check_out < Date.today
raise ArgumentError.new("Can't make reservations for days earlier than today")
end

if check_in.class != Date ||check_out.class != Date
raise ArgumentError.new("Please provide a valid date")
end

if check_out < check_in
raise ArgumentError.new("Invalid Date Range: Check out date is earlier than check-in date.")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to pick a different Error besides ArgumentError (like even writing a custom Error!)

end

end

def self.setup_rooms
standard_rooms = []

(1..NUM_STANDARD_ROOMS).each do |num|
room = HotelBooking::Room.new(num)
standard_rooms << room
end

return standard_rooms
end

end

end
7 changes: 7 additions & 0 deletions lib/Guest.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### OPTIONAL CLASS

module Hotel
class Guest

end
end
28 changes: 28 additions & 0 deletions lib/Reservation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require 'date'
module HotelBooking

class Reservation
attr_accessor :id, :guest, :check_in, :check_out, :room_id
attr_reader :all_reservations, :type, :rate

def initialize(check_in,check_out,room_id, res_id, rate = 200, guest = nil)
@id = res_id
@check_in = check_in #ruby Date object
@check_out = check_out #ruby Date object
@room_id= room_id
@guest = guest
@rate = rate
@type= :standard
end #end initialize

def cost
num_nights_charged * @rate
end

def num_nights_charged
(check_out.mjd - check_in.mjd)
end

end

end
49 changes: 49 additions & 0 deletions lib/Room.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require 'date'

module HotelBooking

class Room
attr_reader :id, :nightly_rate, :type, :reserv_ids, :all_dates, :block_ids, :blocks_available

def initialize(id_number, nightly_rate = 200)
@id = id_number
@nightly_rate = nightly_rate
@type = :standard
@reserv_ids = []
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are @reserv_ids for?

@block_ids = []
@all_dates = []
@blocks_available = []
end

def reserve_room(check_in,check_out,reservation_id, guest_id=nil)

(check_in...check_out).each do |date|
@all_dates << date
end

@reserv_ids << reservation_id
end


def block_room(check_in,check_out,block_id)
if available_all_days?(check_in, check_out)
@blocks_available << block_id

(check_in...check_out).each do |date|
@all_dates << date
end
end

end

def available_all_days?(check_in, check_out)
(check_in..check_out).each do |date|
return false if @all_dates.include?(date)
end

return true
end

end

end
Loading