Лъчезар обнови решението на 07.11.2011 14:24 (преди около 13 години)
+#!/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