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

Pipes - Nkiru - Hotel #42

Open
wants to merge 56 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
d0e1d07
Added a Rakefile
nkiruka Sep 6, 2017
65c8d1a
Created file new file
nkiruka Sep 6, 2017
cb76466
Created new file for hotel class
nkiruka Sep 6, 2017
9cb7c61
Create new file for reservation class
nkiruka Sep 6, 2017
79f37d4
Created spec helper file
nkiruka Sep 6, 2017
30be2cd
Created new test file for date_range class
nkiruka Sep 6, 2017
c515095
Created test file for reservation class
nkiruka Sep 6, 2017
8b2cf49
Added a module
nkiruka Sep 6, 2017
74db4bb
Created test for initialize method
nkiruka Sep 6, 2017
2b103c7
Created test for initialize method
nkiruka Sep 6, 2017
3115b7c
Added date_range file
nkiruka Sep 6, 2017
131a909
Created date_include method
nkiruka Sep 6, 2017
91a6c29
Added test for date_include method
nkiruka Sep 6, 2017
2947707
Added test for invalid date entry
nkiruka Sep 6, 2017
329fe9b
Refactored tests
nkiruka Sep 6, 2017
0d89d32
Created overlap method
nkiruka Sep 6, 2017
dbaf7ec
Tested date overlap method
nkiruka Sep 6, 2017
28d0ad4
Added 4 additional tests for overlap method
nkiruka Sep 6, 2017
673c52f
Modified the overlap method
nkiruka Sep 6, 2017
a66fab8
Added room and booking_system to spec file
nkiruka Sep 7, 2017
b0adc07
Created initialize method
nkiruka Sep 7, 2017
53455cc
Created initialize and self methods
nkiruka Sep 8, 2017
4cff4f1
Added tests for initialize and self methods
nkiruka Sep 8, 2017
8c999db
Added another test for the all method
nkiruka Sep 8, 2017
9ab879a
Added another test for the all method
nkiruka Sep 8, 2017
b56f895
Added total cost method
nkiruka Sep 8, 2017
eadd6a8
Added initialize and total cost tests
nkiruka Sep 8, 2017
cde4005
created room class
nkiruka Sep 11, 2017
6add0b1
Added test for initialize method
nkiruka Sep 11, 2017
5d95ca1
Added additional tests for initialize method
nkiruka Sep 11, 2017
20617e1
removed unnecessary code
nkiruka Sep 11, 2017
399047b
Added tests for initialize and total cost methods
nkiruka Sep 11, 2017
b37015d
Edited initialize method
nkiruka Sep 11, 2017
87a1a93
Modified all tests
nkiruka Sep 11, 2017
3a2f997
Added new variable to include and overlap methods
nkiruka Sep 11, 2017
27f9dd5
Corrected date_range in include method
nkiruka Sep 11, 2017
f31d007
Added edge case testing for include method
nkiruka Sep 11, 2017
ca75b74
Fixed indentation
nkiruka Sep 11, 2017
3b33547
Fixed indentation
nkiruka Sep 11, 2017
480123a
Added initialize method
nkiruka Sep 11, 2017
fba8b6e
Added test for initialize method
nkiruka Sep 11, 2017
c7837c0
Added additional tests for initialize method
nkiruka Sep 11, 2017
1f6bf91
Removed duplicate code
nkiruka Sep 11, 2017
ac710dc
Edited total_cost method
nkiruka Sep 11, 2017
a505e08
Edited tests
nkiruka Sep 11, 2017
8c75ea9
Added another test to total cost
nkiruka Sep 11, 2017
23f7d89
Edited file
nkiruka Sep 11, 2017
eb78ee2
Added test for room available method
nkiruka Sep 11, 2017
137fe73
Edited room available method to check the correct index
nkiruka Sep 12, 2017
6d339d3
test on room availability passed
nkiruka Sep 12, 2017
7004075
Edited files
nkiruka Sep 12, 2017
81b1408
Update booking_system.rb
nkiruka Sep 12, 2017
bc0f84c
Completed design activity
nkiruka Oct 2, 2017
d878eaf
Update design activity
nkiruka Oct 2, 2017
a407a32
changed the argument name in the overlap method for reservation class
nkiruka Oct 2, 2017
09eaff3
removed comments
nkiruka 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ build-iPhoneSimulator/
/_yardoc/
/doc/
/rdoc/
.DS_Store

## Environment normalization:
/.bundle/
Expand Down
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 = true
t.test_files = FileList['specs/*_spec.rb']
end

task default: :test
108 changes: 108 additions & 0 deletions design-activity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
What classes does each implementation include? Are the lists the same?

Implementation A & B includes the following classes:
CartEntry
ShoppingCart
Order

Write down a sentence to describe each class.
implementation A:
Class CartEntry stores the unit price and quantity of an item

ShoppingCart stores the collection of all the items

Order creates a new ShoppingCart and calculates the subtotal and total price for the items.

Implementation B:
CartEntry stores the unit price and quantity of an item and calculates the price for each item.

ShoppingCart stores the collection of all the items and calculates the subtotal of all the items.

Order creates a new ShoppingCart and calculates the total price of all the items by taking the subtotal from the ShoppingCart class and adding 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.

What data does each class store? How (if at all) does this differ between the two implementations?
Implementation A
CartEntry class stores unit price and quantity

ShoppingCart class stores an array of all the cart entry items

Order class stores the sales tax (constant) and shopping cart object.

Implementation B
CartEntry stores the unit price and quantity

ShoppingCart stores an array of the cart entry items

Order stores sales tax (constant) and shopping cart object.

Both implementations are the same with regards to what is stored in each class.


What methods does each class have? How (if at all) does this differ between the two implementations?
Implementation A
CartEntry - initialize method
ShoppingCart - initialize method
Order - Initialize method and total price method

Implementation B
CartEntry - Initialize method and price method
ShoppingCart - Initialize method and price method
Order - Initialize and total price method

In Implementation B, CartEntry and ShoppingCart each has 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?
Implementation A
Logic to compute price is retained in Order.

Implementation B
Logic to compute price is delegated to the CartEntry and ShoppingCart classes. Order only requires the subtotal when a ShoppingCart object is created to calculate the total price with tax.

Does total_price directly manipulate the instance variables of other classes?
No, it doesn't but in Implementation A, the Order class has access to the instances variables in the CartEntry and ShoppingCart classes.

If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify?
Implementation B
BULK_QUANTITY = 100
DISCOUNT = 0.1

def price
if @quantity >= BULK_QUANTITY
return @unit_price * @quantity * (1.0 - DISCOUNT)
else
return @unit_price * @quantity
end
end

Implementation B is a better option because only CartEntry will need to be modified without causing major changes downstream.

In Implementation A, the discount price and bulk quantity will need to added to the Order class.

Which implementation better adheres to the single responsibility principle?
Implementation B, each class is responsible for it's own behavior and state.

Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled?
Implementation B. According to Sandi Metz, the more one class knows about another, the more tightly it is coupled (as seen in Implementation A).

In Implementation A, Order class knows the order of CartEntry's arguments (i.e unit price & quantity)
Order class has access to CartEntry's unit price & quantity due to the attr_reader. Order class knows the name of another class i.e cart = ShoppingCart.new as well as CartEntry (I made the assumption that entry is an instance of CartEntry)

In Implementation B, there is no attr_reader and each class has its own specific responsibility.

Once you've responded to the prompts, git add design-activity.md and git commit!


HOTEL ACTIVITY

It seems that most of my classes are loosely coupled but there is opportunity to refactor the booking system.

In the BookingSystem class, (lines 41 and 54), it will be better to create a new method for reservation date range in reservation class and call it in print reservation and room available methods.

Check the date_range in the reservation class instead of calling the method directly in the booking system class. Furthermore, I can remove date_range from the attribute reader in the reservation class (I tried this and it is not true!).

After transferring the responsibility of checking if a reservation date overlaps to the reservation class, I am not so sure it was necessary. It seems to make more sense to me initially the way it was designed. That is, check if a reservation check is available then book. Thoughts please.
166 changes: 166 additions & 0 deletions lib/booking_system.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
require_relative 'room'
require_relative 'reservation'
require_relative 'date_range'
require 'date'


module Hotel
class BookingSystem
attr_reader :collection_of_rooms, :collection_of_reservations, :block_rooms

#Access list of all rooms in the hotel.
def initialize
@collection_of_reservations = []
@collection_of_rooms = []
@block_rooms = []
build_rooms
# is it better to create a separate method and call in initialize?
# 20.times do |i|
# room = Hotel::Room.new(i + 1, 200)
# @collection_of_rooms << room
# end
end

def build_rooms
20.times do |i|
room = Hotel::Room.new(i + 1, 200)
@collection_of_rooms << room
end
end
#
# def make_block_rooms(date_range, num_rooms)
#
# end
# end
# # take in the num_rooms to determine # iteration
# # loop through the collection_of_rooms to find the first available rooms that match criteria
# # if you find the num_rooms before looping through entire array, break; if not continue
# end


def print_reservations(date_range)
reservation_list = []
@collection_of_reservations.each do |reservation|
if reservation.date_range.date_include?(date_range)
# refactor: create new method for reservation date range in reservation class and call it in print reservation.
reservation_list << reservation
end
end
return reservation_list
end

def room_available(room_number, res_date)
room_is_available = true

@collection_of_reservations.each do |reservation|
reserved_rooms = reservation.reserved_rooms
# overlap = reservation.date_range.date_overlap?(date_range) #initial design
if !reservation.overlap(res_date) # new design
# # refactor
# puts reserved_rooms.class
reserved_rooms.each do |room|
puts room.room_num
if room.room_num == room_number && overlap == true
room_is_available = false
end
end
else
return false
end
end

# if room_is_available
# @block_rooms.each do |block|
# block.include room.room_num
# room_is_available = false
# if the room is in a block for that date range, room_is_available = false
# end

return room_is_available
end

def make_reservation(name,room_num,date_range)
reserved_rooms = []

if room_available(room_num,date_range) == true

reserved_rooms << @collection_of_rooms[room_num - 1]
reservation = Hotel::Reservation.new(name,reserved_rooms,date_range)
@collection_of_reservations << reservation
else
raise ArgumentError.new("Room unavailable")
end
return reservation
end

end #end of class
end # end of module

<<<<<<< HEAD
#TESTING#####
# new_reservation = Hotel::BookingSystem.new
# # puts new_reservation.collection_of_rooms
# checkin_date = Date.new(2001,01,01)
# checkout_date = Date.new(2001,01,31)
# dates = Hotel::DateRange.new(checkin_date, checkout_date)
# puts new_reservation.make_reservation("bob", 1, dates)
# puts
# puts new_reservation.collection_of_reservations
# #
# trey = new_reservation.make_reservation("trey", 2, dates)
# puts trey.total_cost
# puts "this is the total cost"
# new_reservation.collection_of_reservations


#TESTING FOR AVAILABILITY
# puts new_reservation.room_available(1)
# puts new_reservation.room_available(9)
# checkin_date = Date.new(2001,01,05)
# checkout_date = Date.new(2001,01,14)
# dates = Hotel::DateRange.new(checkin_date, checkout_date)
# new_reservation.make_reservation("trey", 2, dates)
# puts new_reservation.print_reservations(dates)
# checkin_date = Date.new(2001,01,30)
# checkout_date = Date.new(2001,02,2)
# dates = Hotel::DateRange.new(checkin_date, checkout_date)
# new_reservation.make_reservation("suyi", 3, dates)

# puts
# puts
##TESTING FOR OVERLAP
# checkin_date = Date.new(2001,02,2)
# checkout_date = Date.new(2001,02,10)
# dates = Hotel::DateRange.new(checkin_date, checkout_date)
# puts
# puts new_reservation.room_available(1,dates)
# puts new_reservation.make_reservation("bob", 1, dates)
# puts new_reservation.collection_of_reservations
#
#
# checkin_date = Date.new(2001,02,3)
# checkout_date = Date.new(2001,02,7)
# dates = Hotel::DateRange.new(checkin_date, checkout_date)
# puts new_reservation.room_available(1,dates)
# #
# checkin_date = Date.new(2001,02,3)
# checkout_date = Date.new(2001,02,14)
# dates = Hotel::DateRange.new(checkin_date, checkout_date)
# puts new_reservation.room_available(1,dates)
# puts
# checkin_date = Date.new(2001,01,3)
# checkout_date = Date.new(2001,01,7)
# dates = Hotel::DateRange.new(checkin_date, checkout_date)
# puts new_reservation.room_available(1,dates)
# puts
# puts
#
# checkin_date = Date.new(2017,01,3)
# checkout_date = Date.new(2017,01,7)
# dates = Hotel::DateRange.new(checkin_date, checkout_date)
#
# rooms = [2,3,4,5,6]

# puts new_reservation.reserve_block_rooms(dates, rooms)
=======
>>>>>>> 81b14087aa1e4a11764bcae28888d634dd8d6e74
58 changes: 58 additions & 0 deletions lib/date_range.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
require 'date'

module Hotel
class DateRange
attr_reader :checkin_date, :checkout_date

# Checkin and checkout dates are instances of the Date class
def initialize(checkin_date, checkout_date)
if !checkin_date.is_a?(Date) || !checkout_date.is_a?(Date)
raise ArgumentError.new("Checkin or Checkout dates is not Date object")
end

if checkin_date > checkout_date
raise ArgumentError.new("Checkin date must be before Checkout date")
end

@checkin_date = checkin_date
@checkout_date = checkout_date
end

# check if reservation date request is within date range.
def date_include?(date_range)
# if date >= @checkin_date && date <= @checkout_date
start_date = date_range.checkin_date
end_date = date_range.checkout_date

if start_date >= @checkin_date && end_date <= @checkout_date
return true
else
return false
end
end

# check if the room is overbooked
def date_overlap?(date_range)
#(@checkin_date - end_date) * (start_date - @checkout_date) >= 0
# Will this method work?
start_date = date_range.checkin_date
end_date = date_range.checkout_date

if (start_date <= @checkout_date) && (end_date > @checkin_date)
return true
else
return false
# raise ArgumentError.new("#{start_date} and #{end_date} are outside the date range")
end
end

end #end of class
end #end of module


#### TESTING ##########

# checkin_date = 2001,2,3
# checkout_date = 2001,2,14
# date = Hotel::DateRange.new(checkin_date, checkout_date)
# puts date.date_include?(2001,2,5)
9 changes: 9 additions & 0 deletions lib/hotel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require_relative 'booking_system.rb'
require_relative 'date_range.rb'
require_relative 'reservation.rb'
require_relative 'room.rb'
require 'date'

module Hotel

end
Loading