From: "bcparanj@..." Date: 2007-03-17T03:50:07+09:00 Subject: Need feedback on improving Ruby code 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.