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

Ampers - Abinnet #41

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
963ba6c
tests written and passed for room and admin class
Abiaina Mar 5, 2018
881a7d5
room, admin, reservation classes passing tests; most of wave 1 completed
Abiaina Mar 5, 2018
48a4ce0
completed admin code for generating new reservations, missing adequat…
Abiaina Mar 5, 2018
5860f19
some tests pass, missing wave 1 price at reservation and booking inqu…
Abiaina Mar 6, 2018
5531ef5
passes test, most of wave 1 completed
Abiaina Mar 6, 2018
224e90e
admin and reservation decoupled, confirms valid date entry for reserv…
Abiaina Mar 8, 2018
c166e23
reservation class instantiated
Abiaina Mar 8, 2018
1a453d0
removed room instances from admin, updated testing for admin to take …
Abiaina Mar 8, 2018
58a770e
calculate reservation cost in reservation cost, testing for calling c…
Abiaina Mar 8, 2018
d7a17f8
books reservation from 2 dates, assigns room, testing confirms reserv…
Abiaina Mar 8, 2018
dd6e2d1
can search for reservations with check-in/check-out range that inters…
Abiaina Mar 8, 2018
46f2d1c
removed room class
Abiaina Mar 8, 2018
d0f6177
return room id by reservation, corrected testing for reservations arr…
Abiaina Mar 8, 2018
e659624
testing for availble rooms by date outline
Abiaina Mar 8, 2018
467cf83
determines available rooms for certain date ranges, test written and …
Abiaina Mar 8, 2018
45dbe06
available_rooms logic fixed, tests updated and passing
Abiaina Mar 8, 2018
81e50a1
outline testing for updates to add_reservation, compares new reservat…
Abiaina Mar 9, 2018
b2adbf4
completed most of testing for making new reservation without conflict…
Abiaina Mar 11, 2018
8782399
argument error raised for reservations attempted in fully booked hotel
Abiaina Mar 11, 2018
317c6f7
testing completed for preventing double assigning the same room
Abiaina Mar 11, 2018
47cf59b
raises argument for no available rooms reservation attempt, reassigns…
Abiaina Mar 11, 2018
ca58274
raises argument error when attempting to book a reserved room, does n…
Abiaina Mar 11, 2018
d6ecd15
block class created and testing for block class started
Abiaina Mar 11, 2018
cab4d12
admin can block rooms, set variable rate, reserve rooms in and out of…
Abiaina Mar 13, 2018
96f08c2
error fixed using .dup, removed code that removes list of blocked roo…
Abiaina Mar 15, 2018
ea49bb3
answered design-activity prompts
Abiaina Apr 2, 2018
19c7d16
created outline for design improvements decoupling the reservation an…
Abiaina Apr 2, 2018
d9a1374
removed instance variable price from admin class
Abiaina Apr 3, 2018
d44fc34
moved logic for new reservation of block into block_room class
Abiaina Apr 3, 2018
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
Binary file added .DS_Store
Binary file not shown.
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
55 changes: 55 additions & 0 deletions design-activity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
What classes does each implementation include? Are the lists the same?
Both A & B have classes: CartEntry, ShoppingCart, and Order. Yes, the list of classes are the same for both implementations.

Write down a sentence to describe each class.
CartEntry: Tracks the quantity of each item ordered and their individual item costs. B has a method to calculate cost of items.

ShoppingCart: Tracks the items ordered, can calculate the subtotal or order. B has a method to calculate running subtotal.

Order: Calculates the total for each order, B does relies on its other classes and their methods to do the logic required.

How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper.
Order class creates a shopping cart that has an instance variable entries that can store instances of Cart entries. This is then used to calculate total price with the order class' total_price instance method.


What data does each class store? How (if at all) does this differ between the two implementations?
CartEntry: stores number quantity of an item and item unit price. Implementation B also has a method to return the price accounting only for item quantity.

ShoppingCart: Stores instance of CartEntry. Implementation B calculates subtotal of all items in a cart.

Order: creates instances of ShoppingCart and calculates the total_price of all items. ShoppingCart is an array that can hold instances of CartEntry.


What methods does each class have? How (if at all) does this differ between the two implementations?
CartEntry & ShoppingCart Implementation A: no instance methods, except for initialize.

CartEntry & ShoppingCart Implementation B: has 2 helper methods to calculate subtotal of instance variables values.

Order Implementation A & B: Stores instance of CartEntry. Implementation B calculates subtotal of all items in a cart.

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: It is computed in Order.

Implementation B: It is completed in all the classes. Total base price per item in CartEntry. Subtotal for all entries in ShoppingCart is called in ShoppingCart. Order does the final calculates the total or the order.

Does total_price directly manipulate the instance variables of other classes?
If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify?
Implementation A: Yes it acts on the CartEntry class using instance variables unit_price and quantity.

Implementation B: Yes it acts directly on the ShoppingCart instance using the price instance method of the ShoppingCart class.

Which implementation better adheres to the single responsibility principle?
Implementation B because it only calculates the total price based on the subtotal returned by the ShoppingCart price instance method and shares the logic required for calculating the total across all of the classes.

Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled?

Implementation B because it separates uses a local variable subtotal and instance variable #@cart to shield the ShoppingCart instance from the calculation done by total_price method of Order.


Revisiting Hotel Activity
There are a couple of places where I violate the single responsibility rule for classes.

I chose to remove the instance variable price in admin and use a local variable to store the block room prices. This did not require any changes to my testing.

I also decided to change the block_add_reservation instance method in admin and move the logic and making of new reservation into block_room class. The tests pass still.
94 changes: 94 additions & 0 deletions lib/admin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
require 'date'
require_relative 'reservation'
require_relative 'block_room'

class Admin
attr_reader :roomlist, :reservations, :blocks

def initialize
@roomlist = []
@reservations = []

#array of block instances
@blocks = []

20.times do |i|
@roomlist << (i + 1)
end
end

def add_reservation(check_in, check_out, room_id)
available_rooms = available_rooms(check_in, check_out)

if !(available_rooms.include?(room_id))
raise ArgumentError.new("#{room_id} is booked for these dates")
end

if available_rooms.count == 0

Choose a reason for hiding this comment

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

Ummm.. if there were no rooms then available_rooms would not include room_id.

raise ArgumentError.new("No available roooms")
end

@reservations << Reservation.new(check_in, check_out, room_id)
end


def available_rooms(check_in, check_out)

check_in = Date.parse(check_in)
check_out = Date.parse(check_out)

rooms = @roomlist.dup

@reservations.each do |reservation|
valid_check_in = check_in.between?(reservation.start_date, (reservation.end_date - 1))


valid_check_out = check_out.between?((reservation.start_date + 1), reservation.end_date)

if valid_check_in && valid_check_out
rooms.delete(reservation.room_id)
end
end
return rooms
end

def new_block(check_in, check_out, number_of_rooms, rate)
block_rooms_ids = []

rooms_available = available_rooms(check_in, check_out)

if number_of_rooms <= 5 && rooms_available.count >= number_of_rooms
number_of_rooms.times do
block_rooms_ids << rooms_available[0]
end

block = BlockRoom.new(check_in, check_out, rate, block_rooms_ids)

@blocks << block
else
raise ArgumentError.new("Can only block 5 rooms at a time. Can only block available rooms. There are #{available_rooms.count} rooms.")
end
end

# Modified this method
def block_add_reservation(block)
new_rez = block.reserve_block

@reservations << new_rez
end

def bookings_by_date(date)
bookings_by_day = []

date = Date.parse(date)

@reservations.each do |booking|
if date.between?(booking.start_date, booking.end_date)
bookings_by_day << booking
end
end

return bookings_by_day
end

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

class BlockRoom

attr_reader :reservations, :blocked_rooms_ids, :check_in, :check_out, :rate

def initialize(check_in, check_out, rate, blocked_rooms_ids)
if blocked_rooms_ids.count > 5 || blocked_rooms_ids.count < 1 || rate >= 200
raise ArgumentError.new("Room Blocks must range 1 to 5 rooms, rate must be <200")
end

@check_in = Date.parse(check_in)
@check_out = Date.parse(check_out)
@rate = rate
@reservations = []

# an array of blocked room's ids
@blocked_rooms_ids = blocked_rooms_ids
end

def add_reservation(reservation)
if @reservations.count > 4 || !@blocked_rooms_ids.include?(reservation.room_id)
raise ArgumentError.new("Room Block")
else
@reservations << reservation
end
end

# Valid to make this block?
def new_block(check_in, check_out, number_of_rooms, rate)
block_rooms_ids = []

rooms_available = available_rooms(check_in, check_out)

if number_of_rooms <= 5 && rooms_available.count >= number_of_rooms
number_of_rooms.times do
block_rooms_ids << rooms_available[0]
end

block = BlockRoom.new(check_in, check_out, rate, block_rooms_ids)

@blocks << block
else
raise ArgumentError.new("Can only block 5 rooms at a time. Can only block available rooms. There are #{available_rooms.count} rooms.")
end
end

# Modified this method
def reserve_block
new_rez = Reservation.new(@block.check_in.to_s, @block.check_out.to_s, @block.blocked_rooms_ids[0])

@block.add_reservation(new_rez)

return new_rez
end

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

class Reservation

Choose a reason for hiding this comment

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

I would suggest a method in reservation which either takes a Reservation or a date range and returns true if it overlaps with this reservation and false if it does not. It might make the logic easier in Admin.


attr_reader :end_date, :start_date, :stay, :cost, :room_id

def initialize(start_date, end_date, room_id)
valid = true
if valid_dates?(start_date, end_date)
@start_date = Date.parse(start_date)
@end_date = Date.parse(end_date)
else
valid = false
end
stay_length if valid

if !@stay || !valid
raise ArgumentError.new("Invalid date(s)")
end

@room_id = room_id
end

def valid_dates?(start_date, end_date)
valid = true
begin
Date.parse(start_date)
Date.parse(end_date)
rescue
valid = false
end
return valid
end

def stay_cost
@cost = @stay * 200
end

def stay_length
@stay = false
date_order = @start_date <=> @end_date
if date_order < 0
@stay = (@end_date.mjd - @start_date.mjd)
stay_cost
end
end
end
Loading