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

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

Към профила на Владимир Ценев

Резултати

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

Код

require 'bigdecimal'
require 'bigdecimal/util'
class Inventory
def initialize
@inventory = {}
@registered_coupons = {}
end
def register(product_name, price_as_str, discount = {})
price = BigDecimal.new(price_as_str)
if product_name.length > 40 or price < 0.01 or price > 999.99 or exist(product_name)
raise "Invalid paramaters passed."
return
end
new_product = Product.new(product_name, price_as_str, discount)
@inventory[product_name] = new_product
end
def new_cart
@cart = Cart.new
@cart.inventory = @inventory
@cart.available_coupons = @registered_coupons
return @cart
end
def register_coupon(coupon_name, type)
@registered_coupons[coupon_name] = type
end
def exist(name)
return true if @inventory.has_key? name
end
end
class Product
attr_accessor :name, :price, :discount
def initialize(name, price, discount)
@name, @price, @discount = name, price, discount
end
end
class Cart
attr_writer :inventory, :available_coupons
def initialize
@items_in_cart, @available_coupons, @inventory = {}
@sum = BigDecimal.new('0')
@prod_disc = BigDecimal.new('0')
@discount_amount = BigDecimal.new('0')
@discount_percent = BigDecimal.new('1')
@coupon_used = false
end
def add(product_name, count = 1)
raise "Product count is wrong." if count < 1
if @inventory.has_key? product_name
product = @inventory[product_name]
@items_in_cart[product] = 0 if @items_in_cart[product] == nil
@items_in_cart[product] = @items_in_cart[product] + count
raise "Product count is wrong." if @items_in_cart[product] > 99
else
raise "Product doesn't exist in inventory."
end
end
def total
@items_in_cart.each do |product, count|
apply_discounts(product, count)
@sum = @sum + count*product.price.to_d - @prod_disc
end
result = BigDecimal.new("0")
if @sum*@discount_percent - @discount_amount < 0
return result
else
result = @sum*@discount_percent - @discount_amount
return result
end
end
def invoice
# invoice...
end
def use(name)
if @coupon_used or not @available_coupons.has_key? name
raise "Wrong coupon name or another is used."
return
end
type_discount = @available_coupons[name]
if type_discount.has_key? :percent
@discount_percent = 1 - type_discount[:percent].to_f/100
elsif type_discount.has_key? :amount
@discount_amount = @discount_amount + type_discount[:amount].to_d
end
end
def apply_discounts(prod, count)
if prod.discount.has_key? :get_one_free
get_free = (count/prod.discount[:get_one_free])
@prod_disc = prod.price.to_d*get_free if count >= get_free
elsif prod.discount.has_key? :package
calc_package(prod.discount[:package], prod, count)
elsif prod.discount.has_key? :threshold
calc_threshold(prod.discount[:threshold], prod, count)
end
end
def calc_package(rule, prod, count)
rule.each { |k, v| @prod_disc = count*prod.price.to_d*(v.to_f/100) if count >= k }
end
def calc_threshold(rule, prod, count)
rule.each { |k, v| @prod_disc = (count-k)*prod.price.to_d*(v.to_f/100) if count > k }
end
end

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

..F..FFFF.FF..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: nil
       
       (compared using ==)
     # /tmp/d20111115-5847-qhwbwl/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: nil
       
       (compared using ==)
     # /tmp/d20111115-5847-qhwbwl/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 gives % off for every group of n
     Failure/Error: cart.total.should eq '6.40'.to_d
       
       expected: #<BigDecimal:957b120,'0.64E1',8(8)>
            got: 9.6
       
       (compared using ==)
     # /tmp/d20111115-5847-qhwbwl/spec.rb:134: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 for every n' promotion does not discount for extra items, that don't fit in a group
     Failure/Error: cart.total.should eq '2.80'.to_d
       
       expected: #<BigDecimal:95797a8,'0.28E1',8(8)>
            got: 4.5
       
       (compared using ==)
     # /tmp/d20111115-5847-qhwbwl/spec.rb:144: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 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: nil
       
       (compared using ==)
     # /tmp/d20111115-5847-qhwbwl/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)>'

  6) 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 '10.00'.to_d
       
       expected: #<BigDecimal:95947c4,'0.1E2',4(8)>
            got: #<BigDecimal:9594800,'0.18E2',4(12)>
       
       (compared using ==)
     # /tmp/d20111115-5847-qhwbwl/spec.rb:184: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 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: nil
       
       (compared using ==)
     # /tmp/d20111115-5847-qhwbwl/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)>'

  8) 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: nil
       
       (compared using ==)
     # /tmp/d20111115-5847-qhwbwl/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)>'

  9) 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: nil
       
       (compared using ==)
     # /tmp/d20111115-5847-qhwbwl/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)>'

  10) 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: nil
       
       (compared using ==)
     # /tmp/d20111115-5847-qhwbwl/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.57917 seconds
19 examples, 10 failures

Failed examples:

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

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

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

+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class Inventory
+
+ def initialize
+ @inventory = {}
+ @registered_coupons = {}
+ end
+
+ def register(product_name, price_as_str, discount = {})
+ price = BigDecimal.new(price_as_str)
+ if product_name.length > 40 or price < 0.01 or price > 999.99 or exist(product_name)
+ raise "Invalid paramaters passed."
+ return
+ end
+ new_product = Product.new(product_name, price_as_str, discount)
+ @inventory[product_name] = new_product
+ end
+
+ def new_cart
+ @cart = Cart.new
+ @cart.inventory = @inventory
+ @cart.available_coupons = @registered_coupons
+ return @cart
+ end
+
+ def register_coupon(coupon_name, type)
+ @registered_coupons[coupon_name] = type
+ end
+
+ def exist(name)
+ return true if @inventory.has_key? name
+ end
+
+end
+
+
+class Product
+
+ attr_accessor :name, :price, :discount
+
+ def initialize(name, price, discount)
+ @name, @price, @discount = name, price, discount
+ end
+
+end
+
+
+class Cart
+
+ attr_writer :inventory, :available_coupons
+
+
+ def initialize
+ @items_in_cart, @available_coupons, @inventory = {}
+ @sum = BigDecimal.new('0')
+ @prod_disc = BigDecimal.new('0')
+ @discount_amount = BigDecimal.new('0')
+ @discount_percent = BigDecimal.new('1')
+ @coupon_used = false
+ end
+
+ def add(product_name, count = 1)
+ raise "Product count is wrong." if count < 1
+ if @inventory.has_key? product_name
+ product = @inventory[product_name]
+ @items_in_cart[product] = 0 if @items_in_cart[product] == nil
+ @items_in_cart[product] = @items_in_cart[product] + count
+ raise "Product count is wrong." if @items_in_cart[product] > 99
+ else
+ raise "Product doesn't exist in inventory."
+ end
+ end
+
+ def total
+ @items_in_cart.each do |product, count|
+ apply_discounts(product, count)
+ @sum = @sum + count*product.price.to_d - @prod_disc
+ end
+ result = BigDecimal.new("0")
+ if @sum*@discount_percent - @discount_amount < 0
+ return result
+ else
+ result = @sum*@discount_percent - @discount_amount
+ return result
+ end
+ end
+
+ def invoice
+ # invoice...
+ end
+
+ def use(name)
+ if @coupon_used or not @available_coupons.has_key? name
+ raise "Wrong coupon name or another is used."
+ return
+ end
+ type_discount = @available_coupons[name]
+ if type_discount.has_key? :percent
+ @discount_percent = 1 - type_discount[:percent].to_f/100
+ elsif type_discount.has_key? :amount
+ @discount_amount = @discount_amount + type_discount[:amount].to_d
+ end
+ end
+
+ def apply_discounts(prod, count)
+ if prod.discount.has_key? :get_one_free
+ get_free = (count/prod.discount[:get_one_free])
+ @prod_disc = prod.price.to_d*get_free if count >= get_free
+ elsif prod.discount.has_key? :package
+ calc_package(prod.discount[:package], prod, count)
+ elsif prod.discount.has_key? :threshold
+ calc_threshold(prod.discount[:threshold], prod, count)
+ end
+ end
+
+ def calc_package(rule, prod, count)
+ rule.each { |k, v| @prod_disc = count*prod.price.to_d*(v.to_f/100) if count >= k }
+ end
+
+ def calc_threshold(rule, prod, count)
+ rule.each { |k, v| @prod_disc = (count-k)*prod.price.to_d*(v.to_f/100) if count > k }
+ end
+
+end