forked from AdaGold/hotel
-
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
Amper: Kaitlin Forsman #23
Open
kcforsman
wants to merge
35
commits into
Ada-C9:master
Choose a base branch
from
kcforsman:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
cb02ee6
initial setup of lib and spec files so get ready to write tests and s…
kcforsman 385592e
stubbed some tests for user class and wrote tests and code for user i…
kcforsman b9f7f43
added errors for invalid inputs to reserve_room method
kcforsman 40a50e5
small refactor of tests and code
kcforsman 31315fb
initialized reservation class with attributes: id, room_num, guest, s…
kcforsman 3994a23
added night calculator method to reservation class
kcforsman 9b9e88f
trying to structure how to store dates and reservations in relation t…
kcforsman 1166bc7
finished main method and helper method that allows user to look up al…
kcforsman 9556184
finished approach to calculating reservation cost and how user access…
kcforsman 9d711e9
created a room class that has a number and calendar that dates can be…
kcforsman d5ca5a9
cleaned up unused but assigned variables and included a forgotten test
kcforsman fa322f7
refactored all room and reservation to take Range of dates instead of…
kcforsman 8cc9a31
reworked, restructured, wrote tests and codes for method to present a…
kcforsman 1ec19e7
added couple more tests to user_spec to check availability at the end…
kcforsman 2d777b5
double-checked functionality of find_available room: it works and doe…
kcforsman 2289465
correct version of helper spec and set up of new class files for a Block
kcforsman 977b8dd
initialized Block spec and added notes to user for tests and content …
kcforsman 4035cf4
added initial method for block rooms availibility
kcforsman c99adbc
finished block versions of find_available_rooms and reserve_room with…
kcforsman 6865048
finished discounted calculate_reservation_cost method to finish first…
kcforsman f84fde8
stubbed out remaining tests I could think of for Block with the User …
kcforsman 6b2607a
stubbed out remaining tests I could think of for Block within the Use…
kcforsman 89358fb
finished functionality for creating a block within User and adjusting…
kcforsman 001caa3
finished functionality for reserving a room from the block within the…
kcforsman daa21aa
finished last piece of functionality, allowing User to search for ava…
kcforsman bea1945
not sure what i'm committing
kcforsman a87ae30
while everything is still working: refactoring, pulled rooms out of i…
kcforsman dcd77c7
finished answering question for code analysis of Online Shopping Cart…
kcforsman 2192c67
adjusted id assignment for blocks and reservationswith a class variab…
kcforsman 659b5d0
changed code to eliminate other User's direct interaction with each R…
kcforsman cdcff7b
adjusted User class so it doesnt need to directly know a reservations…
kcforsman cfbcbec
deleted attr_reader for @reservations in Block class. it was used no …
kcforsman b4cee38
altered Room and Reservation class, so that reservation does directly…
kcforsman cd3e93b
updated design activity with what discussion of how to improve hotel'…
kcforsman e4ff02c
added some tests to up coverage percentage
kcforsman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#Hotel Revisited | ||
***** | ||
### Questions for Online Shopping Cart Code Implementations: | ||
* What classes does each implementation include? Are the lists the same? | ||
- Both implementations have the same classes: CartEntry, ShoppingCart, and Order. | ||
* Write down a sentence to describe each class. | ||
- CartEntry appears to be a class for containing information about a specific item or product. | ||
- ShoppingCart appears to be a class that stores a list of items or products. | ||
- Order appears to be class for calculating total cost of the ShoppingCart, including SALES_TAX. | ||
* How do the classes relate to each other? It might be helpful to draw a diagram. | ||
- There doesn't appear to be any explicit relationship between the CartEntry and any of the other classes, but I would assume a ShoppingCart could potentially have one or more CartEntry instances. | ||
- An instance of a Order within this implementation has-a ShoppingCart. | ||
* What data does each class store? How (if at all) does this differ between the two implementations? | ||
- The appears to be no difference between the two implementations for the data each class stores: CartEntry stores the \@quantity (of the product) and \@unit_price (cost per product), ShoppingCart stores \@entries (a list of some entries, in this code, like CartEntry instances), and Order stores \@cart (a ShoppingCart) and the constant, SALES_TAX. | ||
* What methods does each class have? How (if at all) does this differ between the two implementations? | ||
- Each implementation as an initialize method for the three classes. | ||
- Implementation A: uses helper methods in each "lower level" class, CartEntry and ShoppingCart. Then, Order#total_price calculates the sum all entries together and adds on sales tax. | ||
- Implementation B: uses no helper methods in any class. Instead, CartEntry and ShoppingCart have price instance methods that calculate the their own prices. Then, Order only has to add the sales tax cost to the price in Order#total_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, I would say the logic is solely retained in Order. | ||
- In Implementation B, the logic is shared between all three classes, as such delegated to the "lower level" classes: ShoppingCart and CartEntry. | ||
* Does total_price directly manipulate the instance variables of other classes? | ||
- In Implementation A, yes, it does (helper methods). | ||
- In Implementation B, no, it does not seem to. | ||
* If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify? | ||
- You would need to add some conditional if quantity > some_amount then unit_price = unit_price * some_discount. This code could be added into the each loop of total_price for Implementation A or the instance method for price of CartEntry in Implementation B. | ||
- As far as difficulty to modify the code to make this possible, I think it would be possible to apply to either method just as easily. It also depends on how complicated the discount logic is. You would need some type of discount for above a certain quantity. If the discount is the same no matter what the item, either method can be changed as easily as the other. If the discount is changes item to item, I think it would be easier to change Implementation B. | ||
* Which implementation better adheres to the single responsibility principle? | ||
- I believe Implementation B adheres better. The Order doesn't have to the responsibility of calculating each CartEntry price then summing all the Entries in the ShoppingCart together to then add on sales tax. | ||
* Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? | ||
- Also, Implementation B. It doesn't have to call on the instance variables of CartEntry or ShoppingCart to find the total price for the order. | ||
***** | ||
### The Hotel Revision | ||
I had a few unnecessary helper methods, so want to change the code, so the classes only have access to the ids of the other classes. This means changing the code so Room doesn't respond to :calendar or :cost, Reservation doesn't respond to :room or :date_range, and Block doesn't respond to :reservations. This is better because if later I change all the information in a class, I can just change that method within the class and the other classes wont know what know any different as long as it is getting the information it needs. | ||
|
||
To revise Hotel, I changed the initialize arguments for Block and Reservation to take a hash instead of separate arguments. I changed the way the classes assign and track ids. Then, I worked on changing all the different classes approach to instance variables of other classes, so that except for ids and room_num, the other classes don't know too much about the others. (hopefully) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
require 'date' | ||
require 'pry' | ||
|
||
module Hotel | ||
class Block < Reservation | ||
@@id = 1 | ||
attr_reader :id | ||
def initialize block_args | ||
super(block_args) | ||
@party = block_args[:party] | ||
@rooms = block_args[:rooms] | ||
@discount = block_args[:discount] | ||
@reservations = [] | ||
@reserved_rooms = [] | ||
end | ||
|
||
def find_available_rooms | ||
available_rooms = [] | ||
return @rooms if @reserved_rooms.empty? | ||
@rooms.each do |room| | ||
next if @reserved_rooms.any? { |reserved_room| reserved_room == room } | ||
available_rooms << room | ||
end | ||
raise StandardError.new("no rooms available") if available_rooms.empty? | ||
available_rooms | ||
end | ||
|
||
def reserve_room(room_num, guest) | ||
room = @rooms[room_num - 1] | ||
raise StandardError.new("room not available") if !find_available_rooms.include?(room) | ||
new_reservation = Reservation.new({id: @@id, room: room, guest: guest, date_range: @date_range}) | ||
@@id += 1 | ||
@reserved_rooms << room | ||
@reservations << new_reservation | ||
new_reservation | ||
end | ||
|
||
def calculate_reservation_cost(reservation_id) | ||
reservation = find_reservation(reservation_id) | ||
((1 - @discount) * reservation.calculate_reservation_cost).round(2) | ||
end | ||
|
||
def find_reservation(reservation_id) | ||
@reservations.find { |reservation| reservation.id == reservation_id } | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
require 'date' | ||
|
||
module Hotel | ||
class Reservation | ||
attr_reader :id | ||
def initialize reservation_args | ||
@id = reservation_args[:id] | ||
@room = reservation_args[:room] | ||
@guest = reservation_args[:guest] | ||
@date_range = reservation_args[:date_range] | ||
end | ||
|
||
def calculate_nights | ||
@date_range.to_a.length | ||
end | ||
|
||
def find_all_dates | ||
@date_range.to_a | ||
end | ||
|
||
def calculate_reservation_cost | ||
@room.calculate_cost(calculate_nights) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
require 'date' | ||
require 'pry' | ||
|
||
module Hotel | ||
class Room | ||
attr_reader :room_num | ||
def initialize(room_num, cost) | ||
@room_num = room_num | ||
@cost = cost | ||
@calendar = [] | ||
end | ||
|
||
def add_to_calendar(date_range) | ||
dates = date_range.to_a | ||
dates.each { | date | @calendar << date } | ||
end | ||
|
||
def is_available date_range | ||
return false if @calendar.any?(date_range) | ||
true | ||
end | ||
|
||
def calculate_cost nights | ||
@cost * nights | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
require 'date' | ||
require 'pry' | ||
|
||
module Hotel | ||
TOTAL_ROOMS = 20 | ||
class User | ||
@@id = 1 | ||
attr_reader :rooms | ||
def initialize(rooms) | ||
if rooms.size != TOTAL_ROOMS | ||
raise StandardError.new("incorrect number of rooms") | ||
end | ||
@rooms = rooms | ||
@reservations = [] | ||
@calendar = {} | ||
end | ||
def find_available_rooms(start_date, end_date) | ||
date_range = (start_date...end_date) | ||
available_rooms = [] | ||
@rooms.each do |room| | ||
available_rooms << room if room.is_available(date_range) | ||
end | ||
available_rooms | ||
# need to deal with no rooms available | ||
end | ||
|
||
def reserve_room(room_num, guest, start_date, end_date) | ||
valid_dates(start_date, end_date) | ||
date_range = (start_date...end_date) | ||
check_room_availibility(room_num, date_range) | ||
room = @rooms[room_num - 1] | ||
id = @reservations.length + 1 | ||
new_reservation = Reservation.new({id: @@id, room: room, guest: guest, date_range: date_range}) | ||
@@id += 1 | ||
add_to_calendar(new_reservation, date_range) | ||
room.add_to_calendar(date_range) | ||
@reservations << new_reservation | ||
new_reservation | ||
end | ||
|
||
def valid_dates(start_date, end_date) | ||
if start_date.class != Date || end_date.class != Date | ||
raise StandardError.new("not a date") | ||
elsif end_date < start_date | ||
raise StandardError.new("End date (#{end_date}) comes before start date (#{start_date})") | ||
elsif end_date == start_date | ||
raise StandardError.new("End date (#{end_date}) is same as start date (#{start_date})") | ||
end | ||
end | ||
|
||
def check_room_availibility(room_num, date_range) | ||
calendar = @rooms[room_num - 1].is_available(date_range) | ||
return true if calendar | ||
if !calendar | ||
raise StandardError.new("room already reserved") if date_range.include?(date) | ||
end | ||
end | ||
|
||
def add_to_calendar(reservation, date_range) | ||
date_range.each do |date| | ||
@calendar[date] ? @calendar[date].push(reservation) : @calendar[date] = [reservation] | ||
end | ||
end | ||
|
||
def find_reservations_for_given_date(date) | ||
@calendar[date] | ||
end | ||
|
||
def find_reservation_cost(reservation_id) | ||
reservation = find_reservation(reservation_id) | ||
reservation.calculate_reservation_cost | ||
end | ||
def find_reservation(reservation_id) | ||
@reservations.find { |reservation| reservation.id == reservation_id } | ||
end | ||
|
||
def create_room_block(rooms, party, start_date, end_date, discount) | ||
raise StandardError.new('too many rooms for a block') if rooms.length > 5 | ||
raise StandardError.new('too few rooms for a block') if rooms.length < 2 | ||
valid_dates(start_date, end_date) | ||
date_range = (start_date...end_date) | ||
rooms.each { |room| check_room_availibility(room.room_num, date_range) } | ||
id = @reservations.length + 1 | ||
new_block = Block.new({id: @@id, rooms: rooms, party: party, date_range: date_range, discount: discount}) | ||
@@id += 1 | ||
add_to_calendar(new_block, date_range) | ||
rooms.each { |room| room.add_to_calendar(date_range) } | ||
@reservations << new_block | ||
new_block | ||
end | ||
|
||
def reserve_room_from_block(block, room_num, guest) | ||
block.reserve_room(room_num, guest) | ||
end | ||
|
||
def check_block_room_availibility(block) | ||
block.find_available_rooms | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
require_relative 'spec_helper' | ||
require 'date' | ||
require 'pry' | ||
|
||
describe 'Block class' do | ||
describe 'instantiation' do | ||
before do | ||
rooms = [] | ||
4.times {|x| rooms << Hotel::Room.new(x+1, 200) } | ||
date_range = (Date.new(2018,3,22)...Date.new(2018,3,26)) | ||
@block = Hotel::Block.new({id: 1, rooms: rooms, party: "Fanime", date_range: date_range, discount: 0.2}) | ||
end | ||
it 'can be initialized' do | ||
@block.must_be_instance_of Hotel::Block | ||
end | ||
it 'inherits from User' do | ||
@block.must_be_kind_of Hotel::Reservation | ||
end | ||
it 'has attributes: id, list of some rooms, reservations, party, date range, discount' do | ||
# may not need this test stub.... | ||
@block.must_respond_to :id | ||
@block.id.must_equal 1 | ||
end | ||
end | ||
describe 'find_available_rooms' do | ||
before do | ||
@rooms = [] | ||
4.times {|x| @rooms << Hotel::Room.new(x+1, 200) } | ||
date_range = (Date.new(2018,3,22)...Date.new(2018,3,26)) | ||
@block = Hotel::Block.new({id: 1, rooms: @rooms, party: "Fanime", date_range: date_range, discount: 0.2}) | ||
end | ||
it 'returns array of rooms available in block' do | ||
available_rooms_in_block = @block.find_available_rooms | ||
|
||
available_rooms_in_block.must_be_kind_of Array | ||
available_rooms_in_block.must_equal @rooms | ||
end | ||
it 'handles (throw exception or returns nil) no rooms available' do | ||
4.times do |x| | ||
@block.reserve_room(x+1, "fan #{x+1}") | ||
end | ||
|
||
proc { @block.find_available_rooms }.must_raise StandardError | ||
end | ||
it 'exclude rooms that are already reserved' do | ||
@block.reserve_room(1, "Fan 543") | ||
@block.reserve_room(3, "Fan 564") | ||
|
||
available_rooms_in_block = @block.find_available_rooms | ||
|
||
available_rooms_in_block.wont_include @rooms[0] | ||
available_rooms_in_block.wont_include @rooms[2] | ||
end | ||
end | ||
describe 'reserve_room' do | ||
before do | ||
rooms = [] | ||
4.times {|x| rooms << Hotel::Room.new(x+1, 200) } | ||
date_range = (Date.new(2018,3,22)...Date.new(2018,3,26)) | ||
@block = Hotel::Block.new({id: 1, rooms: rooms, party: "Fanime", date_range: date_range, discount: 0.2}) | ||
end | ||
it 'returns a reservation for an available room' do | ||
reservation = @block.reserve_room(1, "Fan 1") | ||
|
||
reservation.must_be_instance_of Hotel::Reservation | ||
end | ||
it 'throws exception if room is unavailable' do | ||
@block.reserve_room(2, "Jace Poe") | ||
proc { @block.reserve_room(2, "Jade Poe")}.must_raise StandardError | ||
end | ||
end | ||
describe 'calculate_reservation_cost' do | ||
before do | ||
rooms = [] | ||
4.times {|x| rooms << Hotel::Room.new(x+1, 200) } | ||
date_range = (Date.new(2018,3,22)...Date.new(2018,3,26)) | ||
@block = Hotel::Block.new({id: 1, rooms: rooms, party: "Fanime", date_range: date_range, discount: 0.2}) | ||
end | ||
it 'returns discounted cost for the reservation' do | ||
reservation = @block.reserve_room(1, "Meka Starbright") | ||
|
||
@block.calculate_reservation_cost(reservation.id).must_equal 640 | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
require_relative 'spec_helper' | ||
require 'date' | ||
|
||
describe 'Reservation' do | ||
before do | ||
date_range = (Date.new(2018,3,18)...Date.new(2018,3,26)) | ||
room = Hotel::Room.new(4, 200) | ||
@reservation = Hotel::Reservation.new({id: 1, room: room, guest: "Bob", date_range: date_range}) | ||
end | ||
describe 'initialization' do | ||
it 'can be initialized' do | ||
@reservation.must_be_instance_of Hotel::Reservation | ||
end | ||
it 'has attributes: id, room, guest, date_range' do | ||
@reservation.id.must_equal 1 | ||
@reservation.id.must_be_kind_of Integer | ||
# @reservation.room.must_be_instance_of Hotel::Room | ||
end | ||
end | ||
describe 'calculate_nights' do | ||
before do | ||
date_range = (Date.new(2018,3,18)...Date.new(2018,3,26)) | ||
room = Hotel::Room.new(4, 200) | ||
@reservation = Hotel::Reservation.new({id: 1, room: room, guest: "Bob", date_range: date_range}) | ||
end | ||
it 'returns the number of nights' do | ||
nights = @reservation.calculate_nights | ||
|
||
nights.must_be_kind_of Integer | ||
nights.must_equal 8 | ||
end | ||
end | ||
describe 'find_all_dates' do | ||
it 'returns an array of all dates in reservation' do | ||
date_range = (Date.new(2018,3,20)...Date.new(2018,3,22)) | ||
room = Hotel::Room.new(4, 200) | ||
reservation = Hotel::Reservation.new({id: 1, room: room, guest: "Kaeli", date_range: date_range}) | ||
all_dates = reservation.find_all_dates | ||
|
||
all_dates.must_be_kind_of Array | ||
all_dates.must_equal [Date.new(2018,3,20), Date.new(2018,3,21)] | ||
end | ||
end | ||
|
||
describe 'calculate_reservation_cost' do | ||
it 'returns the cost of the reservation' do | ||
date_range = (Date.new(2018,3,20)...Date.new(2018,3,25)) | ||
room = Hotel::Room.new(4, 200) | ||
reservation = Hotel::Reservation.new({id: 1, room: room, guest: "Bob", date_range: date_range}) | ||
|
||
reservation.calculate_reservation_cost.must_equal 1000 | ||
end | ||
end | ||
end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Interesting idea having a hash of the reservation dates, very efficient.