Решение на Трета задача от Виктор Карагяуров

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

Към профила на Виктор Карагяуров

Резултати

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

Код

require 'bigdecimal'
require 'bigdecimal/util'
class Inventory
attr_accessor :price_list, :coupons, :inventory
def initialize
@price_list = {}
@coupons = {}
@inventory = { price_list: @price_list, coupons: @coupons }
end
def register product_name, product_price, discount = {}
price = product_price.to_d
raise 'Product name too long.' if product_name.length > 40
raise 'Price too low.' if price < BigDecimal('0.01')
raise 'Price too high.' if price > BigDecimal('999.99')
raise 'Product already registered.' if @price_list[product_name]
@price_list[product_name] = { price: price, discount: discount }
end
def register_coupon coupon_name, coupon_discount
@coupons[coupon_name] = coupon_discount
end
def new_cart
Cart.new @inventory
end
end
class Cart
attr_accessor :inventory, :products
def initialize inventory
@products = Hash.new(0)
@inventory = inventory
end
def add product_name, quantity = 1
current_quantity = @products[product_name]
raise 'No such product.' if !@inventory[:price_list][product_name]
raise 'Too little items.' if current_quantity + quantity <= 0
raise 'Too much items.' if current_quantity + quantity > 99
@products[product_name] += quantity
end
def use coupon_name
raise 'Coupon already used.' if @coupon
raise 'Coupon does not exists.' if !@inventory[:coupons][coupon_name]
@coupon = @inventory[:coupons][coupon_name]
end
def total
total = 0
@subinvoices = @products.map { |product, quantity| subinvoice product, quantity }
@subinvoices.each do |subinvoice|
total += subinvoice[:product_group][2]
if subinvoice[:discount]
total += subinvoice[:discount][1]
end
end
total = apply_coupon total if @coupon
total
end
def invoice
Invoice.new @products, @coupon
end
private
def subinvoice product, quantity
price = @inventory[:price_list][product][:price]
discount = @inventory[:price_list][product][:discount]
subinvoice = {}
if discount.length == 0
subinvoice[:product_group] = [product, quantity, price * quantity]
subinvoice[:discount] = nil
subinvoice
else
get_discount product, price, quantity, discount
end
end
def get_discount product, price, quantity, discount
if discount[:get_one_free]
Discount.get_one_free product, price, quantity, discount[:get_one_free]
elsif discount[:package]
key = discount[:package].keys[0]
Discount.package product, price, quantity, key, discount[:package][key]
elsif discount[:threshold]
key = discount[:threshold].keys[0]
Discount.threshold product, price, quantity, key, discount[:threshold][key]
end
end
def apply_coupon total
if @coupon[:percent]
total *= (100 - @coupon[:percent]) / '100'.to_d
elsif @coupon[:amount]
total -= @coupon[:amount].to_d
total = '0'.to_d if total < 0
end
total
end
end
class Invoice
def initialize products, coupon
end
end
class Coupon
def initialize
end
end
class Discount
def self.get_one_free product, price, quantity, n
subinvoice = {}
subinvoice[:product_group] = [product, quantity, price * quantity]
if quantity >= n
subinvoice[:discount] = ["(buy #{n - 1}, get 1 free)", quantity / n * -price]
end
subinvoice
end
def self.package product, price, quantity, package_size, package_discount
subinvoice = {}
subinvoice[:product_group] = [product, quantity, price * quantity]
if quantity >= package_size
price_modifier = package_discount / '100'.to_d
packages = quantity / package_size
subinvoice[:discount] = ["(get #{package_discount}% off for every #{package_size})"]
subinvoice[:discount] << packages * package_size * price_modifier * -price
end
subinvoice
end
def self.threshold product, price, quantity, min, discount
subinvoice = {}
subinvoice[:product_group] = [product, quantity, price * quantity]
if quantity > min
price_modifier = discount / '100'.to_d
subinvoice[:discount] = ["(#{discount}% off of every after the #{suffix min})"]
subinvoice[:discount] << (quantity - min) * price_modifier * -price
end
subinvoice
end
def self.suffix number
case number
when 1
'1st'
when 2
'2nd'
when 3
'3rd'
else
"#{number}th"
end
end
end

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

..F..F..F..F..F..FF

Failures:

  1) 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: #<Invoice:0x9e24b64>
       
       (compared using ==)
       
       Diff:
       @@ -1,10 +1,2 @@
       -+------------------------------------------------+----------+
       -| Name                                       qty |    price |
       -+------------------------------------------------+----------+
       -| Green Tea                                    1 |     0.79 |
       -| Earl Grey                                    3 |     2.97 |
       -| Black Coffee                                 2 |     3.98 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |     7.74 |
       -+------------------------------------------------+----------+
       +#<Invoice:0x9e24b64>
     # /tmp/d20111115-5847-1no3peb/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)>'

  2) 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: #<Invoice:0x9a5ebd8>
       
       (compared using ==)
       
       Diff:
       @@ -1,11 +1,2 @@
       -+------------------------------------------------+----------+
       -| 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 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |    16.00 |
       -+------------------------------------------------+----------+
       +#<Invoice:0x9a5ebd8>
     # /tmp/d20111115-5847-1no3peb/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)>'

  3) 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: #<Invoice:0x9ee123c>
       
       (compared using ==)
       
       Diff:
       @@ -1,11 +1,2 @@
       -+------------------------------------------------+----------+
       -| 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 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |    17.60 |
       -+------------------------------------------------+----------+
       +#<Invoice:0x9ee123c>
     # /tmp/d20111115-5847-1no3peb/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)>'

  4) 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: #<Invoice:0x9ef7a64>
       
       (compared using ==)
       
       Diff:
       @@ -1,11 +1,2 @@
       -+------------------------------------------------+----------+
       -| 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 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |    49.80 |
       -+------------------------------------------------+----------+
       +#<Invoice:0x9ef7a64>
     # /tmp/d20111115-5847-1no3peb/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)>'

  5) Inventory with a '% off' coupon shows the discount in the invoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                   10 |    10.00 |\n| Coupon TEA-TIME - 20% off                      |    -2.00 |\n+------------------------------------------------+----------+\n| TOTAL                                          |     8.00 |\n+------------------------------------------------+----------+\n"
            got: #<Invoice:0x9f0f740>
       
       (compared using ==)
       
       Diff:
       @@ -1,9 +1,2 @@
       -+------------------------------------------------+----------+
       -| Name                                       qty |    price |
       -+------------------------------------------------+----------+
       -| Green Tea                                   10 |    10.00 |
       -| Coupon TEA-TIME - 20% off                      |    -2.00 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |     8.00 |
       -+------------------------------------------------+----------+
       +#<Invoice:0x9f0f740>
     # /tmp/d20111115-5847-1no3peb/spec.rb:240: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 an 'amount off' coupon shows the discount in the invoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    5 |     5.00 |\n| Coupon TEA-TIME - 10.00 off                    |    -5.00 |\n+------------------------------------------------+----------+\n| TOTAL                                          |     0.00 |\n+------------------------------------------------+----------+\n"
            got: #<Invoice:0x9eb7f40>
       
       (compared using ==)
       
       Diff:
       @@ -1,9 +1,2 @@
       -+------------------------------------------------+----------+
       -| Name                                       qty |    price |
       -+------------------------------------------------+----------+
       -| Green Tea                                    5 |     5.00 |
       -| Coupon TEA-TIME - 10.00 off                    |    -5.00 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |     0.00 |
       -+------------------------------------------------+----------+
       +#<Invoice:0x9eb7f40>
     # /tmp/d20111115-5847-1no3peb/spec.rb:281: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 multiple discounts can print an invoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    8 |    22.32 |\n|   (buy 1, get 1 free)                          |   -11.16 |\n| Black Coffee                                 5 |    14.95 |\n|   (get 20% off for every 2)                    |    -2.39 |\n| Milk                                         5 |     8.95 |\n|   (30% off of every after the 3rd)             |    -1.07 |\n| Cereal                                       3 |     7.47 |\n| Coupon BREAKFAST - 10% off                     |    -3.91 |\n+------------------------------------------------+----------+\n| TOTAL                                          |    35.16 |\n+------------------------------------------------+----------+\n"
            got: #<Invoice:0x9eb5858>
       
       (compared using ==)
       
       Diff:
       @@ -1,15 +1,2 @@
       -+------------------------------------------------+----------+
       -| Name                                       qty |    price |
       -+------------------------------------------------+----------+
       -| Green Tea                                    8 |    22.32 |
       -|   (buy 1, get 1 free)                          |   -11.16 |
       -| Black Coffee                                 5 |    14.95 |
       -|   (get 20% off for every 2)                    |    -2.39 |
       -| Milk                                         5 |     8.95 |
       -|   (30% off of every after the 3rd)             |    -1.07 |
       -| Cereal                                       3 |     7.47 |
       -| Coupon BREAKFAST - 10% off                     |    -3.91 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |    35.16 |
       -+------------------------------------------------+----------+
       +#<Invoice:0x9eb5858>
     # /tmp/d20111115-5847-1no3peb/spec.rb:309: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.57015 seconds
19 examples, 7 failures

Failed examples:

rspec /tmp/d20111115-5847-1no3peb/spec.rb:64 # Inventory with no discounts can print an invoice
rspec /tmp/d20111115-5847-1no3peb/spec.rb:104 # Inventory with a 'buy X, get one free' promotion shows the discount in the invoice
rspec /tmp/d20111115-5847-1no3peb/spec.rb:147 # Inventory with a '% off for every n' promotion shows the discount in the invoice
rspec /tmp/d20111115-5847-1no3peb/spec.rb:190 # Inventory with a '% off of every item after the nth' promotion shows the discount in the ivnoice
rspec /tmp/d20111115-5847-1no3peb/spec.rb:233 # Inventory with a '% off' coupon shows the discount in the invoice
rspec /tmp/d20111115-5847-1no3peb/spec.rb:274 # Inventory with an 'amount off' coupon shows the discount in the invoice
rspec /tmp/d20111115-5847-1no3peb/spec.rb:295 # Inventory with multiple discounts can print an invoice

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

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

+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class Inventory
+ attr_accessor :price_list, :coupons, :inventory
+ def initialize
+ @price_list = {}
+ @coupons = {}
+ @inventory = { price_list: @price_list, coupons: @coupons }
+ end
+
+ def register product_name, product_price, discount = {}
+ price = product_price.to_d
+ raise 'Product name too long.' if product_name.length > 40
+ raise 'Price too low.' if price < BigDecimal('0.01')
+ raise 'Price too high.' if price > BigDecimal('999.99')
+ raise 'Product already registered.' if @price_list[product_name]
+ @price_list[product_name] = { price: price, discount: discount }
+ end
+
+ def register_coupon coupon_name, coupon_discount
+ @coupons[coupon_name] = coupon_discount
+ end
+
+ def new_cart
+ Cart.new @inventory
+ end
+end
+
+class Cart
+ attr_accessor :inventory, :products
+ def initialize inventory
+ @products = Hash.new(0)
+ @inventory = inventory
+ end
+
+ def add product_name, quantity = 1
+ current_quantity = @products[product_name]
+ raise 'No such product.' if !@inventory[:price_list][product_name]
+ raise 'Too little items.' if current_quantity + quantity <= 0
+ raise 'Too much items.' if current_quantity + quantity > 99
+ @products[product_name] += quantity
+ end
+
+ def use coupon_name
+ raise 'Coupon already used.' if @coupon
+ raise 'Coupon does not exists.' if !@inventory[:coupons][coupon_name]
+ @coupon = @inventory[:coupons][coupon_name]
+ end
+
+ def total
+ total = 0
+ @subinvoices = @products.map { |product, quantity| subinvoice product, quantity }
+ @subinvoices.each do |subinvoice|
+ total += subinvoice[:product_group][2]
+ if subinvoice[:discount]
+ total += subinvoice[:discount][1]
+ end
+ end
+ total = apply_coupon total if @coupon
+ total
+ end
+
+ def invoice
+ Invoice.new @products, @coupon
+ end
+
+ private
+ def subinvoice product, quantity
+ price = @inventory[:price_list][product][:price]
+ discount = @inventory[:price_list][product][:discount]
+ subinvoice = {}
+ if discount.length == 0
+ subinvoice[:product_group] = [product, quantity, price * quantity]
+ subinvoice[:discount] = nil
+ subinvoice
+ else
+ get_discount product, price, quantity, discount
+ end
+ end
+
+ def get_discount product, price, quantity, discount
+ if discount[:get_one_free]
+ Discount.get_one_free product, price, quantity, discount[:get_one_free]
+ elsif discount[:package]
+ key = discount[:package].keys[0]
+ Discount.package product, price, quantity, key, discount[:package][key]
+ elsif discount[:threshold]
+ key = discount[:threshold].keys[0]
+ Discount.threshold product, price, quantity, key, discount[:threshold][key]
+ end
+ end
+
+ def apply_coupon total
+ if @coupon[:percent]
+ total *= (100 - @coupon[:percent]) / '100'.to_d
+ elsif @coupon[:amount]
+ total -= @coupon[:amount].to_d
+ total = '0'.to_d if total < 0
+ end
+ total
+ end
+end
+
+class Invoice
+ def initialize products, coupon
+ end
+end
+
+class Coupon
+ def initialize
+ end
+end
+
+class Discount
+ def self.get_one_free product, price, quantity, n
+ subinvoice = {}
+ subinvoice[:product_group] = [product, quantity, price * quantity]
+ if quantity >= n
+ subinvoice[:discount] = ["(buy #{n - 1}, get 1 free)", quantity / n * -price]
+ end
+ subinvoice
+ end
+
+ def self.package product, price, quantity, package_size, package_discount
+ subinvoice = {}
+ subinvoice[:product_group] = [product, quantity, price * quantity]
+ if quantity >= package_size
+ price_modifier = package_discount / '100'.to_d
+ packages = quantity / package_size
+ subinvoice[:discount] = ["(get #{package_discount}% off for every #{package_size})"]
+ subinvoice[:discount] << packages * package_size * price_modifier * -price
+ end
+ subinvoice
+ end
+
+ def self.threshold product, price, quantity, min, discount
+ subinvoice = {}
+ subinvoice[:product_group] = [product, quantity, price * quantity]
+ if quantity > min
+ price_modifier = discount / '100'.to_d
+ subinvoice[:discount] = ["(#{discount}% off of every after the #{suffix min})"]
+ subinvoice[:discount] << (quantity - min) * price_modifier * -price
+ end
+ subinvoice
+ end
+
+ def self.suffix number
+ case number
+ when 1
+ '1st'
+ when 2
+ '2nd'
+ when 3
+ '3rd'
+ else
+ "#{number}th"
+ end
+ end
+end