require ‘print_receipt’
require “test/unit”
class TestReceiptBuilder < Test::Unit::TestCase
def test_create_dynamic_method_list
r = ReceiptBuilder.new([[“1 book at 12.49”], [“1 music cd at
14.99”], [“1 chocolate bar at 0.85”]])
r.create_dynamic_method_list
assert_equal r.dynamic_method_list.size, 3
assert_equal r.dynamic_method_list[0].to_s, "buy(1,' book ') { at
12.49 }"
assert_equal r.dynamic_method_list[1].to_s, “buy(1,’ music cd ')
{ at 14.99 }”
assert_equal r.dynamic_method_list[2].to_s, “buy(1,’ chocolate bar
') { at 0.85 }”
end
def test_nearest_five_rounding
assert_equal ReceiptBuilder.round_to_nearest_five_cents(0.01),
0.05
assert_equal ReceiptBuilder.round_to_nearest_five_cents(0.02),
0.05
assert_equal ReceiptBuilder.round_to_nearest_five_cents(0.03),
0.05
assert_equal ReceiptBuilder.round_to_nearest_five_cents(0.04),
0.05
assert_equal ReceiptBuilder.round_to_nearest_five_cents(0.05),
0.05
assert_equal ReceiptBuilder.round_to_nearest_five_cents(0.06),
0.1
assert_equal ReceiptBuilder.round_to_nearest_five_cents(0.07),
0.1
assert_equal ReceiptBuilder.round_to_nearest_five_cents(0.08),
0.1
assert_equal ReceiptBuilder.round_to_nearest_five_cents(0.09),
0.1
assert_equal ReceiptBuilder.round_to_nearest_five_cents(0.1), 0.1
end
def test_exempt_products
r = ReceiptBuilder.new([])
exempt_products = ["book", "chocolate bar", "packet of headache
pills", “imported box of chocolates”,
“box of imported chocolates”]
exempt_products.each do |product|
assert r.is_exempt_product?(product)
end
non_exempt_products = ["tin tin", "bugs bunny"]
non_exempt_products.each do |product|
assert !r.is_exempt_product?(product)
end
end
def test_imported_products
r = ReceiptBuilder.new([])
imported_products = ["imported box of chocolates", "imported
bottle of perfume", “box of imported chocolates”]
imported_products.each do |product|
assert r.is_imported_product?(product)
end
end
def test_line_item
r = ReceiptBuilder.new([[“1 book at 12.49”], [“1 music cd at
14.99”], [“1 chocolate bar at 0.85”]])
r.create_dynamic_method_list
r.generate_output
r.print_output
line_item = LineItem.new(1, 'book', 15.99)
assert_not_nil line_item.nil?
assert_not_nil line_item.quantity
assert_equal line_item.quantity, 1
assert_not_nil line_item.name
assert_equal line_item.name, 'book'
assert_not_nil line_item.price
assert_equal line_item.price, 15.99
# Check for all combinations of exempt and imported status
assert_equal line_item.sales_tax_for('imported bottle of perfume',
10, 1), 1.5
assert_equal line_item.sales_tax_for(‘chocolate bar’, 10,1), 0
assert_equal line_item.sales_tax_for(‘bugs bunny’, 10,1), 1
assert_equal line_item.sales_tax_for(‘imported box of chocolates’,
10,1), 0.5
end
def test_output_two
r = ReceiptBuilder.new([[“1 imported box of chocolates at 10.00”],
[“1 imported bottle of perfume at 47.50”]])
r.create_dynamic_method_list
r.generate_output
r.print_output
# line_item = LineItem.new(1, 'imported bottle of perfume', 10)
assert_equal line_item.sales_tax_for('imported box of
chocolates’, 47.5,1), 2.375
end
def test_output_three
r = ReceiptBuilder.new([[“1 imported bottle of perfume at 27.99”],
[“1 bottle of perfume at 18.99”], [“1 packet of headache pills at
9.75”],[“1 box of imported chocolates at 11.25”]])
r.create_dynamic_method_list
r.generate_output
r.print_output
end
end
The same inputs and outputs are:
Input 1:
1 book at 12.49
1 music CD at 14.99
1 chocolate bar at 0.85
Input 2:
1 imported box of chocolates at 10.00
1 imported bottle of perfume at 47.50
Input 3:
1 imported bottle of perfume at 27.99
1 bottle of perfume at 18.99
1 packet of headache pills at 9.75
1 box of imported chocolates at 11.25
OUTPUT
Output 1:
1 book : 12.49
1 music CD: 16.49
1 chocolate bar: 0.85
Sales Taxes: 1.50
Total: 29.83
Output 2:
1 imported box of chocolates: 10.50
1 imported bottle of perfume: 54.65
Sales Taxes: 7.65
Total: 65.15
Output 3:
1 imported bottle of perfume: 32.19
1 bottle of perfume: 20.89
1 packet of headache pills: 9.75
1 imported box of chocolates: 11.85
Sales Taxes: 6.70
Total: 74.68
print_receipt.rb
class ReceiptBuilder
module SalesTaxPolicy
BASE_SALES_TAX = 0.1
IMPORT_DUTY = 0.05
def is_exempt_product?(product)
["book", "chocolate bar", "packet of headache pills", "imported
box of chocolates",
“box of imported chocolates”].include?
(product)
end
def is_imported_product?(product)
["imported box of chocolates", "imported bottle of perfume",
“box of imported chocolates”].include?(product)
end
end
include SalesTaxPolicy
attr_accessor :dynamic_method_list, :buffer, :line_items_list
@@header = “Count Item Price\n”
def initialize(purchase_list)
@dynamic_method_list = Array::new
@purchased_items = purchase_list
@buffer = Array::new
@line_items_list = Array::new
end
def generate_output
@dynamic_method_list.each do |element|
eval(element.to_s)
end
end
def create_dynamic_method_list
@purchased_items.each do |s|
input_tokens = s.to_s.split(/(\s+)/)
input_tokens.each_index do |i|
input_tokens[i] = "') { at " if input_tokens[i] ==
“at”
end
input_tokens[0] = input_tokens[0] + ",'"
input_tokens.unshift "buy("
input_tokens << " }"
@dynamic_method_list << input_tokens
end
end
def buy(quantity, item, &block)
_save_line_item_output(quantity, item, block.call)
end
def at(price)
price
end
def self.round_to_nearest_five_cents(price)
((20 * (price + 0.04)).floor)*0.05
end
def print_output
puts “_________________________________________________”
puts @@header
puts @buffer.to_s
total = 0
@line_items_list.each do |item|
total += item.tax_inclusive_price
end
sales_tax_total = 0
@line_items_list.each do |item|
sales_tax_total += item.sales_tax_for(item.name, item.price,
item.quantity)
end
rounded_sales_tax =
ReceiptBuilder.round_to_nearest_five_cents(sales_tax_total)
rounded_total = ReceiptBuilder.round_to_nearest_five_cents(total)
puts “_________________________________________________”
puts “Sales Taxes : #{rounded_sales_tax}”
puts “Total : #{rounded_total}”
end
private
def _save_line_item_output(quantity, item, price)
rounded_amount =
ReceiptBuilder.round_to_nearest_five_cents(price)
line_item = LineItem.new(quantity, item.strip, rounded_amount)
@line_items_list << line_item
@buffer << line_item.to_s + "\n"
end
end
class LineItem
include ReceiptBuilder::SalesTaxPolicy
attr_reader :quantity, :name, :price, :tax_inclusive_price
def initialize(quantity, name, price)
@quantity = quantity
@name = name
@price = price
@tax_inclusive_price =
ReceiptBuilder.round_to_nearest_five_cents(sales_tax_for(name, price,
quantity) + price)
end
def to_s
padding_size = 28 - name.size
extra_space = []
temp = padding_size.times { extra_space << ’ '}
“#{quantity} #{name} :” + extra_space.to_s +
“#{tax_inclusive_price}”
end
Basic sales tax is applicable at a rate of 10% on all goods,
except books,
food, and medical products that are exempt. Import duty is an
additional
sales tax applicable on all imported goods at a rate of 5%, with
no
exemptions.
def sales_tax_for(name, price, quantity)
_importe = is_imported_product?(name)
_exempte = is_exempt_product?(name)
(_basic_tax(_exempte, price) + _import_tax(_importe,
price))*quantity
end
private
def _basic_tax(exempt, price)
if exempt
0
else
BASE_SALES_TAX * price
end
end
def _import_tax(importe, price)
if importe
IMPORT_DUTY * price
else
0
end
end
end
I took a test for a company and they have already decided my
background does not fit their requirements. I want to learn from
advanced Ruby developers on how I can improve the solution. This is
just for improving my Ruby skills. TIA.