Skip to content

Instantly share code, notes, and snippets.

@Heavyblade
Created February 12, 2024 22:09
Show Gist options
  • Save Heavyblade/7b5c8e7c423f96b36b1a638ebec42e94 to your computer and use it in GitHub Desktop.
Save Heavyblade/7b5c8e7c423f96b36b1a638ebec42e94 to your computer and use it in GitHub Desktop.
rental_program
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
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