Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
983cc93
created Rakefile, lib files and spec files.
kseastman Mar 1, 2018
6fbb6a4
Finished Wave1 pseudocode for the propotential program.
kseastman Mar 5, 2018
d6a100a
Finished Wave1 pseudocode for the spec files, some of it has ts tests…
kseastman Mar 5, 2018
3978b7f
fleshing out tests, adding attr_readers and checking for existence of…
kseastman Mar 5, 2018
b9f45da
added BookingManager#load_rooms to populate @rooms list with room ins…
kseastman Mar 5, 2018
2398bed
Added coverage folder to .gitignore file
kseastman Mar 5, 2018
eb97e81
shuShuffled methods around to hopefully have them make more se sense.…
kseastman Mar 5, 2018
c9988f7
changed BookingManger#get_booking to #set_booking, added a booking id…
kseastman Mar 6, 2018
9a3d9ec
My lie, missed functionality from Wave 1 to return all bookings for a…
kseastman Mar 6, 2018
0fbc718
spec_helper fixed by moving simplecov up.
kseastman Mar 6, 2018
b55f686
added get_booking_by_id method and test.
kseastman Mar 6, 2018
0283f4d
added method to set the availability each day, based ed on the bookin…
kseastman Mar 6, 2018
2fe99ce
streamlined syntax for test, and methods to set_availability.
kseastman Mar 7, 2018
37931df
modified date range and tests.
kseastman Mar 7, 2018
fea1ede
Removed spec files from simple coverage reports, added a new block cl…
kseastman Mar 7, 2018
700815c
Streamlined the date parsing in #set_booking.
kseastman Mar 7, 2018
e047d35
Streamlined the status parsing in Room#change_status to include the b…
kseastman Mar 7, 2018
88827f7
stubbed out neccessary elements of reserve block
kseastman Mar 7, 2018
eda2458
Cleaning up logic and tests, adding additional classes to handle dat…
kseastman Mar 8, 2018
c8f1beb
added class stay, and specs for block and stay.
kseastman Mar 8, 2018
13868ca
will amend this later, for now, added things and they were glorious.
kseastman Mar 8, 2018
e144426
Changed Stay class to Duration for better readability, refactoringed …
kseastman Mar 8, 2018
b7e6d1f
saving clean-up work before branching.
kseastman Mar 9, 2018
b490b18
Switched reservation logic to a hash.
kseastman Mar 15, 2018
7054070
cleaned up room status debris from refactor.
kseastman Mar 15, 2018
0a7a4e8
removed user from spec_helper
kseastman Mar 15, 2018
14519f9
new tests for block
kseastman Mar 15, 2018
929502f
Solved the block issue and test.
kseastman Mar 15, 2018
eaf428a
Answered design-activity questions.
kseastman Mar 24, 2018
aad890f
Answered Activity question in design-activity.md
kseastman Mar 24, 2018
e8832d9
checkin last stable version before coupling revisions.
kseastman Mar 25, 2018
d311c0a
added room method free? to decouple BookingManager.
kseastman Mar 25, 2018
9cf4848
removed unnecessary error flag.
kseastman Mar 25, 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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
/test/tmp/
/test/version_tmp/
/tmp/
.DS_Store
/lib/junk_files/

# Used by dotenv library to load environment variables.
# .env
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
56 changes: 56 additions & 0 deletions design-activity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
> What classes does each implementation include? Are the lists the same?

CartEntry, ShoppingCart & Order - yes, the lists are the same.

> Write down a sentence to describe each class.

* CartEntry stores information about individual items, like price and quantity.

* ShoppingCart holds a list of CartEntries.

* Order applies sales tax to the subtotal derived from ShoppingCart.

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

CartEntry is an element in ShoppingCart (though that logic is invisible) - and Order takes information from ShoppingCart and adds the sales tax.

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

* In the first implementation CartEntry exists to hold the instance variables for @unit_price and @quanitity, in the second implementation it has a method for price that returns the @unit_price multiplied by the @quantity.

* In the first implementation ShoppingCart holds the instance variable @entries which is assigned to an empty array, in the second implementation ShoppingCart has a method for price that returns the sum of elements in the @entries array.

* In implementation A, Order holds a constant for SALES_TAX, an instance of ShoppingCart and a method for total price that adds the unit_price * quantity for each entry in the ShoppingCart @entries array, but in the second implementation the logic is much simpler for the total price method.

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

See previous answer.

> 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, it is retained in Order in Implementation B it is delegated to "lower level" classes.

> Does total_price directly manipulate the instance variables of other classes?

It doesn't change the values of other variables, but it uses them to calculate a new value.

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

It would probably affect the price for CartEntry. The change for Implementation B requires less complicated logic because it's not as far removed from the source of the change.

> Which implementation better adheres to the single responsibility principle?

Implementation B seems to adhere to this better.

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

Implementation B is more loosely coupled, because it knows less information about other classes. In B, total_price only knows its own variable @cart has a price, in A, total_price knows that each entry has a unit_price and a quantity, if those values are changed, then it will no longer work. Whereas with A, if they were changed, as long as price remained as method that could be called there would be no difference for the program as a whole.

## Activity
> Based on the answers to the above questions, identify one place in your Hotel project where a class takes on multiple roles, or directly modifies the attributes of another class.

> Describe in design-activity.md what changes you would need to make to improve this design, and how the resulting design would be an improvement.

My BookingManager class takes on multiple responsibilities when it should delegate them. I need to change all of the places where I chain to an instance method so that those classes handle the logic themselves.
31 changes: 31 additions & 0 deletions lib/block.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require 'awesome_print'
require 'pry'
require 'date'
require 'simplecov'

module Hotel

class Block
@@block_count = 0

attr_reader :id, :rooms, :period
def initialize(date_range, available_rooms)
@id = @@block_count += 1
@rooms = reserve_block(date_range, available_rooms)
@period = date_range
end

def reserve_block(date_range, open_rooms, price: 150)
reserved = Hash[date_range.collect { |date| [date, :BLOCK]}]
rooms = []
open_rooms.each do |open_room|
open_room.check_block_dates(date_range)
open_room.block_dates.merge!(reserved)
open_room.block_price(price)
rooms << open_room
end
return rooms
end

end
end
32 changes: 32 additions & 0 deletions lib/booking.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require 'awesome_print'
require 'pry'
require 'date'
require 'simplecov'

module Hotel


class Booking
@@id_count = 0
attr_reader :cost_estimate, :room, :period, :id, :id_count
def initialize(open_room, date_range)
@id = @@id_count += 1
@room = reserve_room(open_room, date_range)
@period = date_range
@cost_estimate = get_cost_estimate(date_range)
end

def get_cost_estimate(period)
length = period.size
subtotal = room.cost_per_night * length
return subtotal
end

def reserve_room(open_room, date_range)
reserved = Hash[date_range.collect { |date| [date, :RESERVED]}]
open_room.reserved_dates.merge!(reserved)
return open_room
end

end
end
108 changes: 108 additions & 0 deletions lib/booking_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
require 'awesome_print'
require 'pry'
require 'time'

require_relative 'booking'
require_relative 'room'
require_relative 'block'
require_relative 'duration'

module Hotel
class BookingManager
# should handle the business logic for bookings
attr_reader :rooms, :reservations, :occupied_rooms
def initialize
@rooms = load_rooms
@reservations = []
@occupied_rooms = []
@block_reservations = []
@available_rooms = nil
end

def load_rooms
rooms = []
numbers = (1..20).to_a
numbers.each do |num|
rooms << Room.new(num)
end
return rooms
end

def set_booking(start_date, end_date)
dates = Duration.new(start_date, end_date)
date_range = dates.period

if @reservations.length == 0
open_room = rooms.first
else
available_rooms = all_available(date_range)
open_room = available_rooms.pop
end

@reservations << Booking.new(open_room, date_range)
end

def reserve_block(start_date, end_date, number_of_rooms: 5)
dates = Duration.new(start_date, end_date)
date_range = dates.period

open_rooms = rooms.take(number_of_rooms)
block = Block.new(date_range, open_rooms)

@block_reservations << block
return block
end



def all_available(date_range) #actively using this
available_rooms = []
date_range.each do |date|
rooms_check = get_availability_by_date(date)

if available_rooms.length == 0
available_rooms = rooms_check
else
temp_rooms = available_rooms & rooms_check
available_rooms = temp_rooms
end
end

available_rooms.each do |room|
room.check_reserved_dates(date_range)
end

return available_rooms
end

def get_bookings_by_date(date)
bookings = @reservations.find_all do |booking|
if booking.period.include? date
@occupied_rooms << booking
end
end
@available_rooms = @rooms - @occupied_rooms

return bookings
end

def get_booking_by_id(id_to_find)
find_booking = @reservations.find { |booking| booking.id == id_to_find}
return find_booking
end

def get_availability_by_date(date)
get_bookings_by_date(date)
open_rooms = []

@available_rooms.each do |room|
unless room.free?(date)
open_rooms << room
end
end

return open_rooms
end

end
end
36 changes: 36 additions & 0 deletions lib/duration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require 'awesome_print'
require 'pry'
require 'date'
require 'simplecov'

module Hotel
class Duration
attr_reader :period
def initialize(start_date, end_date)
@date_range = date_range(start_date, end_date)
@period = list
end

def date_range(start_date, end_date)
new_range = (check_date(start_date)...check_date(end_date))
return new_range
end

def list
dates = []
@date_range.each {|date| dates << date }
#add in call to check availability of the room.
return dates
end


private
def check_date(date)
unless date.class == Date
parsed_date = Date.parse(date)
date = parsed_date
end
return date
end
end
end
51 changes: 51 additions & 0 deletions lib/room.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
require 'awesome_print'
require 'pry'
require 'date'
require 'simplecov'

module Hotel
class Room
attr_accessor :reserved_dates, :block_dates
attr_reader :room_number, :cost_per_night
def initialize(number)

# rooms that know their room number and cost
# make more sense as objects than a hash, for future
# proofing reasons, maybe overcomplicating things

@room_number = number
@cost_per_night = 200
@block_dates = {}
@reserved_dates = {}

end

def block_price(price)
@cost_per_night = price
end

def check_block_dates(date_range)
date_range.each do |date|
if @block_dates.has_key?(date)
raise StandardError.new("Room is reserved to a block on #{date}")
end
end
end

def check_reserved_dates(date_range)
date_range.each do |date|
if @reserved_dates.has_key?(date)
raise StandardError.new("Room is already reserved on #{date}")
end
end
end

def free?(date)
if @block_dates.has_key?(date) || @reserved_dates.has_key?(date)
return true
end
return false
end

end
end
44 changes: 44 additions & 0 deletions specs/block_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require_relative 'spec_helper'

describe "Block" do
before do
@booking_manager = Hotel::BookingManager.new
@block1 = @booking_manager.reserve_block("apr4, 2018", "apr7, 2018")
end
describe "Block#initialize" do
it "creates a block with an id, rooms and a date_range" do
# test that it creates a user
result = @block1

result.must_be_instance_of Hotel::Block

result.id.must_be_kind_of Integer
result.rooms.must_be_kind_of Array
result.period.length.wont_be_nil
end

it "won't accept a block with rooms from another block" do
proc{
@booking_manager.reserve_block("apr4, 2018", "apr7, 2018")
}.must_raise StandardError
end


end

it "can do things" do
# create as many tests as are needed to make sure
# that the user can actually navigate the program
end

# find {n} rooms that are near eachother and available for those dates
# requirements:
#=> date range, no more than 5 rooms at a discounted rate
#=> only include rooms available for the given date range
#=> a room in a block is not available or included in another block

#needs:
#=> date_range
#=> availablity_checking
#=> uniqueness
end
Loading