diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..10f4d4306 Binary files /dev/null and b/.DS_Store differ diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..deb52f2cd --- /dev/null +++ b/Rakefile @@ -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 diff --git a/design-activity.md b/design-activity.md new file mode 100644 index 000000000..e02d11e7c --- /dev/null +++ b/design-activity.md @@ -0,0 +1,64 @@ +Prompts + +1. What classes does each implementation include? Are the lists the same? + + Implementation A - CartEntry, ShoppingCart, Order + + Implementation B - CartEntry, ShoppingCart, Order + + Yes, they look to be the same, the differences look to be in the methods. + +2. Write down a sentence to describe each class. +How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper. + + Implementation A - To calculate the price of the Order, the Order class has to access the instance variables of CartEntry and ShoppingCart in order to calculate the total_price. + + Implementation B - In this case it is the ShoppingCart class which calls the price method of CartEntry in order to calculate the price of all instances (@entries) of CartEntry. From there the Order class calls the price method from the ShoppingCart class to calculate the total of everything that is located in @cart. + + All in all Implementation B is much more sensical, especially seeing them side-by-side. + +4. What data does each class store? How (if at all) does this differ between the two implementations? + + Each class stores the same data in both implementations. + + CartEntry stores data for quantity and unit price of each instance of CartEntry in the ShoppingCart class. + + ShoppingCart contains all of these instances in an array. + + Order contains a constant variable. This is set equal to the sales tax, as well as, an instance of ShoppingCart. + +5. What methods does each class have? How (if at all) does this differ between the two implementations? + + The methods between the two implementations do differ, as such; + + Implementation A - The classes CartEntry and ShoppingCart have only initialize methods. There is one main method with all of the logic placed in the Order class. This method essentially does the order pricing calculations and does so by directly accessing/using the instance variables located in ShoppingCart and CartEntry. + + Implementation B - The classes have changed here with CartEntry and ShoppingCart now containing their own price methods with logic that allows for them to calculate the total price of the Order class. + + CartEntry's calculation method calculates the cost of an instance of CartEntry. ShoppingCart's method calculates the total cost of all instances of CartEntry via @entries, which it does by calling the price method of CartEntry from within the class of ShoppingCart. The addition of the Order class having a total_price method that adds in tax to the sum by calling on the price method in ShoppingCart. + +6. 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? + + Implementation A - Logic is in the Order class, with the total_price method directly reading the instance variables of the ShoppingCart and CartEntry which then provides a calculation via the total_price method. + + Implementation B - There is a change in logic, which is now in the 'lower level classes'. In order to calculate total_price the 'higher level classes' call on the methods of the instances provided in the 'lower level' instead of calling on them directly as in Implementation A. + +7. Does total_price directly manipulate the instance variables of other classes? + + Implementation A - There is a small degree of manipulation with the entries through the loop. + + Implementation B - No, not in this case that I could tell. + +8. If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify? + + Implementation B - It is much easier to change the logic of the price method and provide/add a 'discount' depending on what is considered bulk. Thus defining what is considered 'bulk' and worthy of a discounted rate, then setting up that discount in the price method as a conditional could be one way to potentially go about this. + +9. Which implementation better adheres to the single responsibility principle? + + Implementation B - This because the classes in B have both behaviour and state. Adding that the methods of higher level classes don't rely directly on the lower level classes. + +10. Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? + + Implementation B - This because the classes components are in my opinion what I would call more 'self-reliant' and work more cohesively together due to that. diff --git a/lib/hotel.rb b/lib/hotel.rb new file mode 100644 index 000000000..a61af4e11 --- /dev/null +++ b/lib/hotel.rb @@ -0,0 +1,60 @@ +# All buisiness logic here (changed mind from reservations because this makes most sense). + +# I need for this to access all of the rooms in the room class. + +# I need for this to access all of the reservations, the reservations class holds my dates for the reservations. + +# I need for this to provide a total charge amount for the days reserved. + +# Somehow I need this to provide reservation list that is DATE specific. This will be tricky (IMO). + +require_relative 'rooms' +require_relative 'reservations' + +module HotelHedwig + class Reservations + attr_reader :rooms, :check_in, :check_out, :total_charges + def initialize(rooms, check_in, check_out, total_charges) + @rooms = rooms + @check_in = check_in + @check_out = check_out + @total_charges = total_charges + end + + # Start pseudocode + # Remember to not duplicate methods! + + def all_rooms + @rooms = [] + end + + def reserve_room(room, check_in, check_out) + + + end + + def date_reservations + + end + + # Calculating costs take 3, not sure how to best calculate this or if it belongs here. The idea is using the base amount aka room_cost (200) multiplied by the number of days customer stays. Check out day minus check in day provides that number. I hope. This should also allow for a one day stay ex. 200 * (day 2 - day 1) = 200 * 1 = 200. + + def total_charges + @room_rate = room_rate * (@check_out - @check_in).to_i + end + end +end + + +# User Stories Wave 1 (methods); + +# As an administrator, I can access the list of all of the rooms in the hotel +# As an administrator, I can reserve a room for a given date range +# As an administrator, I can access the list of reservations for a specific date +# As an administrator, I can get the total cost for a given reservation + +# 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 checkout day, so the guest should not be charged for that night diff --git a/lib/reservations.rb b/lib/reservations.rb new file mode 100644 index 000000000..9e36bfd28 --- /dev/null +++ b/lib/reservations.rb @@ -0,0 +1,30 @@ +# Logic for reservations here, aka reservation dates. +# I need this to require the date gem. +# This must initialize check in and check out dates +# This must also take those dates and use a method to calculate charges. +# I need to make sure that I can access this information in the hotel class which is going to hold all of the biz logic. + +require 'date' +require 'rooms' + +module HotelHedwig + class Reservations + + attr_reader :check_in, :check_out + + def initialize(check_in, check_out) + @check_in = check_in + @check_out = check_out + + # Raise an argument error IF the check-in date is after the check-out date! Method? + + # Why is invalid_date raising a warning??? + + def invalid_date + if @check_in < @check_out + raise ArgumentError.new("Invalid date selection, please check and change your check-in and check-out dates.") + end + end + end + end +end diff --git a/lib/rooms.rb b/lib/rooms.rb new file mode 100644 index 000000000..03a6bdc39 --- /dev/null +++ b/lib/rooms.rb @@ -0,0 +1,28 @@ +# Room logic. SIMPLE +# I need this to provide me with 20 numbered rooms starting at the number 1 and ending at the number 20. +# This also needs to (I believe) hold the room cost. Each room has a $200 charge per night. + +module HotelHedwig + class Rooms + + attr_reader :room_num, :room_rate + +# Initialize variables to access the room number AND the charge per room. I believe this will make it easier to calculate in the end. + + def initialize(room_num) + @room_num = room_num + @room_rate = 200 + end + +# Using a self.all method to work out the room numbering system. + + def self.all + rooms = [] + room_num = 0 + 20.times do + number += 1 + rooms << self.new(room_num) + end + end + end +end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb new file mode 100644 index 000000000..189e79b94 --- /dev/null +++ b/specs/hotel_spec.rb @@ -0,0 +1,38 @@ +require_relative 'spec_helper' + +describe "Hotel" do + before do + @check_in = Date.new(2017,9,11) + @check_out = Date.new(2017,9,13) + @reservation_dates = HotelHedwig::Reservations.new(@check_in, @check_out) + end + + + # Test pseudocode + + describe "#initialize" do + it "" do + end + end + + describe "all_rooms" do + it "Must be an array of rooms" do + end + end + + describe "reserve_room" do + it "Must allow reservation by date range" do + end + end + + describe "date_reservations" do + it "Must be able to access reservation list by specific date" do + end + end + + describe "total_charges" do + it "Must have a charge of $200 per night" do + @charges.must_equal + end + end +end diff --git a/specs/reservations_spec.rb b/specs/reservations_spec.rb new file mode 100644 index 000000000..84c2ab7f2 --- /dev/null +++ b/specs/reservations_spec.rb @@ -0,0 +1,21 @@ +require_relative 'spec_helper' + +describe "Reservations" do + before do + @check_in = Date.new(2017,9,11) + @check_out = Date.new(2017,9,13) + @reservation_dates = HotelHedwig::Reservations.new(@check_in, @check_out) + end + + it "Must be instance of Reservations" do + @reservation_dates.must_be_instance_of HotelHedwig::Reservations + end + + describe "invalid_date" do + it "Must raise argument error if check-in date is after check out date" do + proc { HotelHedwig::Reservations.new(@check_in < @check_out) }.must_raise ArgumentError + end + end +end + +# More testing needed. Big time. diff --git a/specs/rooms_spec.rb b/specs/rooms_spec.rb new file mode 100644 index 000000000..3a87f9251 --- /dev/null +++ b/specs/rooms_spec.rb @@ -0,0 +1,28 @@ +require_relative 'spec_helper' + +describe "Rooms" do + describe "#initialize" do + before do + @room_1 = HotelHedwig::Rooms.new(1) + end + + # Basic needs tests to access room numbers and the cost. + # Can I do anything else? + + it "Can access a room number." do + @room_1.room_num.must_equal 1 + end + + it "Can access the cost of a room per night." do + @room_1.room_rate.must_equal 200 + end + + it "Must respond to room_num" do + @room_1.must_respond_to :room_num + end + + it "Must be instance of HotelHedwig module and Rooms class" do + @room_1.must_be_instance_of HotelHedwig::Rooms + end + end +end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 000000000..62e43c833 --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,8 @@ +require 'simplecov' +SimpleCov.start +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/skip_dsl' +require_relative '../lib/rooms' +require_relative '../lib/hotel' +require_relative '../lib/reservations'