Created
February 12, 2024 22:09
-
-
Save Heavyblade/7b5c8e7c423f96b36b1a638ebec42e94 to your computer and use it in GitHub Desktop.
rental_program
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Customer | |
attr_reader :name, :rentals | |
def initialize(name) | |
@name = name | |
@rentals = [] | |
end | |
def add_rental(arg) | |
@rentals << arg | |
end | |
def statement | |
Rental.build_statement_for_customer(self) | |
end | |
end | |
class Rental | |
attr_reader :movie, :days_rented | |
def initialize(movie, days_rented) | |
@movie = movie | |
@days_rented = days_rented | |
end | |
def value_to_charge | |
movie.value_to_charge(days_rented) | |
end | |
class << self | |
def build_statement_for_customer(customer) | |
ReportBuilder.new(customer, calculate_rental_statement(customer.rentals)).build | |
end | |
def calculate_rental_statement(rentals) | |
values_per_movie = rentals.map do |rental| | |
{ title: rental.movie.title, amount: rental.value_to_charge } | |
end | |
total_amount = values_per_movie.sum { |h| h[:amount] } | |
frequent_renter_points = calculate_frequent_renter_points(rentals) | |
{ values_per_movie:, frequent_renter_points:, total_amount: } | |
end | |
def calculate_frequent_renter_points(rentals) | |
rentals.inject(0) { |sum, rental| sum + (rental.movie.has_extra_points? ? 2 : 1) } | |
end | |
end | |
end | |
class ReportBuilder | |
attr_reader :customer, :statement | |
def initialize(customer, statement) | |
@customer = customer | |
@statement = statement | |
end | |
def build(format = :txt_report) | |
send format, customer, statement | |
end | |
private | |
def txt_report(customer, statement) | |
[ | |
"Rental Record for #{customer.name}", | |
statement[:values_per_movie].map { |v| "\t#{v[:title]}\t#{v[:amount]}" }, | |
"Amount owed is #{statement[:total_amount]}", | |
"You earned #{statement[:frequent_renter_points]} frequent renter points" | |
].flatten.join("\n") | |
end | |
def html_report(customer, statement) | |
[ | |
"<h2>Rental Record for #{customer.name}</h2>", | |
'<ul>', | |
statement[:values_per_movie].map { |v| "<li>#{v[:title]}\t#{v[:amount]}</li>" }, | |
'</ul>', | |
"<p>Amount owed is #{statement[:total_amount]}</p>", | |
"<p>You earned #{statement[:frequent_renter_points]} frequent renter points</p>" | |
].flatten.join("\n") | |
end | |
end | |
class Movie | |
REGULAR = 0 | |
NEW_RELEASE = 1 | |
CHILDRENS = 2 | |
COSTS = { | |
REGULAR => { fixed: 2, extra: 1.5, days: 2 }, | |
NEW_RELEASE => { fixed: 0, extra: 3, days: 0 }, | |
CHILDRENS => { fixed: 1.5, extra: 1.5, days: 3 } | |
} | |
attr_reader :title, :price_code, :cost | |
def initialize(title, price_code) | |
@title = title | |
@price_code = price_code | |
@cost = COSTS[price_code] | |
end | |
def has_extra_points? | |
price_code == NEW_RELEASE | |
end | |
def value_to_charge(days_rented) | |
return cost[:fixed] unless days_rented > cost[:days] | |
cost[:fixed] + (days_rented - cost[:days]) * cost[:extra] | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'minitest/autorun' | |
require 'minitest/reporters' | |
require_relative 'rental_program' | |
Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(color: true)] | |
class RentalProgram < Minitest::Test | |
def test_customer_having_a_name | |
customer = Customer.new('John Doe') | |
assert_equal customer.name, 'John Doe' | |
end | |
def test_customer_adding_rental | |
customer = Customer.new('John Doe') | |
movie = Movie.new('The Matrix', Movie::REGULAR) | |
customer.add_rental(Rental.new(movie, 3)) | |
assert_equal customer.rentals.count, 1 | |
end | |
def test_statement_for_regular_movie_lest_than_2_days | |
customer = Customer.new('John Doe') | |
movie = Movie.new('The Matrix', Movie::REGULAR) | |
customer.add_rental(Rental.new(movie, 1)) | |
result = [ | |
'Rental Record for John Doe', | |
"\tThe Matrix\t2", | |
'Amount owed is 2', | |
'You earned 1 frequent renter points' | |
].join("\n") | |
assert_equal customer.statement, result | |
end | |
def test_statement_for_childrens_movie_greater_than_3_days | |
customer = Customer.new('John Doe') | |
movie = Movie.new('The Matrix', Movie::CHILDRENS) | |
customer.add_rental(Rental.new(movie, 4)) | |
result = [ | |
'Rental Record for John Doe', | |
"\tThe Matrix\t3.0", | |
'Amount owed is 3.0', | |
'You earned 1 frequent renter points' | |
].join("\n") | |
assert_equal customer.statement, result | |
end | |
def test_rental_statement | |
customer = Customer.new('John Doe') | |
movie = Movie.new('The Matrix', Movie::REGULAR) | |
customer.add_rental(Rental.new(movie, 3)) | |
movie = Movie.new('Avengers', Movie::NEW_RELEASE) | |
customer.add_rental(Rental.new(movie, 3)) | |
movie = Movie.new('The truman show', Movie::CHILDRENS) | |
customer.add_rental(Rental.new(movie, 3)) | |
result = [ | |
'Rental Record for John Doe', | |
"\tThe Matrix\t3.5", | |
"\tAvengers\t9", | |
"\tThe truman show\t1.5", | |
'Amount owed is 14.0', | |
'You earned 4 frequent renter points' | |
].join("\n") | |
assert_equal customer.statement, result | |
end | |
def test_movie_has_title_and_price_code | |
movie = Movie.new('The Matrix', Movie::REGULAR) | |
assert_equal movie.title, 'The Matrix' | |
assert_equal movie.price_code, Movie::REGULAR | |
end | |
def test_rental_has_movie_and_days_rented | |
movie = Movie.new('The Matrix', Movie::REGULAR) | |
rental = Rental.new(movie, 3) | |
assert_equal rental.movie, movie | |
assert_equal rental.days_rented, 3 | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment