Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
9764369
created test file for initial set up to test guard
kimj42 Sep 4, 2018
f84bf41
created test_spec file to test guard
kimj42 Sep 4, 2018
511ead2
added awesome print, minitest/skip_dsl
kimj42 Sep 4, 2018
bb9a903
added change Dan requested
kimj42 Sep 4, 2018
8609b2a
no change, just finalizing that guardfile is good now
kimj42 Sep 4, 2018
05a329a
deleted lib/test.rb since that was just for initial set up before rea…
kimj42 Sep 4, 2018
7cfd993
created rooms in hotel method where it will load all rooms in hotel a…
kimj42 Sep 4, 2018
0a433dc
created test for rooms in hotel and it passed. checked if array is re…
kimj42 Sep 4, 2018
7dbba01
created initialize method with room number, checkin date, checkout date
kimj42 Sep 4, 2018
2b292b8
added test to see if initialize method raises argument errors and if …
kimj42 Sep 4, 2018
b15f566
created count_number_of_nights method to calculate number of nights u…
kimj42 Sep 5, 2018
00ef5ed
created test for count_number_of_nights method and it passed
kimj42 Sep 5, 2018
87edfda
created booking system class with initialize method
kimj42 Sep 6, 2018
a52808e
created tests for booking system initialize method
kimj42 Sep 6, 2018
aab529c
created rooms class but will determine if need to delete later
kimj42 Sep 6, 2018
95de6be
created file to test rooms class
kimj42 Sep 6, 2018
a032ab7
require relatived both booking system and rooms file
kimj42 Sep 6, 2018
9632394
created test for rooms in hotel method
kimj42 Sep 6, 2018
e8c00f0
created rooms in hotel method that lists all the rooms in hotel
kimj42 Sep 6, 2018
ee5555d
created reservation_date_range method to create array of all dates th…
kimj42 Sep 6, 2018
9e47d43
created 2 tests for reservation_date_range method and passed both
kimj42 Sep 6, 2018
4fa4d3b
changed instance variables as hash key/values
kimj42 Sep 6, 2018
6afd0c1
changed tests to accommodate the hash as input
kimj42 Sep 6, 2018
89ff764
created assign_room_to_booking method to assign room to the date range
kimj42 Sep 7, 2018
42bbd41
added tests to pass assigned room to booking method
kimj42 Sep 7, 2018
1b1212c
created calculate_booking_cost method to calculate cost of booking by…
kimj42 Sep 7, 2018
4bd629b
created test for calculate_booking_cost method and passed all tests
kimj42 Sep 7, 2018
c8d4d2d
made booked_dates as attr_reader to read it
kimj42 Sep 7, 2018
1e04809
created test for checking existence of booked_dates and for creating …
kimj42 Sep 7, 2018
d721fa5
deleted unnecessary file
kimj42 Sep 7, 2018
5091434
changed file name and made booking system create a new instance of re…
kimj42 Sep 7, 2018
adc40e1
created make_reservation that makes new instance of reservation withi…
kimj42 Sep 7, 2018
2417864
changed file names
kimj42 Sep 7, 2018
677185b
deleted unnecessary methods
kimj42 Sep 7, 2018
c0c9721
deleted unnecessary methods
kimj42 Sep 7, 2018
f1b9bf8
changed file name for readability
kimj42 Sep 7, 2018
53b73d6
changed file name for readability
kimj42 Sep 7, 2018
6a77f5b
created list_existing_reservations
kimj42 Sep 7, 2018
929977f
created calculate_booking_cost method
kimj42 Sep 7, 2018
e51b6f8
created test for list_existing_reservations
kimj42 Sep 7, 2018
f47355e
created test for list_existing_reservations method
kimj42 Sep 7, 2018
47864f1
added code in make reservation method for edge case of overlapping dates
kimj42 Sep 8, 2018
6a4136b
no change, removed the added room number again
kimj42 Sep 8, 2018
d1ea68c
added test for checking for edge case of overlapping dates
kimj42 Sep 8, 2018
ebafef3
raised error when unavailable date is asked to be booked
kimj42 Sep 8, 2018
1fb7714
changed code to make list_reservations_by_date method to show all boo…
kimj42 Sep 9, 2018
9fb37dd
added more test for list_reservations_by_date method and passed all
kimj42 Sep 9, 2018
cef78da
added test to check if booking is created when the checkin date is th…
kimj42 Sep 9, 2018
7ce9572
not using rooms.rb so deleted it
kimj42 Sep 10, 2018
42d4c53
added tests to reflect changes in booking_systems.rb
kimj42 Sep 10, 2018
6d99938
added tests to reflect changes in reservation.rb
kimj42 Sep 10, 2018
de76799
deleted because no longer needed
kimj42 Sep 10, 2018
6f851e3
changed file names
kimj42 Sep 10, 2018
14c15b1
changed file name, worked with Ada tutor on both booking_system and r…
kimj42 Sep 10, 2018
273eddc
added tests to reflect changes in reservation_creator.rb
kimj42 Sep 10, 2018
a79583b
submitting original
kimj42 Sep 13, 2018
c2f08f7
submitting original
kimj42 Sep 13, 2018
bb156ac
removed rooms
kimj42 Sep 13, 2018
af79d2a
able to assign new room number if room already booked for that date r…
kimj42 Sep 30, 2018
f748e4e
added tests to cover all edge cases Dan wrote in slack
kimj42 Sep 30, 2018
fc4e065
added method to show rooms available on specific date
kimj42 Sep 30, 2018
ae0e4ae
fixed all warning signs of unused assigned variables in tests
kimj42 Sep 30, 2018
9bfcbcb
final submission for wave 2 before refactoring to DRY code
kimj42 Sep 30, 2018
6aeea07
renamed reservation creator to reservation.rb
kimj42 Sep 30, 2018
53d07af
changed reservation_creator to reservation.rb
kimj42 Sep 30, 2018
e8f1196
completed all questions to design-activity.md
kimj42 Sep 30, 2018
660979a
created and wrote things to refactor in refactors.txt
kimj42 Sep 30, 2018
59bf096
reduced DRY in #make_reservation method and used show available rooms…
kimj42 Oct 1, 2018
1f4a43f
wrote what could be improved with the design in design-activity.md
kimj42 Oct 1, 2018
a1a99e0
created custom error msg and tested it yay
kimj42 Oct 1, 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
4 changes: 2 additions & 2 deletions Guardfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
guard :minitest, bundler: false, rubygems: false do
guard :minitest, bundler: false, autorun: false, rubygems: false do
# with Minitest::Spec
watch(%r{^spec/(.*)_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^lib/(.+)\.rb$}) { |m| "speguc/#{m[1]}_spec.rb" }
watch(%r{^spec/spec_helper\.rb$}) { 'spec' }
end
57 changes: 57 additions & 0 deletions design-activity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
What classes does each implementation include? Are the lists the same?
Both implementation include classes named CartEntry, ShoppingCart, Order. If you mean the class name list by "list" then yes, the list is the same for both implementations.

Write down a sentence to describe each class.
For implementation A, class CartEntry stores unit price and quantity. Class ShoppingCart stores all entries in an array. Class Order stores all entries from ShoppingCart then calculates the cost of all entries including tax.

For implementation B, class CartEntry stores unit price and quantity while also being able to calculate cost of the merchandise with its cost and quantity. Class ShoppingCart stores all entires and can calculate the total cost for all entires. Class Order stores all entries, gets the total price from ShoppingCart then adds tax to calculate total sum.

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

For implementation A, ShoppingCart is directly instantiated in Order with .new but CartEntry's instance variables are also called in Order. Order is the big class that brings all classes together.

For implementation B, CartEntry's instance method price, price, is called in ShoppingCart inside it's instance method, price. ShoppingCart's price method is called in Order's instance method, total_price.

What data does each class store? How (if at all) does this differ between the two implementations?
For A, CartEntry holds unit_price and quantity, ShoppingCart holds all entires, Order holds all entries and total sum.

For B, CartEntry holds unit_price, quantity, price of one merchandise w/o tax, ShoppingCart holds all entires with price of all merchandise w/o tax, Order holds all entries and total sum with tax.

Difference is that B holds more data and has more behavior for each of its classes compared to A. A has 2 classes that just holds state.

What methods does each class have? How (if at all) does this differ between the two implementations?
A: Only order has an instance method but all classes do have the initialize method. Order#total_price method.

B: CartEntry#price method, ShoppingCart#price method, Order#total_price method.

Difference: B has more instance methods in each class so more behavior.

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: retained in order

B: delegated to lower level classes

Does total_price directly manipulate the instance variables of other classes?
A: yes, because total_price directly iterates over @cart.entries which is manipulating the instance variable of ShoppingCart.

B: no, because total_price simply calls the ShoppingCart#price method then assigns it to a local variable then adds the tax to that local variable.

If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify?
It would change the unit price to drop if one buys 10 folders in quantity for one order instead of 10 orders with 1 folder. So it could be an if statement of if quantity is multiples of 10 then minus price by 2 dollars.

B is easier to modify because the if statement can go inside #price method of CartEntry class. For A, I would either need to create an if statement inside the initialize method or create it inside the iteration of the total_price which would make it have too much responsibility in one method.

Which implementation better adheres to the single responsibility principle?
B. Because each class has both state and behavior while having one single responsibility.

HOTEL REVISITED:

what changes you would need to make to improve this design, and how the resulting design would be an improvement.
BookingSystem takes on the role of checking for overlapping dates which is more than what it should do. Reservation class could instead become a date range class and it could address the overlapping date ranges there. This will allow BookingSystem to have less responsibilities.

Then I could still have a reservation class where it takes in the confirmed date ranges that can be used to make a reservation and assign a room number to that date range in that class.

I did not finish wave 2 before when we submitted this project so I focused on completing that part. Then I focused on breaking down the methods with less responsibility for the #make_reservation method.

The way the methods are set up makes sense for them to be in BookingSystem so I had difficulty with fleshing the responsibilities out in BookingSystem. I am still working on breaking down the booking_system class so I have not committed a repo with a newly improved design but it does have better methods with less responsibility.
29 changes: 29 additions & 0 deletions hotel-revisited.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
What is this class's responsibility? You should be able to describe it in a single sentence.
Reservation: stores check in, check out date, and room number while also calculating the cost for those dates.

BookingSystem: keeps track of all reservations, assigns room number, checks for overlaps in dates for new booking, list reservations by date and show available rooms.

Is this class responsible for exactly one thing?
Reservation: Almost. It's perhaps it will be better if it just focuses on dates rather than also keeping track of the room_number as well as calculating the cost.

BookingSystem: No. It's checking to see if the dates overlap while trying to confirm the client is able to make a reservation for that date range.

Does this class take on any responsibility that should be delegated to "lower level" classes?
Reservation: Not sure if calculating the cost should go to a lower level class but it this class does need to focus on one responsibility.

BookingSystem: Yes. Overlaps could go to a date range class.

Is there code in other classes that directly manipulates this class's instance variables?
Reservation:

BookingSystem:

How easy is it to follow your own instructions?
It was easy for me to follow the instructions because I wrote them today but if I looked at it a week from now then it will be difficult to follow because it's not specific.

Do these refactors improve the clarity of your code?
Yes, if implemented it will reduce the number of responsibilities the booking_system class has right now.


Do you still agree with your previous assesment, or could your refactor be further improved?
I agree with the previous assessment but there are always ways to refactor for one's code to be improved.
1 change: 1 addition & 0 deletions lib/.keep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

60 changes: 60 additions & 0 deletions lib/booking_system.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require_relative 'reservation'

module Hotel
class BookingSystem
class AllBookedError < StandardError ; end

attr_reader :rooms, :reservations

def initialize
@reservations = []
@rooms = [*1..20]
end

def make_reservation(check_in_date:, check_out_date:)

room_number = get_available_room(check_in_date: check_in_date, check_out_date: check_out_date)
reservation = Reservation.new(check_in_date: check_in_date, check_out_date: check_out_date, room_number: room_number)

assign_diff_room_for_overlapping_dates(reservation)
@reservations << reservation
return reservation
end
Copy link

Choose a reason for hiding this comment

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

I think from a birds-eye view, this method make_reservation is set up for success. It's outline is the following:

  1. Figure out what the room number of the next available room is
  2. Make a new instance of reservation with the following info: the passed in check in date, check out date, and the room number from step 1
  3. add that reservation to the collection of reservations being recorded in this class on @reservations
  4. return that reservation

I think that the rest of the work for wave 2 is just filling in the detail for those steps, and those details will be filled in with the helper methods. I think that this method looks really good as is though.


def assign_diff_room_for_overlapping_dates(booking)
if @reservations.length >= 1
booking.date_range.each do |date|
if list_reservations_by_date(date).length >= 1
booking.room_number = show_available_rooms(date).first
raise AllBookedError.new("unable to reserve/rooms all booked") unless !booking.room_number.nil?
end
end
end
end

def get_available_room(check_in_date:, check_out_date:)
return @rooms.first
Copy link

Choose a reason for hiding this comment

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

I'd love to get more insight into your thoughts here of how you wanted to continue and push this code -- feel free to add comments that include your pseudocode next time :)

end

def list_all_rooms
return @rooms
end

def list_reservations_by_date(date)
specific_date = Date.parse("#{date}")

bookings_by_date = []
@reservations.each do |booking|
dates = booking.date_range
bookings_by_date << booking if dates.include?(specific_date)
end

return bookings_by_date
end
Copy link

Choose a reason for hiding this comment

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

This method looks pretty good to me. I see the following logic:

We start with figuring out the specific_date that we'll be comparing things to, and an empty collection in bookings_by_date.

Looking through the entire collection of reservations in @reservations, for every reservation, we'll get to see look at every set of dates that each reservation holds... then we'll make a comparison: if those dates include the specific date we were looking at, then we'll add the reservation/booking to the collection bookings_by_date.

Not bad -- can't wait to see more!


def show_available_rooms(date)
show = list_reservations_by_date(date).map {|reservation| reservation.room_number }
return list_all_rooms - show
end
end
end
28 changes: 28 additions & 0 deletions lib/reservation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require 'date'

module Hotel
class Reservation
attr_reader :check_in_date, :check_out_date
attr_accessor :room_number

COST = 200

def initialize(input)
@check_in_date = Date.parse("#{input[:check_in_date]}")

@check_out_date = Date.parse("#{input[:check_out_date]}")
raise StandardError, "Checkout date cannot be before checkin date" unless input[:check_in_date] < input[:check_out_date]
@room_number = input[:room_number].nil? ? input[:room_number] : 1
end

def date_range
date_range = [*check_in_date...check_out_date]
return date_range
end

def calculate_booking_cost
cost = date_range.length * COST
return cost
end
end
end
9 changes: 9 additions & 0 deletions refactors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Refactoring ideas:

BookingSystem might have too many responsibilities so might need to divide it into several classes.

#make_reservation method has too many responsibilities inside and the if statement is too clumped. Break down the method to several instance methods.

Use .map instead of .each in #list_reservations_by_date.

Clean up the tests and organize them so that it's easier to read.
119 changes: 119 additions & 0 deletions spec/booking_system_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
require_relative 'spec_helper'

describe "BookingSystem class" do
before do
@booking = Hotel::BookingSystem.new
@reservation = @booking.make_reservation(check_in_date: 180904, check_out_date: 180907)
end

it "creates a BookingSystem class" do
expect(@booking).must_be_kind_of Hotel::BookingSystem
end

it "returns an array of all instances of reservations created" do
expect(@booking.reservations).must_be_kind_of Array
expect(@booking.reservations[0]).must_be_kind_of Hotel::Reservation
end

it "returns array of all room numbers in hotel" do
expect(@booking.list_all_rooms).must_be_kind_of Array
expect(@booking.list_all_rooms).must_equal [*1..20]
end

it "returns array of dates" do
expect(@reservation).must_be_kind_of Hotel::Reservation
expect(@reservation.date_range).must_equal [Date.parse("180904"), Date.parse("180905"), Date.parse("180906")]
end

it "returns the total cost of the booking" do
expect(@reservation.calculate_booking_cost).must_equal 600
end

it "lists all bookings of specific date" do
bad_reservation = @booking.make_reservation(check_in_date: 180909, check_out_date: 1809010)

expect(@booking.list_reservations_by_date(180904)).must_include @reservation
expect(@booking.list_reservations_by_date(180904)).wont_include bad_reservation
end

it "assigns different room number if room number is already taken for existing reservation" do
@booking.make_reservation(check_in_date: 180904, check_out_date: 180905)
@booking.make_reservation(check_in_date: 180904, check_out_date: 180905)
fourth_reservation = @booking.make_reservation(check_in_date: 180904, check_out_date: 180905)

expect(fourth_reservation.room_number).must_equal 4
expect(@booking.list_reservations_by_date(180904)).must_include fourth_reservation
end

it "raises argument error when tries to overbook" do
19.times do
@booking.make_reservation(check_in_date: 180904, check_out_date: 180905)
end

expect{(@booking.make_reservation(check_in_date: 180904, check_out_date: 180905))}.must_raise Hotel::BookingSystem::AllBookedError
end

it "does not raise error when booking for 20th time on same day" do
19.times do
@booking.make_reservation(check_in_date: 180904, check_out_date: 180905)
end

expect(@booking.list_reservations_by_date(180904).length).must_equal 20
end

it "automatically assigns room number 1 if it\'s the first booking for that date range" do
new_reservation = @booking.make_reservation(check_in_date: 180910, check_out_date: 180911)
# binding.pry
expect(new_reservation.room_number).must_equal 1
expect(@booking.reservations.length).must_equal 2
end

it "assigns different room number if dates overlap at the front" do
new_reservation = @booking.make_reservation(check_in_date: 180903, check_out_date: 180905)

expect(new_reservation.room_number).must_equal 2
expect(@booking.reservations.length).must_equal 2
end

it "assigns different room number if dates overlap at the end" do
new_reservation = @booking.make_reservation(check_in_date: 180906, check_out_date: 180908)

expect(new_reservation.room_number).must_equal 2
expect(@booking.reservations.length).must_equal 2
end

it "assigns different room number if dates are contained in existing reservation date_range" do
new_reservation = @booking.make_reservation(check_in_date: 180905, check_out_date: 180906)

expect(new_reservation.room_number).must_equal 2
expect(@booking.reservations.length).must_equal 2
end

it "assigns different room number if dates contain the existing reservation date_range" do
new_reservation = @booking.make_reservation(check_in_date: 180903, check_out_date: 180908)

expect(new_reservation.room_number).must_equal 2
expect(@booking.reservations.length).must_equal 2
end

it "creates reservation for checkout date of existing reservation" do
new_reservation = @booking.make_reservation(check_in_date: 180907, check_out_date: 180908)

expect(new_reservation.room_number).must_equal 1
expect(@booking.reservations.length).must_equal 2
end

it "creates new reservation with the same checkout date for the checkin date of existing reservation" do
new_reservation = @booking.make_reservation(check_in_date: 180903, check_out_date: 180904)

expect(new_reservation.room_number).must_equal 1
expect(@booking.reservations.length).must_equal 2
end

it "shows all room_numbers that were reserved" do
@booking.make_reservation(check_in_date: 180903, check_out_date: 180906)

expect(@booking.show_available_rooms(180904)).must_be_kind_of Array
expect(@booking.show_available_rooms(180904)).must_equal [*3..20]
end
end
28 changes: 28 additions & 0 deletions spec/reservation_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require_relative 'spec_helper'

describe "Reservation class" do
before do
@reservation = Hotel::Reservation.new({check_in_date: 180904, check_out_date: 180905})
end

it "initialize method" do
expect(@reservation).must_be_kind_of Hotel::Reservation
expect(@reservation.check_in_date).must_be_kind_of Date
expect(@reservation.check_out_date).must_be_kind_of Date
end

it "raises ArgumentError if check out date is before check in date" do
expect{(Hotel::Reservation.new(180904, 180903))}.must_raise StandardError
end

it "returns all dates in date range" do
expect(@reservation.date_range).must_be_kind_of Array
expect(@reservation.date_range.length).must_equal 1
expect(@reservation.date_range).must_equal [Date.parse("180904")]
end

it "returns cost of that date range" do
expect(@reservation.calculate_booking_cost).must_be_kind_of Integer
expect(@reservation.calculate_booking_cost).must_equal 200
end
end
8 changes: 7 additions & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
require 'simplecov'
SimpleCov.start

require 'minitest'
require 'minitest/autorun'
require 'minitest/reporters'
# Add simplecov
require 'minitest/skip_dsl'
require 'awesome_print'

Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new

# Require_relative your lib files here!
require_relative '../lib/reservation'
require_relative '../lib/booking_system'