Решение на Трета задача от Николай Хубанов

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

Към профила на Николай Хубанов

Резултати

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

Код

require 'bigdecimal'
require 'bigdecimal/util' # добавя String#to_d
class GetOneFreePromotion
def initialize(free_number)
@free_number = free_number
end
def discount(products_count, product_price)
affected_products = products_count / @free_number
affected_products * product_price
end
def discount_message
"(buy #{@free_number - 1}, get 1 free)"
end
end
class PackagePromotion
def initialize(package_size, discount_percent)
@package_size = package_size
@discount_percent = discount_percent
end
def discount(products_count, product_price)
affected_products = products_count - products_count % @package_size
affected_products * product_price * @discount_percent / 100.0
end
def discount_message
"(get #{@discount_percent}% off for every #{@package_size})"
end
end
class ThresholdPromotion
def initialize(threshold_size, discount_percent)
@threshold_size = threshold_size
@discount_percent = discount_percent
end
def discount(products_count, product_price)
if products_count <= @threshold_size
return 0.0
end
affected_products = products_count - @threshold_size
affected_products * product_price * @discount_percent / 100.0
end
def discount_message
position = if @threshold_size == 1 then 'st'
elsif @threshold_size == 2 then 'nd'
elsif @threshold_size == 3 then 'rd'
else 'th'
end
"(#{@discount_percent}% off of every after the #{@threshold_size}#{position})"
end
end
class PercentCoupon
def initialize(discount_percent)
@discount_percent = discount_percent
end
def discount(total_cost)
total_cost * @discount_percent / 100.0
end
def discount_message(name)
"Coupon #{name} - #{@discount_percent}% off"
end
end
class AmountCoupon
def initialize(discount_amount)
@discount_amount = discount_amount
end
def discount(total_cost)
if total_cost <= @discount_amount
total_cost
else
@discount_amount
end
end
def discount_message(name)
"Coupon #{name} - #{sprintf("%.2f", @discount_amount)} off"
end
end
class ShoppingCart
def initialize(inventory)
@inventory = inventory
@purchases = Hash.new(0)
@coupon_used = nil
end
def add(product, quantity = 1)
incorrect_product = !@inventory.has_product?(product)
incorrect_quantity = incorrect_quantity? product, quantity
if incorrect_product or incorrect_quantity
raise "Invalid arguments in add in cart"
end
@purchases[product] += quantity
end
def use(name)
if not (@inventory.get_coupon name).nil? and @coupon_used.nil?
@coupon_used = name
else
raise 'Already used coupon!'
end
end
def incorrect_quantity?(name, quantity)
not (1..99).include? @purchases[name] + quantity
end
def invoice
result = "+------------------------------------------------+----------+
| Name qty | price |
+------------------------------------------------+----------+\n"
@purchases.each { |key, value| result += print_purchase_info(key, value) }
if not @coupon_used.nil?
result += print_coupon_info
end
result += "+------------------------------------------------+----------+
| TOTAL | #{sprintf("%8.2f", total)} |
+------------------------------------------------+----------+\n"
result
end
def print_coupon_info
coupon = @inventory.get_coupon @coupon_used
discount = coupon.discount total_without_coupon
result = ""
if discount > 0.0
discount_message = sprintf("%-47s", (coupon.discount_message @coupon_used))
result = "| #{discount_message}| #{sprintf("%8.2f", -discount)} |\n"
end
result
end
def print_purchase_info(product, quantity)
product_string = sprintf("%-42s", product)
quantity_string = sprintf("%3d", quantity)
cost_string = sprintf("%8.2f", quantity * (@inventory.product_price product))
result = "| #{product_string} #{quantity_string} | #{cost_string} |\n"
if not (@inventory.get_promotion product).nil?
result += print_discount_info product, quantity
end
result
end
def print_discount_info(product, quantity)
promotion = @inventory.get_promotion product
discount = promotion.discount quantity, (@inventory.product_price product)
result = ""
if discount > 0
message_string = sprintf("%-44s", promotion.discount_message)
discount_string = sprintf("%8.2f", -discount)
result = "| #{message_string} | #{discount_string} |\n"
end
result
end
def total_without_coupon
result = "0.0".to_d
@purchases.each do |product, quantity|
product_price = @inventory.product_price product
result += quantity * product_price
if not (@inventory.get_promotion product).nil?
result -= (@inventory.get_promotion product).discount quantity, product_price
end
end
result
end
def total
result = total_without_coupon
if not @coupon_used.nil?
coupon = @inventory.get_coupon @coupon_used
discount = coupon.discount total_without_coupon
result -= discount
end
result
end
end
class Inventory
def initialize
@products = {}
@promotions = {}
@coupons = {}
end
def new_cart
ShoppingCart.new self
end
def register(name, price, preferences = {})
incorrect_name = name.size > 40 or @products.has_key? name
incorrect_price = !((price.to_d <= 999.99) and (price.to_d >= 0.01))
if incorrect_name or incorrect_price
raise "Ivalid arguments in register of product in invetory!"
end
@products[name] = price.to_d
register_promotions name, preferences
end
def register_promotions(name, preferences = {})
if preferences.has_key? :get_one_free
@promotions[name] = GetOneFreePromotion.new preferences[:get_one_free]
elsif preferences.has_key? :package
package_size, discount_percent = preferences[:package].flatten
@promotions[name] = PackagePromotion.new package_size, discount_percent
elsif preferences.has_key? :threshold
threshold_size, discount_percent = preferences[:threshold].flatten
@promotions[name] = ThresholdPromotion.new threshold_size, discount_percent
end
end
def register_coupon(name, preferences = {})
if @coupons.has_key? name
raise "Duplicate coupon"
end
if preferences.has_key? :percent
@coupons[name] = PercentCoupon.new preferences[:percent]
elsif preferences.has_key? :amount
@coupons[name] = AmountCoupon.new preferences[:amount].to_d
end
end
def get_coupon(coupon_name)
@coupons[coupon_name]
end
def get_promotion(product_name)
@promotions[product_name]
end
def has_product?(product_name)
@products.has_key? product_name
end
def product_price(product_name)
@products[product_name]
end
end

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

...................

Finished in 0.56692 seconds
19 examples, 0 failures

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

Николай обнови решението на 07.11.2011 02:37 (преди над 12 години)

+require 'bigdecimal'
+require 'bigdecimal/util' # добавя String#to_d
+
+class GetOneFreePromotion
+ def initialize(free_number)
+ @free_number = free_number
+ end
+
+ def discount(products_count, product_price)
+ affected_products = products_count / @free_number
+ affected_products * product_price
+ end
+
+ def discount_message
+ "(buy #{@free_number - 1}, get 1 free)"
+ end
+end
+
+class PackagePromotion
+ def initialize(package_size, discount_percent)
+ @package_size = package_size
+ @discount_percent = discount_percent
+ end
+
+ def discount(products_count, product_price)
+ affected_products = products_count - products_count % @package_size
+ affected_products * product_price * @discount_percent / 100.0
+ end
+
+ def discount_message
+ "(get #{@discount_percent}% off for every #{@package_size})"
+ end
+end
+
+class ThresholdPromotion
+ def initialize(threshold_size, discount_percent)
+ @threshold_size = threshold_size
+ @discount_percent = discount_percent
+ end
+
+ def discount(products_count, product_price)
+ if products_count <= @threshold_size
+ return 0.0
+ end
+
+ affected_products = products_count - @threshold_size
+ affected_products * product_price * @discount_percent / 100.0
+ end
+
+ def discount_message
+ position = if @threshold_size == 1 then 'st'
+ elsif @threshold_size == 2 then 'nd'
+ elsif @threshold_size == 3 then 'rd'
+ else 'th'
+ end
+
+ "(#{@discount_percent}% off of every after the #{@threshold_size}#{position})"
+ end
+end
+
+class PercentCoupon
+ def initialize(discount_percent)
+ @discount_percent = discount_percent
+ end
+
+ def discount(total_cost)
+ total_cost * @discount_percent / 100.0
+ end
+
+ def discount_message(name)
+ "Coupon #{name} - #{@discount_percent}% off"
+ end
+end
+
+class AmountCoupon
+ def initialize(discount_amount)
+ @discount_amount = discount_amount
+ end
+
+ def discount(total_cost)
+ if total_cost <= @discount_amount
+ total_cost
+ else
+ @discount_amount
+ end
+ end
+
+ def discount_message(name)
+ "Coupon #{name} - #{sprintf("%.2f", @discount_amount)} off"
+ end
+end
+
+
+class ShoppingCart
+ def initialize(inventory)
+ @inventory = inventory
+ @purchases = Hash.new(0)
+ @coupon_used = nil
+ end
+
+ def add(product, quantity = 1)
+ incorrect_product = !@inventory.has_product?(product)
+ incorrect_quantity = incorrect_quantity? product, quantity
+ if incorrect_product or incorrect_quantity
+ raise "Invalid arguments in add in cart"
+ end
+
+ @purchases[product] += quantity
+ end
+
+ def use(name)
+ if not (@inventory.get_coupon name).nil? and @coupon_used.nil?
+ @coupon_used = name
+ else
+ raise 'Already used coupon!'
+ end
+ end
+
+ def incorrect_quantity?(name, quantity)
+ not (1..99).include? @purchases[name] + quantity
+ end
+
+ def invoice
+ result = "+------------------------------------------------+----------+
+| Name qty | price |
++------------------------------------------------+----------+\n"
+
+ @purchases.each { |key, value| result += print_purchase_info(key, value) }
+ if not @coupon_used.nil?
+ result += print_coupon_info
+ end
+
+ result += "+------------------------------------------------+----------+
+| TOTAL | #{sprintf("%8.2f", total)} |
++------------------------------------------------+----------+\n"
+
+ result
+ end
+
+ def print_coupon_info
+ coupon = @inventory.get_coupon @coupon_used
+ discount = coupon.discount total_without_coupon
+
+ result = ""
+ if discount > 0.0
+ discount_message = sprintf("%-47s", (coupon.discount_message @coupon_used))
+ result = "| #{discount_message}| #{sprintf("%8.2f", -discount)} |\n"
+ end
+
+ result
+ end
+
+ def print_purchase_info(product, quantity)
+ product_string = sprintf("%-42s", product)
+ quantity_string = sprintf("%3d", quantity)
+ cost_string = sprintf("%8.2f", quantity * (@inventory.product_price product))
+ result = "| #{product_string} #{quantity_string} | #{cost_string} |\n"
+
+ if not (@inventory.get_promotion product).nil?
+ result += print_discount_info product, quantity
+ end
+
+ result
+ end
+
+ def print_discount_info(product, quantity)
+ promotion = @inventory.get_promotion product
+ discount = promotion.discount quantity, (@inventory.product_price product)
+
+ result = ""
+ if discount > 0
+ message_string = sprintf("%-44s", promotion.discount_message)
+ discount_string = sprintf("%8.2f", -discount)
+ result = "| #{message_string} | #{discount_string} |\n"
+ end
+ result
+ end
+
+ def total_without_coupon
+ result = "0.0".to_d
+ @purchases.each do |product, quantity|
+ product_price = @inventory.product_price product
+ result += quantity * product_price
+
+ if not (@inventory.get_promotion product).nil?
+ result -= (@inventory.get_promotion product).discount quantity, product_price
+ end
+ end
+
+ result
+ end
+
+ def total
+ result = total_without_coupon
+ if not @coupon_used.nil?
+ coupon = @inventory.get_coupon @coupon_used
+ discount = coupon.discount total_without_coupon
+ result -= discount
+ end
+
+ result
+ end
+end
+
+class Inventory
+ def initialize
+ @products = {}
+ @promotions = {}
+ @coupons = {}
+ end
+
+ def new_cart
+ ShoppingCart.new self
+ end
+
+ def register(name, price, preferences = {})
+ incorrect_name = name.size > 40 or @products.has_key? name
+ incorrect_price = !((price.to_d <= 999.99) and (price.to_d >= 0.01))
+ if incorrect_name or incorrect_price
+ raise "Ivalid arguments in register of product in invetory!"
+ end
+
+ @products[name] = price.to_d
+ register_promotions name, preferences
+ end
+
+ def register_promotions(name, preferences = {})
+ if preferences.has_key? :get_one_free
+ @promotions[name] = GetOneFreePromotion.new preferences[:get_one_free]
+ elsif preferences.has_key? :package
+ package_size, discount_percent = preferences[:package].flatten
+ @promotions[name] = PackagePromotion.new package_size, discount_percent
+ elsif preferences.has_key? :threshold
+ threshold_size, discount_percent = preferences[:threshold].flatten
+ @promotions[name] = ThresholdPromotion.new threshold_size, discount_percent
+ end
+ end
+
+ def register_coupon(name, preferences = {})
+ if @coupons.has_key? name
+ raise "Duplicate coupon"
+ end
+
+ if preferences.has_key? :percent
+ @coupons[name] = PercentCoupon.new preferences[:percent]
+ elsif preferences.has_key? :amount
+ @coupons[name] = AmountCoupon.new preferences[:amount].to_d
+ end
+ end
+
+ def get_coupon(coupon_name)
+ @coupons[coupon_name]
+ end
+
+ def get_promotion(product_name)
+ @promotions[product_name]
+ end
+
+ def has_product?(product_name)
+ @products.has_key? product_name
+ end
+
+ def product_price(product_name)
+ @products[product_name]
+ end
+end
+