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-Mariana-Hotel #26

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
70 changes: 70 additions & 0 deletions design-activity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
Q: What classes does each implementation include? Are the lists the same?

A: Both implementation have the same classes names, but classes itself are different. Those classes are:
* CartEntry
* ShoppingCArt
* Order

Q: Write down a sentence to describe each class.

A:
* Implementation A - CartEntry: It initializes one product that have two instances variables quantity and unit_price.

* Implementation B - CartEntry: It initialize a product with two instances variables, unit_price and quantity. It calculates the total price of the product.

* Implementation A - ShoppingCart: It creates an empty array to place all the products.

* B - ShoppingCart: It initializes an empty array to place all the products and calculate the total price for all products without taxes.

* A - Order: It creates a new instance of ShoppingCart. It calculates the total price per product and it sums the total price for all products including taxes.

* B - Order: Creates a new instance of ShoppingCart and add the taxes to the total price.

Q: How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper.

A: Implementation A: The Order class uses CartEntry and ShoppingCart classes. It creates a new instance of ShoppingCart that is call cart. For each element in cart calculate the total price, using the instance variables of the CartEntry class. Sum all this result and add the taxes.

Implementation B: CartEntry calculates the price per entry, the ShoppingCart uses this prices to calculate the total price of all products without taxes. Finally Order class creates an instance of ShoppingCart, it adds the taxes to the total price (calculates in ShoppingCart). This way ShoppingCart is relate to CartEntry and Order is relate to ShoppingCart.

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

A: CartEntry stores unit_price and quantity, ShoppingCart stores entries, Order stores cart that is an instance of ShoppingCart and sales tax. The classes in both implementations store the same data.

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

A:
* CartEntry has the same initialize method in both implementations. In implementation B, there is also a price method that multiplies unit_price by quantity returning the total price per product.

* ShoppingCart has the same initialize method in both implementations. In implementation B there is a price method that returns the sum of the total value for each element in the entries array.

* Order class has the same initialize method in both implementations. The implementation A has a total_price method that calculates the total price per product in cart and add all this values. Later it adds the sales taxes to get the total price. In the implementation B total_price calls the price method from the ShoppingCart class to calculate the total value without taxes, then returns the total value of the order with taxes.

Q: 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: It is better to have price in lower level classes because otherwise all the logic is going to be store at the Order Class and this is not following the single responsibility principle.

Does total_price directly manipulate the instance variables of other classes?

A: In implementation A it manipulates unit_price and quantity from CartEntry class. It also iterates over the entries arrays from ShoppingCart class.

Implementation B doesn't manipulate directly the instance variables of other classes.

Q: If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify?

We need to have some code that checks if for a given quantity of a product we can apply the discount, this should be inside the CartEntry class.

It is easier to change the implementation B because we just need to change the CartEntry class, at the other hand with the implementation A we need to change CartEntry class and the method total_price inside Order class.

Q: Which implementation better adheres to the single responsibility principle?

A: The implementation B, because CartEntry takes care just for single products, ShoppingCart takes care of products inside entries and Order takes care of the order in general. While in implementation A, Order takes care of the single products, items in entries and the order in general.

Revisiting Hotel

When I did hotel the first time I paid special attention to the single responsibility of a class. Now that I'm looking again this project, I think that the DateRange, Block and Reservation classes satisfies the requirements of a good design.

The Admin class is a big class that manages the reservations and store the information about the rooms. I wanted to crate a new class call Rooms. This class would create the hash with rooms using the create_rooms method. But when I was making the changes, I noticed that if I do this, then Admin class would modify the instance variables of Rooms class, so I decided not to modify Admin class.

The change that I did was to put attr_reader or attr_accessor to instance variables, how Metiz books recommends.
93 changes: 93 additions & 0 deletions lib/admin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@

module Hotel
class Admin
attr_reader :list_reservations, :rooms

def initialize
@rooms = {}
@list_reservations = []
create_rooms
end

def add_reservation(checkin, checkout)
dates_to_reserve = Hotel::DateRange.new(checkin, checkout)
rooms.each do |room_number, dates|
if is_room_avaliable?(room_number, dates_to_reserve)
rooms[room_number] << dates_to_reserve
make_reservation = Hotel::Reservation.new(checkin, checkout, room_number)
list_reservations << make_reservation
return make_reservation
end #if
end #each
raise ArgumentError.new( "There are not avaliable rooms for that date range")
end

def reservations_per_day(date)
list_per_day = []
list_reservations.each do |reservation|
if reservation.days_range.include?(date)
list_per_day << reservation
end #if
end #each
return list_per_day
end #method

def create_rooms
20.times do |i|
rooms["#{i + 1}"] = []
end
end

def is_room_avaliable?(room_number, dates_to_reserve)
avaliable = true

rooms[room_number].each do |busy_dates|
if dates_to_reserve.overlap?(busy_dates)
avaliable = false
end#if
end
return avaliable
end

def avaliable_rooms_daterange(checkin, checkout)
avaliable_rooms = []
date_range = Hotel::DateRange.new(checkin,checkout)
@rooms.each do |room_number, dates|
if is_room_avaliable?(room_number, date_range)
avaliable_rooms << room_number
end
end
return avaliable_rooms
end

def can_create_block?(checkin, checkout, number_of_rooms)
if number_of_rooms > 5
raise ArgumentError.new("There is no possible to create a block qith more of 5 rooms")
else
if avaliable_rooms_daterange(checkin, checkout).length >= number_of_rooms
return true
else
return false
end
end
end

def create_block (checkin, checkout, number_of_rooms, price)
rooms_in_block = []
if can_create_block?(checkin, checkout, number_of_rooms)
number_of_rooms.times do
reserve = add_reservation(checkin, checkout)
rooms_in_block << reserve.room_number
end
end

Hotel::Block.new(checkin, checkout, rooms_in_block, price)

end




end #class

end #module
25 changes: 25 additions & 0 deletions lib/block-admin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# require_relative '../lib/admin.rb'
# module Hotel
# class BlockAdmin
# #def initialize
# #@rooms = Hotel::Admin.rooms
# #@list_reservations = Hotel::Admin.list_reservations
# #end
#
# #def can_create_block?
# #end
# def can_create_block?(checkin, checkout, number_of_rooms)
# if number_of_rooms > 5
# raise ArgumentError.new("There is no possible to create a block qith more of 5 rooms")
# else
# if avaliable_rooms_daterange(checkin, checkout).length >= number_of_rooms
# return true
# else
# return false
# end
# end
# end
#
#
# end#class
# end #module
37 changes: 37 additions & 0 deletions lib/block.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module Hotel
class Block
attr_reader :price_per_night, :days_range, :rooms_set

def initialize(checkin, checkout, rooms_set, price)
@price_per_night = price
@days_range = Hotel::DateRange.new(checkin, checkout)
@rooms_set = rooms_set
end

def totalcost_oneroom
price_per_night * days_range.stay_length
end

def room_avaliable_block?
rooms_set.length > 0 ? true : false
end

def reserve
if room_avaliable_block?
rooms_set.delete_at(0)
return rooms_set
else
raise ArgumentError.new("There is not more rooms avaliables in the given block")
end
end









end #class
end #module
42 changes: 42 additions & 0 deletions lib/daterange.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

module Hotel
class DateRange
attr_reader :checkin, :checkout

def initialize(day1, day2)
@checkin = day1
@checkout = day2
valid_date?
end

def valid_date?
if checkin < checkout
true
else
raise ArgumentError.new("No valid input")
end
end

def stay_length
(checkout - checkin).to_i
end

def include?(date)
if checkin <= date && checkout > date
return true
else
return false
end
end

def overlap?(other)
if other.checkin <= self.checkin && other.checkout > self.checkin
return true
elsif other.checkin >= self.checkin && other.checkin < self.checkout
return true
else
return false
end
end
end
end #module
22 changes: 22 additions & 0 deletions lib/reservation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module Hotel
class Reservation
attr_reader :checkin, :checkout, :days_range, :room_number, :price_per_night
def initialize(checkin, checkout, room_number)
@price_per_night = 200
@days_range = Hotel::DateRange.new(checkin, checkout)
@room_number = room_number
end

def totalcost
price_per_night * days_range.stay_length
end

# def room_avaliables(@days_range)
#
# end




end #class Reservation
end
19 changes: 19 additions & 0 deletions lib/rooms.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# module Hotel
# class Rooms
#
# attr_accessor :rooms
#
# def initialize
# @rooms = {}
# create_rooms
# end
#
# def create_rooms
# 20.times do |i|
# @rooms["#{i + 1}"] = []
# end
# end
#
# end #class
#
# end #module
Loading