Решение на Трета задача от Велина Ташева

Обратно към всички решения

Към профила на Велина Ташева

Резултати

  • 0 точки от тестове
  • 0 бонус точки
  • 0 точки общо
  • 0 успешни тест(а)
  • 19 неуспешни тест(а)

Код

require 'bigdecimal'
require 'bigdecimal/util'
class Inventory
attr_accessor :inventory
def initialize
@inventory = []
end
def register(name, price, promotion = {})
new_product = Product.new(name, price, promotion)
if @inventory.include? new_product
raise "This product is already registered."
end
@inventory << new_product
end
def new_cart
Cart.new inventory
end
end
class Cart
FRAMEWORK_PATTERN = "|------------------------------------------------|----------|\n"
LINE_PATTERN = "+------------------------------------------------+----------+\n"
ITEM_DEFINITION = "------------------------------------------------"
PRICE_DEFINITION = "----------"
attr_accessor :cart, :inventory
def initialize(inventory)
@cart = {}
@inventory = inventory
end
def add(name, amount = 1)
if !@inventory.select { |item| item.name == name }
raise "This product does not exist in inventory."
end
if @cart.has_key? name
add_existing_product name, amount
else
add_not_existing_product name, amount
end
end
def total
total = BigDecimal('')
@cart.each do |key, amount|
product = @inventory.select { |item| item.name == key }[0]
total += product.price * amount
if product.promotion.has_key? :get_one_free
total -= (amount / product.promotion[:get_one_free]) * product.price
end
end
"%.2f" % total
end
def invoice
items = get_items
result = invoice_header
items.each do |product, v|
line = process_item(product, v)
result += line
end
result += invoice_footer
result
end
private
def get_items
items = {}
@cart.each do |key, amount|
product = @inventory.select { |item| item.name == key}[0]
items[product.name] = product.price * amount
if product.promotion.has_key? :get_one_free
items[product.name] -= (amount / product.promotion[:get_one_free]) * product.price
end
end
items
end
def add_existing_product(name, amount)
if (@cart[name] + amount <= 0 || @cart[name] + amount > 99)
raise "Not valid value for amount"
end
@cart[name] += amount
end
def add_not_existing_product(name, amount)
if amount <= 0
raise "Not valid value for amount"
end
@cart[name] = amount
end
def process_item(product, v)
line = ''
price = "%.2f" % v.round(2)
product_price = @cart[product].to_s
number_spaces = ITEM_DEFINITION.length - product.length - product_price.length
spaces = " " * number_spaces
line = FRAMEWORK_PATTERN.gsub(ITEM_DEFINITION, product + spaces + product_price)
number_spaces = PRICE_DEFINITION.length - price.length
line.gsub(PRICE_DEFINITION, " " * number_spaces + price)
end
def invoice_header
result = LINE_PATTERN
number_spaces = ITEM_DEFINITION.length - "Name".length - "qty".length
spaces = " " * number_spaces
line = FRAMEWORK_PATTERN.gsub(ITEM_DEFINITION, "Name" + spaces + "qty")
number_spaces = PRICE_DEFINITION.length - "price".length
line = line.gsub(PRICE_DEFINITION, " " * number_spaces + "price")
result += line + LINE_PATTERN
result
end
def invoice_footer
result = LINE_PATTERN
price = total
number_spaces = ITEM_DEFINITION.length - "TOTAL".length
line = FRAMEWORK_PATTERN.gsub(ITEM_DEFINITION, "TOTAL" + " " * number_spaces)
number_spaces = PRICE_DEFINITION.length - price.length
line = line.gsub(PRICE_DEFINITION, " " * number_spaces + price)
result += line + LINE_PATTERN
result
end
end
class Product
attr_accessor :name, :price, :promotion
def initialize(name, price, promotion)
if name.length > 40
raise "Name cannot be longer than 40 symbols."
end
range = 0.01..999.99
if !range.include? price.to_d
raise "Price is not in the range 0.01..999.99"
end
@name = name
@price = price.to_d
@promotion = promotion
end
def ===(other)
self.name == other.name
end
end

Лог от изпълнението

FFFFFFFFFFFFFFFFFFF

Failures:

  1) Inventory with no discounts can tell the total price of all products
     Failure/Error: cart.total.should eq '3.98'.to_d
       
       expected: #<BigDecimal:9e0ef30,'0.398E1',8(8)>
            got: "3.98"
       
       (compared using ==)
     # /tmp/d20111115-5847-1gufjdf/spec.rb:44:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) Inventory with no discounts has some constraints on prices and counts
     Failure/Error: expect { cart.add 'Unexisting' }.to raise_error
       expected Exception but nothing was raised
     # /tmp/d20111115-5847-1gufjdf/spec.rb:59:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) Inventory with no discounts can print an invoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    1 |     0.79 |\n| Earl Grey                                    3 |     2.97 |\n| Black Coffee                                 2 |     3.98 |\n+------------------------------------------------+----------+\n| TOTAL                                          |     7.74 |\n+------------------------------------------------+----------+\n"
            got: "+------------------------------------------------+----------+\n|Name                                         qty|     price|\n+------------------------------------------------+----------+\n|Green Tea                                      1|      0.79|\n|Earl Grey                                      3|      2.97|\n|Black Coffee                                   2|      3.98|\n+------------------------------------------------+----------+\n|TOTAL                                           |      7.74|\n+------------------------------------------------+----------+\n"
       
       (compared using ==)
       
       Diff:
       
       
       @@ -1,10 +1,10 @@
        +------------------------------------------------+----------+
       -| Name                                       qty |    price |
       +|Name                                         qty|     price|
        +------------------------------------------------+----------+
       -| Green Tea                                    1 |     0.79 |
       -| Earl Grey                                    3 |     2.97 |
       -| Black Coffee                                 2 |     3.98 |
       +|Green Tea                                      1|      0.79|
       +|Earl Grey                                      3|      2.97|
       +|Black Coffee                                   2|      3.98|
        +------------------------------------------------+----------+
       -| TOTAL                                          |     7.74 |
       +|TOTAL                                           |      7.74|
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1gufjdf/spec.rb:73:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  4) Inventory with a 'buy X, get one free' promotion grants every nth item for free
     Failure/Error: cart.total.should eq '3.00'.to_d
       
       expected: #<BigDecimal:9ae35cc,'0.3E1',4(8)>
            got: "3.00"
       
       (compared using ==)
     # /tmp/d20111115-5847-1gufjdf/spec.rb:93:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  5) Inventory with a 'buy X, get one free' promotion grants 2 items free, when 8 purchased and every 3rd is free
     Failure/Error: cart.total.should eq '6.00'.to_d
       
       expected: #<BigDecimal:9ae2528,'0.6E1',4(8)>
            got: "6.00"
       
       (compared using ==)
     # /tmp/d20111115-5847-1gufjdf/spec.rb:101:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  6) Inventory with a 'buy X, get one free' promotion shows the discount in the invoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    3 |     3.00 |\n|   (buy 2, get 1 free)                          |    -1.00 |\n| Red Tea                                      8 |    16.00 |\n|   (buy 4, get 1 free)                          |    -2.00 |\n+------------------------------------------------+----------+\n| TOTAL                                          |    16.00 |\n+------------------------------------------------+----------+\n"
            got: "+------------------------------------------------+----------+\n|Name                                         qty|     price|\n+------------------------------------------------+----------+\n|Green Tea                                      3|      2.00|\n|Red Tea                                        8|     14.00|\n+------------------------------------------------+----------+\n|TOTAL                                           |     16.00|\n+------------------------------------------------+----------+\n"
       
       (compared using ==)
       
       Diff:
       
       
       @@ -1,11 +1,9 @@
        +------------------------------------------------+----------+
       -| Name                                       qty |    price |
       +|Name                                         qty|     price|
        +------------------------------------------------+----------+
       -| Green Tea                                    3 |     3.00 |
       -|   (buy 2, get 1 free)                          |    -1.00 |
       -| Red Tea                                      8 |    16.00 |
       -|   (buy 4, get 1 free)                          |    -2.00 |
       +|Green Tea                                      3|      2.00|
       +|Red Tea                                        8|     14.00|
        +------------------------------------------------+----------+
       -| TOTAL                                          |    16.00 |
       +|TOTAL                                           |     16.00|
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1gufjdf/spec.rb:111:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  7) Inventory with a '% off for every n' promotion gives % off for every group of n
     Failure/Error: cart.total.should eq '3.20'.to_d
       
       expected: #<BigDecimal:9cd70b8,'0.32E1',8(8)>
            got: "4.00"
       
       (compared using ==)
     # /tmp/d20111115-5847-1gufjdf/spec.rb:131:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  8) Inventory with a '% off for every n' promotion does not discount for extra items, that don't fit in a group
     Failure/Error: cart.total.should eq '1.80'.to_d
       
       expected: #<BigDecimal:9cd608c,'0.18E1',8(8)>
            got: "2.00"
       
       (compared using ==)
     # /tmp/d20111115-5847-1gufjdf/spec.rb:141:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  9) Inventory with a '% off for every n' promotion shows the discount in the invoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    4 |     4.00 |\n|   (get 10% off for every 4)                    |    -0.40 |\n| Red Tea                                      8 |    16.00 |\n|   (get 20% off for every 5)                    |    -2.00 |\n+------------------------------------------------+----------+\n| TOTAL                                          |    17.60 |\n+------------------------------------------------+----------+\n"
            got: "+------------------------------------------------+----------+\n|Name                                         qty|     price|\n+------------------------------------------------+----------+\n|Green Tea                                      4|      4.00|\n|Red Tea                                        8|     16.00|\n+------------------------------------------------+----------+\n|TOTAL                                           |     20.00|\n+------------------------------------------------+----------+\n"
       
       (compared using ==)
       
       Diff:
       
       
       @@ -1,11 +1,9 @@
        +------------------------------------------------+----------+
       -| Name                                       qty |    price |
       +|Name                                         qty|     price|
        +------------------------------------------------+----------+
       -| Green Tea                                    4 |     4.00 |
       -|   (get 10% off for every 4)                    |    -0.40 |
       -| Red Tea                                      8 |    16.00 |
       -|   (get 20% off for every 5)                    |    -2.00 |
       +|Green Tea                                      4|      4.00|
       +|Red Tea                                        8|     16.00|
        +------------------------------------------------+----------+
       -| TOTAL                                          |    17.60 |
       +|TOTAL                                           |     20.00|
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1gufjdf/spec.rb:154:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  10) Inventory with a '% off of every item after the nth' promotion gives a discount for every item after the nth
     Failure/Error: cart.total.should eq '15.40'.to_d
       
       expected: #<BigDecimal:997d458,'0.154E2',8(8)>
            got: "16.00"
       
       (compared using ==)
     # /tmp/d20111115-5847-1gufjdf/spec.rb:174:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  11) Inventory with a '% off of every item after the nth' promotion does not give a discount if there are no more than n items in the cart
     Failure/Error: cart.total.should eq '8.00'.to_d
       
       expected: #<BigDecimal:997c42c,'0.8E1',4(8)>
            got: "8.00"
       
       (compared using ==)
     # /tmp/d20111115-5847-1gufjdf/spec.rb:181:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  12) Inventory with a '% off of every item after the nth' promotion shows the discount in the ivnoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                   12 |    12.00 |\n|   (10% off of every after the 10th)            |    -0.20 |\n| Red Tea                                     20 |    40.00 |\n|   (20% off of every after the 15th)            |    -2.00 |\n+------------------------------------------------+----------+\n| TOTAL                                          |    49.80 |\n+------------------------------------------------+----------+\n"
            got: "+------------------------------------------------+----------+\n|Name                                         qty|     price|\n+------------------------------------------------+----------+\n|Green Tea                                     12|     12.00|\n|Red Tea                                       20|     40.00|\n+------------------------------------------------+----------+\n|TOTAL                                           |     52.00|\n+------------------------------------------------+----------+\n"
       
       (compared using ==)
       
       Diff:
       
       
       @@ -1,11 +1,9 @@
        +------------------------------------------------+----------+
       -| Name                                       qty |    price |
       +|Name                                         qty|     price|
        +------------------------------------------------+----------+
       -| Green Tea                                   12 |    12.00 |
       -|   (10% off of every after the 10th)            |    -0.20 |
       -| Red Tea                                     20 |    40.00 |
       -|   (20% off of every after the 15th)            |    -2.00 |
       +|Green Tea                                     12|     12.00|
       +|Red Tea                                       20|     40.00|
        +------------------------------------------------+----------+
       -| TOTAL                                          |    49.80 |
       +|TOTAL                                           |     52.00|
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1gufjdf/spec.rb:197:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  13) Inventory with a '% off' coupon gives % off of the total
     Failure/Error: inventory.register_coupon 'TEATIME', percent: 20
     NoMethodError:
       undefined method `register_coupon' for #<Inventory:0x999b714>
     # /tmp/d20111115-5847-1gufjdf/spec.rb:215:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  14) Inventory with a '% off' coupon applies the coupon discount after product promotions
     Failure/Error: inventory.register_coupon 'TEATIME', percent: 10
     NoMethodError:
       undefined method `register_coupon' for #<Inventory:0x999abc0>
     # /tmp/d20111115-5847-1gufjdf/spec.rb:225:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  15) Inventory with a '% off' coupon shows the discount in the invoice
     Failure/Error: inventory.register_coupon 'TEA-TIME', percent: 20
     NoMethodError:
       undefined method `register_coupon' for #<Inventory:0x999a170>
     # /tmp/d20111115-5847-1gufjdf/spec.rb:235:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  16) Inventory with an 'amount off' coupon subtracts the amount form the total
     Failure/Error: inventory.register_coupon 'TEATIME', amount: '10.00'.to_d
     NoMethodError:
       undefined method `register_coupon' for #<Inventory:0x9ddc1ac>
     # /tmp/d20111115-5847-1gufjdf/spec.rb:256:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  17) Inventory with an 'amount off' coupon does not result in a negative total
     Failure/Error: inventory.register_coupon 'TEATIME', amount: '10.00'.to_d
     NoMethodError:
       undefined method `register_coupon' for #<Inventory:0x9ddb61c>
     # /tmp/d20111115-5847-1gufjdf/spec.rb:266:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  18) Inventory with an 'amount off' coupon shows the discount in the invoice
     Failure/Error: inventory.register_coupon 'TEA-TIME', amount: '10.00'.to_d
     NoMethodError:
       undefined method `register_coupon' for #<Inventory:0x9ddab90>
     # /tmp/d20111115-5847-1gufjdf/spec.rb:276:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  19) Inventory with multiple discounts can print an invoice
     Failure/Error: inventory.register_coupon 'BREAKFAST', percent: 10
     NoMethodError:
       undefined method `register_coupon' for #<Inventory:0x9dd9e70>
     # /tmp/d20111115-5847-1gufjdf/spec.rb:301:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.61027 seconds
19 examples, 19 failures

Failed examples:

rspec /tmp/d20111115-5847-1gufjdf/spec.rb:38 # Inventory with no discounts can tell the total price of all products
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:47 # Inventory with no discounts has some constraints on prices and counts
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:64 # Inventory with no discounts can print an invoice
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:88 # Inventory with a 'buy X, get one free' promotion grants every nth item for free
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:96 # Inventory with a 'buy X, get one free' promotion grants 2 items free, when 8 purchased and every 3rd is free
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:104 # Inventory with a 'buy X, get one free' promotion shows the discount in the invoice
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:127 # Inventory with a '% off for every n' promotion gives % off for every group of n
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:137 # Inventory with a '% off for every n' promotion does not discount for extra items, that don't fit in a group
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:147 # Inventory with a '% off for every n' promotion shows the discount in the invoice
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:170 # Inventory with a '% off of every item after the nth' promotion gives a discount for every item after the nth
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:177 # Inventory with a '% off of every item after the nth' promotion does not give a discount if there are no more than n items in the cart
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:190 # Inventory with a '% off of every item after the nth' promotion shows the discount in the ivnoice
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:213 # Inventory with a '% off' coupon gives % off of the total
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:223 # Inventory with a '% off' coupon applies the coupon discount after product promotions
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:233 # Inventory with a '% off' coupon shows the discount in the invoice
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:254 # Inventory with an 'amount off' coupon subtracts the amount form the total
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:264 # Inventory with an 'amount off' coupon does not result in a negative total
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:274 # Inventory with an 'amount off' coupon shows the discount in the invoice
rspec /tmp/d20111115-5847-1gufjdf/spec.rb:295 # Inventory with multiple discounts can print an invoice

История (1 версия и 0 коментара)

Велина обнови решението на 07.11.2011 16:59 (преди около 13 години)

+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class Inventory
+ attr_accessor :inventory
+
+ def initialize
+ @inventory = []
+ end
+
+ def register(name, price, promotion = {})
+ new_product = Product.new(name, price, promotion)
+ if @inventory.include? new_product
+ raise "This product is already registered."
+ end
+
+ @inventory << new_product
+ end
+
+ def new_cart
+ Cart.new inventory
+ end
+end
+
+class Cart
+ FRAMEWORK_PATTERN = "|------------------------------------------------|----------|\n"
+ LINE_PATTERN = "+------------------------------------------------+----------+\n"
+ ITEM_DEFINITION = "------------------------------------------------"
+ PRICE_DEFINITION = "----------"
+
+ attr_accessor :cart, :inventory
+
+ def initialize(inventory)
+ @cart = {}
+ @inventory = inventory
+ end
+
+ def add(name, amount = 1)
+ if !@inventory.select { |item| item.name == name }
+ raise "This product does not exist in inventory."
+ end
+
+ if @cart.has_key? name
+ add_existing_product name, amount
+ else
+ add_not_existing_product name, amount
+ end
+ end
+
+ def total
+ total = BigDecimal('')
+ @cart.each do |key, amount|
+ product = @inventory.select { |item| item.name == key }[0]
+ total += product.price * amount
+ if product.promotion.has_key? :get_one_free
+ total -= (amount / product.promotion[:get_one_free]) * product.price
+ end
+ end
+ "%.2f" % total
+ end
+
+ def invoice
+ items = get_items
+ result = invoice_header
+
+ items.each do |product, v|
+ line = process_item(product, v)
+ result += line
+ end
+
+ result += invoice_footer
+ result
+ end
+
+ private
+
+ def get_items
+ items = {}
+ @cart.each do |key, amount|
+ product = @inventory.select { |item| item.name == key}[0]
+ items[product.name] = product.price * amount
+ if product.promotion.has_key? :get_one_free
+ items[product.name] -= (amount / product.promotion[:get_one_free]) * product.price
+ end
+ end
+ items
+ end
+
+ def add_existing_product(name, amount)
+ if (@cart[name] + amount <= 0 || @cart[name] + amount > 99)
+ raise "Not valid value for amount"
+ end
+ @cart[name] += amount
+ end
+
+ def add_not_existing_product(name, amount)
+ if amount <= 0
+ raise "Not valid value for amount"
+ end
+ @cart[name] = amount
+ end
+
+ def process_item(product, v)
+ line = ''
+
+ price = "%.2f" % v.round(2)
+ product_price = @cart[product].to_s
+ number_spaces = ITEM_DEFINITION.length - product.length - product_price.length
+ spaces = " " * number_spaces
+ line = FRAMEWORK_PATTERN.gsub(ITEM_DEFINITION, product + spaces + product_price)
+ number_spaces = PRICE_DEFINITION.length - price.length
+ line.gsub(PRICE_DEFINITION, " " * number_spaces + price)
+ end
+
+ def invoice_header
+ result = LINE_PATTERN
+ number_spaces = ITEM_DEFINITION.length - "Name".length - "qty".length
+ spaces = " " * number_spaces
+ line = FRAMEWORK_PATTERN.gsub(ITEM_DEFINITION, "Name" + spaces + "qty")
+
+ number_spaces = PRICE_DEFINITION.length - "price".length
+ line = line.gsub(PRICE_DEFINITION, " " * number_spaces + "price")
+ result += line + LINE_PATTERN
+ result
+ end
+
+ def invoice_footer
+ result = LINE_PATTERN
+ price = total
+ number_spaces = ITEM_DEFINITION.length - "TOTAL".length
+ line = FRAMEWORK_PATTERN.gsub(ITEM_DEFINITION, "TOTAL" + " " * number_spaces)
+
+ number_spaces = PRICE_DEFINITION.length - price.length
+ line = line.gsub(PRICE_DEFINITION, " " * number_spaces + price)
+ result += line + LINE_PATTERN
+ result
+ end
+end
+
+class Product
+ attr_accessor :name, :price, :promotion
+
+ def initialize(name, price, promotion)
+ if name.length > 40
+ raise "Name cannot be longer than 40 symbols."
+ end
+
+ range = 0.01..999.99
+ if !range.include? price.to_d
+ raise "Price is not in the range 0.01..999.99"
+ end
+
+ @name = name
+ @price = price.to_d
+ @promotion = promotion
+ end
+
+ def ===(other)
+ self.name == other.name
+ end
+end
+
+