Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
556fd2d
added Rakefile
murog Sep 5, 2017
0f9313f
create class files and test files
murog Sep 5, 2017
193aa14
wrote pseudocode for wave1
murog Sep 5, 2017
5cc1ce8
green test create instance of room
murog Sep 5, 2017
6d0c0c0
added passing tests for creating instance of room and 20 hotel rooms
murog Sep 5, 2017
caaad48
passing self.all rooms test
murog Sep 5, 2017
05df441
added passing tests find by room
murog Sep 5, 2017
69b5087
added reservations.csv
murog Sep 5, 2017
948422c
added find total cost by reservation_id
murog Sep 6, 2017
a40e794
find reservation based on date tests are passing
murog Sep 6, 2017
52e1f6e
all wave 1 reqs are passing
murog Sep 6, 2017
95d5d61
wrote pseudocode and tests for first user story
murog Sep 6, 2017
42d2163
can search for available rooms based on date
murog Sep 6, 2017
ee90848
updated available rooms to not consider a room unavailable if the che…
murog Sep 6, 2017
6588ebb
wrote failing tests for reserve_room
murog Sep 6, 2017
c250f61
Hotel responds to reserve_room
murog Sep 6, 2017
1fc6199
reserve room passing tests
murog Sep 6, 2017
68c903e
wave 2 passing
murog Sep 6, 2017
4300179
started wave 3, created block tests, csv and ruby files
murog Sep 6, 2017
3f24851
Block initialized with rate, num of rooms, check in and check out dates
murog Sep 6, 2017
184841d
passing tests for Hotel.all_blocks
murog Sep 6, 2017
7d84609
blocks are intiated with rooms with given date range
murog Sep 6, 2017
321ee8b
i messedu p
murog Sep 6, 2017
0e51766
wrote test for checking blocks when checking available rooms
murog Sep 6, 2017
83169a9
truly_available hotel passes test for checking blocks
murog Sep 6, 2017
2aecad4
added block_id attribute to blocks
murog Sep 6, 2017
ed04707
wrote failing test for finding reservation by id
murog Sep 7, 2017
38c6885
added reservations attribute to blocks, added find reservation by id
murog Sep 7, 2017
0613ddd
wrote failing tests for find reservation by block id
murog Sep 7, 2017
91a740b
wrote failing test for block_available
murog Sep 7, 2017
ed0662b
updated failing test for block available to check for integer
murog Sep 7, 2017
9d3dbf0
wrote failing tests for find block by input id
murog Sep 7, 2017
43a8ec4
find block passing
murog Sep 7, 2017
0ceabc4
wrote failing tests for reserve_block_room
murog Sep 7, 2017
4fca524
can create reservation for block
murog Sep 7, 2017
5f8b8b4
blocks have reservations
murog Sep 7, 2017
09ae73c
wrote failing test for hotel.reserving block
murog Sep 7, 2017
fd094fc
can reserve block through hotel, will return error if there are no av…
murog Sep 7, 2017
b86f790
checked self.cost to take input_reservation_id, changed argument erro…
murog Sep 7, 2017
92a06f5
made reservation cost a private method
murog Sep 8, 2017
0d34d0d
update argument for reserve block room to take block_id instead of in…
murog Sep 8, 2017
b5861d8
update argument for block available to take block_id instead of input…
murog Sep 8, 2017
66f8a1d
finalized all blocks tests
murog Sep 11, 2017
5cb8ab7
finalized cost tests
murog Sep 11, 2017
8bd5695
finalized hotel room numbers tests
murog Sep 11, 2017
cb7ebd0
finalized find reservation tests
murog Sep 11, 2017
7610816
finalized all rooms tests
murog Sep 11, 2017
22ae01f
finalized tests for making reservation within block
murog Sep 11, 2017
fac56e9
design activity
murog Oct 2, 2017
efd0873
updated hotel available_rooms and blocked_rooms
murog 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 = true
t.test_files = FileList['specs/*_spec.rb']
end

task default: :test
26 changes: 26 additions & 0 deletions design-activity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
###What classes does each implementation include? Are the lists the same?
Both implementations use three classes: CartEntry, ShoppingCart and Order. However, they differ in that B's classes has price methods instead of attr_accessors.
###Write down a sentence to describe each class.
CartEntry: Is initialized with a unit price and quantity. B's can tell you the price, while A's gives you attr_accessors to the price and quantity.
ShoppingCart: Is initialized with an empty array to called entries. B's can tell you the total price of the all of the entries, while A's gives your attr_accessor to the entries.
Order: Creates an instance of a shopping cart and has a constant variable to store 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.
Orders hold a shopping cart, they can tell you the total price with sales tax included. A shopping cart holds CartEntry objects in an array.
###What data does each class store? How (if at all) does this differ between the two implementations?
Order holds sales tax as a constant variable and an instance of a cart as an instance variable. ShoppingCart holds multiples instances of CartEntry objects as an instance variable within an array. CartEntry has a unit price and quantity as instance variables. The two implementations do not differ on this.
###What methods does each class have? How (if at all) does this differ between the two implementations?
A's gives you attr_accessors for their object's instance variables. However, B's has a separate method for "price." This allows for the data to remain private and from being modified.
###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's computes the the total price by accessing the unit price and quantity for the objects and directly computing using those numbers. However, B's implementation has a price method that gives you the price for each objects, so it just needs to grab the cart's price to use as a subtotal before adding the sales tax.
###Does total_price directly manipulate the instance variables of other classes?
A's method does not currently change the instance variables, but they could if they make a mistake writing a method in Order. However, it would be impossible to do so in B's.
###If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify?
B's implementation would be easiest because you could just modify the price method to adjust when the quantity is above a certain number. In A's implementation you would have to check it for each entry within the total price loop.
###Which implementation better adheres to the single responsibility principle?
B!
###Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled?
###Once you've responded to the prompts, git add design-activity.md and git commit!

### Hotel
My hotel module is doing a lot! It creates, modifies, and finds rooms, reservations and blocks. Some of it can definitely be moved into the classes. I refactored the available_rooms and blocked_rooms method to not rely so heavily on attr_readers from the classes. Instead of manually checking the check in and check out date within the Hotel module, I updated it so the blocks and reservations can tell you if they are available or not within that date range.
48 changes: 48 additions & 0 deletions lib/block.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require 'csv'
require_relative 'room'
require_relative 'reservation'
require_relative 'hotel'

module Hotel
class Block < Reservation
attr_accessor :reservations
attr_reader :block_id, :discount_rate, :num_of_rooms, :rooms
def initialize(input_id, input_room_number, check_in_date, check_out_date, input_block_id = 0 )
super
@block_id = input_block_id.to_i
@discount_rate = input_id.to_f
@num_of_rooms = input_room_number.to_i
raise ArgumentError.new "Blocks can contain a maximum of 5 rooms" if @num_of_rooms > 5
@id = nil
@room_number = nil
@room = nil
@rooms = add_rooms(check_in_date, check_out_date)
@reservations = []
end


def add_rooms(begin_date, end_date)
block_rooms = []
available_rooms = Hotel.available_rooms(begin_date, end_date)
i = 0
num_of_rooms.times do
block_rooms << available_rooms[i]
i+= 1
end
return block_rooms
end

def add_reservations
reservations.replace(Hotel.find_reservation_by_block_id(block_id))
end

def available(begin_search, end_search)
if (begin_search >= @check_in) && (begin_search < @check_out) && (end_search >= @check_in) && (end_search <= @check_out)
return false
else
return true
end
end

end # => end of Block
end # => end of module
172 changes: 172 additions & 0 deletions lib/hotel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
require 'csv'
require_relative 'room'
require_relative 'reservation'

module Hotel

ROOM_NUMBERS = (1..20)

HOTEL_ROOMS = ROOM_NUMBERS.map {|num| Hotel::Room.new(num, 200)}


def self.all_rooms
return HOTEL_ROOMS
end

def self.find_room(input_id)
HOTEL_ROOMS.each do |room|
return room if room.id == input_id
end
end


def self.find_reservation(input_id)
raise ArgumentError.new "Invalid input. Please enter Reservation ID as an Integer" if !(input_id.is_a? Integer)
all_reservations = self.all_reservations
all_reservations.each do |reservation|
return reservation if reservation.id == input_id
end
raise ArgumentError.new "Reservation ID does not exist"
end

def self.find_reservation_by_block_id(input_id)
raise ArgumentError.new "Invalid input. Please enter Block ID as an Integer" if !(input_id.is_a? Integer)
blocked_reservations = []
all_reservations = self.all_reservations
all_reservations.each do |reservation|
blocked_reservations << reservation if reservation.block_id == input_id
end
raise ArgumentError.new "No Reservations found under that Block ID" if blocked_reservations.length == 0
return blocked_reservations
end

def self.find_block(input_id)
all_blocks = self.all_blocks
all_blocks.each do |block|
return block if block.block_id == input_id
end
end

def self.all_reservations
all_reservations = []
CSV.read('support/reservations.csv').each do |row|
reservation_id = row[0]
room_num = row[1]
check_in_date = row[2].split
check_out_date = row[3].split
block_id = row[4] ? row[4] : 0
all_reservations.push(Hotel::Reservation.new(reservation_id, room_num, check_in_date, check_out_date, block_id))
end
return all_reservations
end

def self.all_blocks
all_blocks =[]
CSV.read('support/blocks.csv').each do |row|
block_rate = row[0]
num_of_rooms = row[1]
check_in_date = row[2].split
check_out_date = row[3].split
block_id = row[4]
all_blocks.push(Hotel::Block.new(block_rate, num_of_rooms, check_in_date, check_out_date, block_id))
end
return all_blocks
end

def self.cost(input_reservation_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

you should reuse self.find_reservation here!

raise ArgumentError.new "Invalid reservation ID. Must be Integer." if !(input_reservation_id.is_a? Integer)
all_reservations = self.all_reservations
all_reservations.each do |reservation|
return (reservation.total_cost) if reservation.id == input_reservation_id
end
raise ArgumentError.new "Reservation ID does not exist"
end

def self.access_reservation(input_date)
search_date = Date.new(input_date[0], input_date[1], input_date[2])
search_reservations = []
all_reservations = self.all_reservations
all_reservations.each do |reservation|
search_reservations << reservation if search_date.between?(reservation.check_in, reservation.check_out - 1)
end
raise ArgumentError.new "No Reservations are present on that date" if search_reservations.length == 0
return search_reservations
end

def self.available_rooms(begin_date, end_date)
begin_search = Date.new(begin_date[0].to_i, begin_date[1].to_i, begin_date[2].to_i)
end_search = Date.new(end_date[0].to_i, end_date[1].to_i, end_date[2].to_i)
unavailable_rooms = []
all_reservations = self.all_reservations
all_reservations.each do |reservation|
if reservation.available(begin_search, end_search) == false
unavailable_rooms << reservation.room
end
end
# if (begin_search >= reservation.check_in) && (begin_search < reservation.check_out) && (end_search >= reservation.check_in) && (end_search <= reservation.check_out)
# unavailable_rooms<< reservation.room
# end
available_rooms = HOTEL_ROOMS - unavailable_rooms
return available_rooms
end

def self.blocked_rooms(begin_date, end_date)
begin_search = Date.new(begin_date[0].to_i, begin_date[1].to_i, begin_date[2].to_i)
end_search = Date.new(end_date[0].to_i, end_date[1].to_i, end_date[2].to_i)
blocked_rooms = []
all_the_blocks = self.all_blocks
all_the_blocks.each do |block|
# if (begin_search >= block.check_in) && (begin_search < block.check_out) && (end_search >= block.check_in) && (end_search <= block.check_out)
if block.available(begin_search, end_search) == false
block.rooms.each do |room|
blocked_rooms << room
end
end
end
return blocked_rooms
end

def self.truly_available(begin_date, end_date)
available_rooms = self.available_rooms(begin_date, end_date)
blocked_rooms = self.blocked_rooms(begin_date, end_date)
truly_available = available_rooms - blocked_rooms
return truly_available
end


def self.reserve_room(begin_date, end_date)
# begin_reservation = Date.new(begin_date[0], begin_date[1], begin_date[2])
# end_reservation = Date.new(end_date[0], end_date[1], end_date[2])
available_rooms = self.available_rooms(begin_date, end_date)
raise ArgumentError.new "No rooms are available for this date range" if available_rooms.length == 0
return Hotel::Reservation.new(10, available_rooms[0].id, begin_date, end_date)
end

def self.reserve_block(rate, num_of_rooms, check_in_date, check_out_date, input_block_id)
available_rooms = truly_available(check_in_date, check_out_date)
raise ArgumentError.new "Not enough rooms are available for this date range" if available_rooms.length < num_of_rooms.to_i
return Hotel::Block.new(rate, num_of_rooms, check_in_date, check_out_date, input_block_id)
end

def self.block_available(block_id)
block = self.find_block(block_id)
rooms = block.rooms.length
taken = self.find_reservation_by_block_id(block_id)
return rooms - taken.length
end

def self.reserve_block_room(block_id)
raise ArgumentError.new "Invalid input. Please enter Block ID as an Integer" if !(block_id.is_a? Integer)
block = self.find_block(block_id)
raise ArgumentError.new "Block ID is not found" if !(block.is_a? Hotel::Block)
# block.add_rooms
availability = block_available(block_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

in this method, you've already found the block object and stored it in block, but then you redo that work in calling block_available and passing in the block_id instead of the block itself.

I would refactor this so that it relies on block more, and lets block return internal information about itself

raise ArgumentError.new "No rooms available in Block #{block_id}" if availability == 0
array_check_in = [block.check_in.year, block.check_in.month, block.check_in.day]
array_check_out =[block.check_out.year, block.check_out.month, block.check_out.day]
new_reservation = Hotel::Reservation.new(5, block.rooms[0].id, array_check_in, array_check_out, block.block_id)
# block.add_reservations # => does nothing currently, would work if I was writing new reservations to CSV...)-':'
block.reservations << (new_reservation)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ideally instead of shoveling into a block's internal property reservations, you would use a method

return new_reservation
end
end
42 changes: 42 additions & 0 deletions lib/reservation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
require_relative 'hotel'
require_relative 'room'

module Hotel
class Reservation
# @@reservation_id_max = 0
attr_reader :id, :room_number, :room, :check_in, :check_out, :total_cost, :block_id
def initialize(input_id, input_room_number, check_in_date, check_out_date, input_block_id = 0)
@id = input_id.to_i

@room_number = input_room_number.to_i

@room = Hotel.find_room(@room_number)

@check_in = Date.new(check_in_date[0].to_i, check_in_date[1].to_i, check_in_date[2].to_i)

@check_out = Date.new(check_out_date[0].to_i, check_out_date[1].to_i, check_out_date[2].to_i)

@total_cost = cost
@block_id = input_block_id.to_i
raise ArgumentError.new "Invalid date range" if @check_in >= @check_out
end

def available(begin_search, end_search)
if (begin_search >= @check_in) && (begin_search < @check_out) && (end_search >= @check_in) && (end_search <= @check_out)
return false
else
return true
end
end
private
def cost
length_of_stay = (@check_out - @check_in).to_i
cost_of_stay = length_of_stay * @room.cost
return cost_of_stay
end
# def generate_id
# @@reservation_id_max += 1
# return @@reservation_id_max
# end
end
end
16 changes: 16 additions & 0 deletions lib/room.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require_relative 'hotel'

module Hotel
class Room
attr_reader :id, :cost
def initialize(input_id, cost)
@id = input_id
@cost = cost
end # => end of initialize

# def is_available?(begin_date, end_date)
# @availablility.each do |reservation_id, dates|
# if (begin_date >= check_in) && (begin_date <= check_out) || (end_date >= check_in) && (end_date <= check_out)

end # => end of class
end # => end of module
25 changes: 25 additions & 0 deletions pseudocode_wave3.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require_relative 'lib/hotel.rb'
require_relative 'lib/room.rb'
require_relative 'lib/reservation.rb'

# Wave 3
# User Stories

# As an administrator, I can create a block of rooms

# => To create a block you need a date range, collection of rooms and a discounted room rate
Hotel::Block.new(begin_date, end_date, num_of_rooms, discount_rate)
# => The collection of rooms should only include rooms that are available for the given date range
Block.rooms.each
# => If a room is set aside in a block, it is not available for reservation by the general public, nor can it be included in another block


# As an administrator, I can check whether a given block has any rooms available
Hotel.block_available(input_id)
# As an administrator, I can reserve a room from within a block of rooms
Hotel.reserve_block_room(input_id)

#Constraints
# => A block can contain a maximum of 5 rooms
# => When a room is reserved from a block of room, the reservation dates will always match the date range of the block
# => All of the availablility checking logic from Wave 2 should now respect room blocks as well as an individual
28 changes: 28 additions & 0 deletions pseudocode_wave_1.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require_relative 'lib/hotel.rb'
require_relative 'lib/room.rb'
require_relative 'lib/reservation.rb'

# Wave 1
# User Stories
# => As an administrator, I can access the list of all of the rooms in the hotel
Hotel.rooms # => list of all rooms
[Room1, Room2, Room3, Room4...Room20]
# => As an administrator, I can reserve a room for a given date range
Hotel::Reservation.new(input_room, check_in_date, check_out_date] # => creates instance of a reservation
Hotel::Reservation.new(Room1, 10222017, 10242017)
<Hotel::Reservation @id = 55, @check_in = 10222017, @check_out = 10242017, @length_of_stay = 2, @total_cost = 400>
# => As an administrator, I can access the list of reservations for a specific date
Hotel.find_by_date(input_date)
Hotel::Reservation.find_by_date(10232017) #=> should return my reservation
<Hotel::Reservation @id = 55>
# => As an administrator, I can get the total cost for a given reservation
Hotel.reservation_cost(input_id)
Hotel.find_by_id(input_id).total_cost (?)
# Constraints
# => The hotel has 20 rooms, and they are numbered 1 through 20
# => Every room is identical and a room always costs $200/night
# => The last day of a reservation is the checkoutday, so the guest should not be charged for that night
# => For this wave, any room can be reserved at any time, so you don't need to worry about double booking (-:
#
# Error Handling
# => Your code should raise an error when an invalid date range is provided
22 changes: 22 additions & 0 deletions pseudocode_wave_2.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require_relative 'lib/hotel.rb'
require_relative 'lib/room.rb'
require_relative 'lib/reservation.rb'

# Wave 2
# User Stories

# => As an administrator, I can view a list of rooms that are not reserved for a given date range
Hotel.available_rooms(begin_date, end_date)
#=> returns array [Room Object.available true for date range]
# => As an administrator, I can reserve an available room for a given date range
Hotel.reserve_room(begin_date, end_date)


# Constraints

# => A reservation is allowed to start on the same day that another reservation for the same room ends


# Error Handling

# => Your code should raise an exception when asked to reserve a room that is not available
Loading