Skip to content
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
32 changes: 32 additions & 0 deletions design-activity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
- What classes does each implementation include? Are the lists the same?
- Yes , both include same classes. They are CartEntry, ShoppingCart and Order.

- Write down a sentence to describe each class.
- CartEntry- It represents a shopping cart item entry.
- ShoppingCart- It contains all the entries.
- Order- It represent initialization of new shopping cart instance.

- How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper.
- Order has a ShoppingCart.
- ShoppingCart has a list of CartEntry

- What data does each class store? How (if at all) does this differ between the two implementations?
- CartEntry has unit_price and quantity, ShoppingCart has entries and Order has cart and total_price. In implementation A only the class Order has the responsibility of calculating total_cost.In implementation B CartEntry calculates price, ShoppingCart return sum and Order return total_price.

- What methods does each class have? How (if at all) does this differ between the two implementations?
- CartEntry, ShoppingCart, and Order has initialize and Order has total_price method in both implementations. In implementation B CartEntry and ShoppingCart both have their price method.

- 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's retained in Order and in implementation B it's delegated.
- Does total_price directly manipulate the instance variables of other classes?
- NO.

- If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify?
- In implementation A Order#total_price has to be updated to add a if condition when calculating the sum. In implementation B the CartEntry price method can be updated. Implementation B is easier to modify and easier to supoort different use cases.

- Which implementation better adheres to the single responsibility principle?
- Implementation B

- Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled?
- Implementation B
114 changes: 114 additions & 0 deletions lib/administrator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
require 'csv'
require 'date'
require_relative 'room'
require_relative 'reservation'
require_relative 'block'
require_relative 'room_not_available_error'

module BookingSystem
class Administrator
attr_reader :rooms, :reservations, :range, :blocks

def initialize
@rooms = load_rooms
#{}
# (1..20).each{ |num| @rooms[num] = BookingSystem::Room.new(num, 200.00) }
@reservations = {}
@range = (1..500).to_a
@blocks = {}
end

def load_rooms
number = nil
cost = nil
rooms = {}
CSV.read("support/rooms.csv", :headers => true, :header_converters => :symbol, :converters => :all).each { |line|
number = line[0].to_i
cost = line[1].to_f
rooms[number] = BookingSystem::Room.new(number, cost)
}
return rooms
end


def list_rooms
return @rooms.values
end

def reserve_room(room_num, check_in, check_out)
raise ArgumentError.new("Incorrect room number") if !rooms.keys.include?(room_num)

room = @rooms[room_num]
raise RoomNotAvailableError.new("That room is not available")if !list_available_rooms(check_in, check_out).include?(room)

reservation_details = {id: @range.shift, check_in: check_in, check_out: check_out, room: room}
new_reservation = BookingSystem::Reservation.new(reservation_details)
@reservations[new_reservation.id] = new_reservation
return new_reservation
end

def find_reservation(date)
return @reservations.select{|id, reservation|reservation.check_in <= date && reservation.check_out > date}.values
end

def total_cost(reservation_id)
return @reservations[reservation_id].total_cost
end

def list_reserved_rooms(start_date, end_date)
reserved_rooms = []
(start_date..end_date).each{ |date|
reserved_rooms += find_reservation(date).map{ |reservation| reservation.room }
}
return reserved_rooms.flatten.uniq
end

def list_blocked_rooms(start_date, end_date)
blocked_rooms = []
(start_date..end_date).each{ |date|
selected_blocks = @blocks.select{|id, block|block.check_in <= date && block.check_out > date}.values
blocked_rooms += selected_blocks.map{ |block| block.rooms }
}
return blocked_rooms.flatten.uniq
end

def list_available_rooms(start_date, end_date)
return @rooms.values - list_reserved_rooms(start_date, end_date-1) - list_blocked_rooms(start_date, end_date-1)
end

def create_block(room_numbers, check_in, check_out, discounted_rate)
raise ArgumentError.new("Room numbers should be an Array") if room_numbers.class != Array
raise ArgumentError.new("Room count should be between 1 & 5") if room_numbers.count < 1 || room_numbers.count > 5

block_rooms = []
room_numbers.each { |room_num|
raise ArgumentError.new("Incorrect room number #{room_num}") if !@rooms.keys.include?(room_num)
raise RoomNotAvailableError.new("Room #{room_num} is not available") if !(list_available_rooms(check_in, check_out).map{|room|room.number}).include?(room_num)
block_rooms << @rooms[room_num]
}

block_details = {id: @range.shift, check_in: check_in, check_out: check_out, rooms: block_rooms, rate: discounted_rate}
new_block = BookingSystem::Block.new(block_details)
@blocks[new_block.id] = new_block
return new_block
end

def list_available_rooms_in_block(block_id)
block = @blocks[block_id]
return block.rooms - list_reserved_rooms(block.check_in, block.check_out - 1)
end

def reserve_in_block(block_id, room_number)
block = @blocks[block_id]
raise ArgumentError.new("Room #{room_number} not in block") if !block.rooms.map{ |room| room.number }.include?(room_number)
room = @rooms[room_number]
raise RoomNotAvailableError.new("That room is not available") if list_reserved_rooms(block.check_in, block.check_out - 1).include?(room)

reservation_details = {id: @range.shift, check_in: block.check_in, check_out: block.check_out, room: room}
new_reservation = BookingSystem::Reservation.new(reservation_details)
@reservations[new_reservation.id] = new_reservation
return new_reservation
end

end
end
16 changes: 16 additions & 0 deletions lib/block.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require 'date'
require_relative 'booking'
require_relative 'invalid_duration_error'

module BookingSystem
class Block < Booking
attr_reader :rooms, :rate

def initialize(input)
super(input)
@rooms = input[:rooms]
@rate = input[:rate]
end

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

module BookingSystem
class Booking
attr_reader :id, :check_in, :check_out

def initialize(input)
@id = input[:id]
@check_in = input[:check_in]
@check_out = input[:check_out]
raise InvalidDurationError.new("Check out time can not be before check in time") if booking_duration < 0
end

def booking_duration
return (@check_out - @check_in).to_i
end

end
end
2 changes: 2 additions & 0 deletions lib/invalid_duration_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class InvalidDurationError < StandardError
end
21 changes: 21 additions & 0 deletions lib/reservation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require 'date'
require_relative 'booking'
require_relative 'room'
require_relative 'invalid_duration_error'

module BookingSystem
class Reservation < Booking
attr_reader :room, :cost

def initialize(input)
super(input)
@room = input[:room]
@cost = input.has_key?(:rate) ? input[:rate] : @room.cost
end

def total_cost
return booking_duration * @cost
end

end
end
10 changes: 10 additions & 0 deletions lib/room.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module BookingSystem
class Room
attr_reader :number, :cost

def initialize number, cost
@number = number
@cost = cost
end
end
end
2 changes: 2 additions & 0 deletions lib/room_not_available_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class RoomNotAvailableError < StandardError
end
Loading