Решение на Трета задача от Лъчезар Цанов

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

Към профила на Лъчезар Цанов

Резултати

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

Код

#!/usr/bin/env ruby
require 'bigdecimal'
require 'bigdecimal/util' # добавя String#to_d
class Promotions
@@promotion_list=[:get_one_free ,:package ,:threshold]
def initialize(name,value)
@name = name
@condition = value
end
def exists?
@@promotion_list.include?@name
end
def execute(amount,price)
return calculate_get_one_free(amount,price) if @name == :get_one_free
return calculate_package(amount,price) if @name == :package
return calculate_threshold(amount,price) if @name == :threshold
end
private
def calculate_get_one_free(amount,price)
for_promotion=@condition
free = (amount / for_promotion).to_i
free * price
end
def calculate_package(amount,price)
@condition.each do |count_needed,discount|
no_promotion = amount % count_needed
with_promotion = amount - no_promotion
return (with_promotion * price) * (discount / 100.00).to_d
end
end
def calculate_threshold(amount,price)
@condition.each do |count_needed,discount|
if amount > count_needed
with_promotion = amount - count_needed
no_promotion = count_needed
all = amount * price
return (with_promotion * price) * (discount / 100.00).to_d
else
return 0
end
end
end
end
class Inventory
attr_reader :in_stock
attr_reader :coupons
def initialize
@in_stock = {}
@coupons = {}
end
def register(product,price,promotion=nil)
if promotion != nil
promotion=Promotions.new(promotion.keys.pop,promotion.values.pop)
raise "No such promotion " if !promotion.exists?
end
if product.bytesize > 40 || price.to_f < 0.01 || price.to_f > 999.99
raise "Invalid parameters passed."
else
@in_stock[product] = [price.to_d,promotion]
end
end
def register_coupon(type,discount) #check for negative numbers
@coupons[type]=discount
end
def new_cart
Cart.new(self)
end
end
class Cart
private
def initialize(inventory)
@cart=Hash.new(0)
@in_stock=inventory.in_stock
@coupons=inventory.coupons
@coupons_queue=[]
end
public
def total
@total = total_no_coupons
if @coupons_queue != []
@coupons_queue.each do |name|
condition = @coupons[name]
@total -= coupon_discount(condition)
end
end
return @total
end
def add(product,amount=1)
raise "No #{product} in stock" if @in_stock[product] == nil
if @cart[product] + amount > 0 && @cart[product] + amount < 100
@cart[product] += amount
else
raise "Bad amount of stock.Amount of product >= 0 or more than 99"
end
end
def coupon_exists?(name)
@coupons[name] != nil
end
def coupon_discount(promotion)
if promotion.keys.fetch(0) == :amount
discount = @total - promotion[:amount].to_i
return discount > 0 ? promotion[:amount].to_i : @total
end
if promotion.keys.fetch(0) == :percent
return @total * (promotion[:percent] / 100.00).to_d
end
raise "Invalid Coupon Format."
end
def use(name)
raise "No coupon available." if !coupon_exists?(name)
@coupons_queue<<name
end
def total_no_coupons
@cart.each_key.inject(0) do |total,key|
product_price,promotion = @in_stock[key]
amount_bought = @cart[key]
price = amount_bought * product_price
if promotion != nil
total += price - promotion.execute(amount_bought,product_price)
else
total += product_price * amount_bought
end
end
end
def create_rows
string=""
@cart.each_key do |key|
product_price,promotion = @in_stock[key]
amount = @cart[key].to_i.to_s
price = (amount.to_i * product_price).to_f.to_s
string += "| %s%s |%s |" % [key.ljust(40),amount.rjust(6),price.rjust(9)] + "\n"
# string += promotion_row(promotion,amount,price)
end
string
end
def invoice
separator = "+" + "-" * 48 + "+" + "-" *10 + "+"
initiation = separator + "\n" + "| %s%s |" % ["Name".ljust(40),"qty".rjust(6)]
initiation += "%s |" % "price".rjust(9) + "\n" + separator + "\n"
ending = separator + "\n" + "| %-47s|%s |" % ["TOTAL",total.to_f.to_s.rjust(9)]
ending += "\n" + separator
return initiation + create_rows + ending
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: "+------------------------------------------------+----------+\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+------------------------------------------------+----------+"
       
       (compared using ==)
       
       Diff:
     # /tmp/d20111115-5847-1j1of55/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: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    3 |      3.0 |\n| Red Tea                                      8 |     16.0 |\n+------------------------------------------------+----------+\n| TOTAL                                          |     16.0 |\n+------------------------------------------------+----------+"
       
       (compared using ==)
       
       Diff:
       
       @@ -1,11 +1,9 @@
        +------------------------------------------------+----------+
        | 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 |      3.0 |
       +| Red Tea                                      8 |     16.0 |
        +------------------------------------------------+----------+
       -| TOTAL                                          |    16.00 |
       +| TOTAL                                          |     16.0 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1j1of55/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: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    4 |      4.0 |\n| Red Tea                                      8 |     16.0 |\n+------------------------------------------------+----------+\n| TOTAL                                          |     17.6 |\n+------------------------------------------------+----------+"
       
       (compared using ==)
       
       Diff:
       
       @@ -1,11 +1,9 @@
        +------------------------------------------------+----------+
        | 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.0 |
       +| Red Tea                                      8 |     16.0 |
        +------------------------------------------------+----------+
       -| TOTAL                                          |    17.60 |
       +| TOTAL                                          |     17.6 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1j1of55/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: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                   12 |     12.0 |\n| Red Tea                                     20 |     40.0 |\n+------------------------------------------------+----------+\n| TOTAL                                          |     49.8 |\n+------------------------------------------------+----------+"
       
       (compared using ==)
       
       Diff:
       
       @@ -1,11 +1,9 @@
        +------------------------------------------------+----------+
        | 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.0 |
       +| Red Tea                                     20 |     40.0 |
        +------------------------------------------------+----------+
       -| TOTAL                                          |    49.80 |
       +| TOTAL                                          |     49.8 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1j1of55/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: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                   10 |     10.0 |\n+------------------------------------------------+----------+\n| TOTAL                                          |      8.0 |\n+------------------------------------------------+----------+"
       
       (compared using ==)
       
       Diff:
       
       @@ -1,9 +1,8 @@
        +------------------------------------------------+----------+
        | Name                                       qty |    price |
        +------------------------------------------------+----------+
       -| Green Tea                                   10 |    10.00 |
       -| Coupon TEA-TIME - 20% off                      |    -2.00 |
       +| Green Tea                                   10 |     10.0 |
        +------------------------------------------------+----------+
       -| TOTAL                                          |     8.00 |
       +| TOTAL                                          |      8.0 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1j1of55/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: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    5 |      5.0 |\n+------------------------------------------------+----------+\n| TOTAL                                          |      0.0 |\n+------------------------------------------------+----------+"
       
       (compared using ==)
       
       Diff:
       
       @@ -1,9 +1,8 @@
        +------------------------------------------------+----------+
        | Name                                       qty |    price |
        +------------------------------------------------+----------+
       -| Green Tea                                    5 |     5.00 |
       -| Coupon TEA-TIME - 10.00 off                    |    -5.00 |
       +| Green Tea                                    5 |      5.0 |
        +------------------------------------------------+----------+
       -| TOTAL                                          |     0.00 |
       +| TOTAL                                          |      0.0 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1j1of55/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: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    8 |    22.32 |\n| Black Coffee                                 5 |    14.95 |\n| Milk                                         5 |     8.95 |\n| Cereal                                       3 |     7.47 |\n+------------------------------------------------+----------+\n| TOTAL                                          |  35.1576 |\n+------------------------------------------------+----------+"
       
       (compared using ==)
       
       Diff:
       
       
       
       
       @@ -2,14 +2,10 @@
        | 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 |
       +| TOTAL                                          |  35.1576 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1j1of55/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.56735 seconds
19 examples, 7 failures

Failed examples:

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

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

Лъчезар обнови решението на 07.11.2011 14:24 (преди над 12 години)

+#!/usr/bin/env ruby
+require 'bigdecimal'
+require 'bigdecimal/util' # добавя String#to_d
+class Promotions
+ @@promotion_list=[:get_one_free ,:package ,:threshold]
+ def initialize(name,value)
+ @name = name
+ @condition = value
+ end
+
+ def exists?
+ @@promotion_list.include?@name
+ end
+
+ def execute(amount,price)
+ return calculate_get_one_free(amount,price) if @name == :get_one_free
+
+ return calculate_package(amount,price) if @name == :package
+
+ return calculate_threshold(amount,price) if @name == :threshold
+
+ end
+
+ private
+
+ def calculate_get_one_free(amount,price)
+ for_promotion=@condition
+ free = (amount / for_promotion).to_i
+ free * price
+ end
+
+ def calculate_package(amount,price)
+
+ @condition.each do |count_needed,discount|
+ no_promotion = amount % count_needed
+ with_promotion = amount - no_promotion
+ return (with_promotion * price) * (discount / 100.00).to_d
+
+ end
+ end
+
+ def calculate_threshold(amount,price)
+ @condition.each do |count_needed,discount|
+ if amount > count_needed
+ with_promotion = amount - count_needed
+ no_promotion = count_needed
+ all = amount * price
+ return (with_promotion * price) * (discount / 100.00).to_d
+ else
+ return 0
+ end
+ end
+ end
+end
+
+class Inventory
+ attr_reader :in_stock
+ attr_reader :coupons
+ def initialize
+ @in_stock = {}
+ @coupons = {}
+ end
+ def register(product,price,promotion=nil)
+ if promotion != nil
+ promotion=Promotions.new(promotion.keys.pop,promotion.values.pop)
+ raise "No such promotion " if !promotion.exists?
+ end
+ if product.bytesize > 40 || price.to_f < 0.01 || price.to_f > 999.99
+ raise "Invalid parameters passed."
+ else
+ @in_stock[product] = [price.to_d,promotion]
+ end
+ end
+
+ def register_coupon(type,discount) #check for negative numbers
+ @coupons[type]=discount
+ end
+
+ def new_cart
+ Cart.new(self)
+ end
+end
+
+class Cart
+ private
+ def initialize(inventory)
+ @cart=Hash.new(0)
+ @in_stock=inventory.in_stock
+ @coupons=inventory.coupons
+ @coupons_queue=[]
+ end
+
+ public
+
+ def total
+ @total = total_no_coupons
+ if @coupons_queue != []
+ @coupons_queue.each do |name|
+ condition = @coupons[name]
+ @total -= coupon_discount(condition)
+ end
+ end
+ return @total
+ end
+
+ def add(product,amount=1)
+ raise "No #{product} in stock" if @in_stock[product] == nil
+ if @cart[product] + amount > 0 && @cart[product] + amount < 100
+ @cart[product] += amount
+ else
+ raise "Bad amount of stock.Amount of product >= 0 or more than 99"
+ end
+ end
+
+ def coupon_exists?(name)
+ @coupons[name] != nil
+ end
+
+ def coupon_discount(promotion)
+ if promotion.keys.fetch(0) == :amount
+ discount = @total - promotion[:amount].to_i
+ return discount > 0 ? promotion[:amount].to_i : @total
+ end
+ if promotion.keys.fetch(0) == :percent
+ return @total * (promotion[:percent] / 100.00).to_d
+ end
+ raise "Invalid Coupon Format."
+ end
+
+ def use(name)
+ raise "No coupon available." if !coupon_exists?(name)
+ @coupons_queue<<name
+ end
+
+ def total_no_coupons
+ @cart.each_key.inject(0) do |total,key|
+ product_price,promotion = @in_stock[key]
+ amount_bought = @cart[key]
+ price = amount_bought * product_price
+ if promotion != nil
+ total += price - promotion.execute(amount_bought,product_price)
+ else
+ total += product_price * amount_bought
+ end
+ end
+ end
+
+ def create_rows
+ string=""
+ @cart.each_key do |key|
+ product_price,promotion = @in_stock[key]
+ amount = @cart[key].to_i.to_s
+ price = (amount.to_i * product_price).to_f.to_s
+ string += "| %s%s |%s |" % [key.ljust(40),amount.rjust(6),price.rjust(9)] + "\n"
+ # string += promotion_row(promotion,amount,price)
+ end
+ string
+ end
+
+ def invoice
+ separator = "+" + "-" * 48 + "+" + "-" *10 + "+"
+ initiation = separator + "\n" + "| %s%s |" % ["Name".ljust(40),"qty".rjust(6)]
+ initiation += "%s |" % "price".rjust(9) + "\n" + separator + "\n"
+ ending = separator + "\n" + "| %-47s|%s |" % ["TOTAL",total.to_f.to_s.rjust(9)]
+ ending += "\n" + separator
+ return initiation + create_rows + ending
+
+ end
+end

2 въпроса:

  • invoice изкарва бележката която се иска от теста, но тестът е минава...
  • Кодът по-долу не работи, на втората итерация string вече е nil, вместо да е присвоил стойност

Код:

@cart.inject("") do |string,(key,value)|
  product_price,promotion = @in_stock[key]
  amount = @cart[key].to_i.to_s
  price = (amount.to_i * product_price).to_f.to_s
  string += ( "| %s%s |%s |" % [key.ljust(40),amount.rjust(7),price.rjust(9)] + "\n" ) # валиден стринг е тестал съм
end
  • Редактирал съм ти коментара; виж му "кода" (във вид на Markdown) тук
  • Ако си присъствал на лекцията в понеделник, си видял решението, което Стефан показа; ако не си, скоро ще качим презентацията и ще можеш да я разгледаш
  • Относно кода, който си показал, не виждам причина да не работи; освен това го тествах (или поне негова разновидност) и не успявам да пресъздам твоята ситуация; сигурен ли си, че string е nil, а не нещо друго?
  • Не ползвай String#to_f, така ползваш Float и обезсмисляш упоребата на BigDecimal
  • @cart[key].to_i.to_s, защо? Във format-стринга може да ползваш %d или еквивалент, вместо %s
  • if ! = unless
  • Не така: return (with_promotion * price) * (discount / 100.00).to_d
  • Така: (with_promotion * price) * (discount / '100.00'.to_d)

Ако на лекцията във вторник остане време, ще кажа още някои неща, които засягат и твоя код.

Ако имаш някакви въпроси, питай свободно.

аз също го тествах ... с твоя код и работи. Сигурен ли си че не си имал нещо повече след inject (има един коментиран ред :)) ако е така се решава със string += @cart.inject ......

а invoice не ти работи защото нямаш нов ред след последния разделител. А за следващите освен че ти липсват промоциите и цените не са ти във формата XXXXX.XX

"%8.2f" % "23.215".to_d