Решение на Трета задача от Деница Генчева

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

Към профила на Деница Генчева

Резултати

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

Код

require 'bigdecimal'
require 'bigdecimal/util'
class Product
attr_accessor :name, :price, :promotion
def initialize(name, price, promotion_hash = {})
@name = name
@price = price
if promotion_hash.has_key?(:get_one_free)
@promotion = OneProductFreePromotion.new(promotion_hash[:get_one_free])
end
if promotion_hash.has_key?(:package)
@promotion = PackagePromotion.new(promotion_hash[:package])
end
if promotion_hash.has_key?(:threshold)
@promotion = ThresholdPromotion.new(promotion_hash[:threshold])
end
end
def get_price_before_promotions(quantity)
@price * quantity
end
def get_price(quantity)
result = @price * quantity
result = result - @promotion.get_discount(self, quantity) if @promotion
result
end
end
class OneProductFreePromotion
attr_accessor :free_product_index
def initialize(free_product_index)
@free_product_index = free_product_index
end
def get_discount(product, quantity)
(quantity / @free_product_index) * product.price
end
end
class PackagePromotion
attr_accessor :package_size, :discount
def initialize(promotion_info)
@package_size = promotion_info.keys[0]
@discount = promotion_info[@package_size]
end
def get_discount(product, quantity)
products_with_discount = quantity - (quantity % @package_size)
products_with_discount * product.price * @discount / 100
end
end
class ThresholdPromotion
attr_accessor :threshold, :discount
def initialize(promotion_info)
@threshold = promotion_info.keys[0]
@discount = promotion_info[@threshold]
end
def get_discount(product, quantity)
if quantity < @threshold
return BigDecimal.new("0")
end
products_with_discount = quantity - @threshold
products_with_discount * product.price * @discount / 100
end
end
class Inventory
attr_accessor :products, :coupons
def initialize
@products = {}
@coupons = {}
end
def register(name, price, promotion = {})
if name.length > 40
raise "Invalid parameters passed."
end
product_price = BigDecimal(price)
if product_price < 0.01 or product_price > 999.99
raise "Invalid parameters passed."
end
product = Product.new(name, product_price, promotion)
@products[name] = product
end
def register_coupon(name, coupon_info)
if coupon_info.has_key?(:percent)
coupon = PercentCoupon.new(coupon_info[:percent])
end
if coupon_info.has_key?(:amount)
coupon = AmountCoupon.new(coupon_info[:amount])
end
coupons[name] = coupon
end
def get_product(name)
@products[name]
end
def new_cart
Cart.new(self)
end
end
class PercentCoupon
attr_accessor :percent
def initialize(percent)
@percent = percent
end
def get_discount(cart_total)
cart_total * @percent / 100
end
end
class AmountCoupon
attr_accessor :amount
def initialize(amount)
@amount = BigDecimal.new(amount)
end
def get_discount(cart_total)
if cart_total < @amount
return cart_total
end
@amount
end
end
class Cart
attr_accessor :inventory, :quantities, :coupon_name
def initialize(inventory)
@inventory = inventory
@quantities = {}
end
def add(product_name, quantity = 1)
if quantity < 1
raise "Invalid parameters passed."
end
if not @inventory.get_product(product_name)
raise "Trying to add in the cart a product that doesn't exist!"
end
new_quantity = @quantities.fetch(product_name, 0) + quantity
if new_quantity > 99
raise "Quantity should not exceed 99"
end
@quantities[product_name] = new_quantity
end
def products_sum
result = @quantities.inject(BigDecimal.new("0")) do |sum, pair|
product = @inventory.get_product(pair[0])
sum + product.get_price(pair[1])
end
end
def total
result = products_sum()
if @coupon_name
result = result - coupon.get_discount(result)
end
result
end
def invoice
InvoiceWriter.new.invoice(self)
end
def use(coupon_name)
if not inventory.coupons.has_key?(coupon_name)
raise "Trying to use a coupon that doesn't exist"
end
@coupon_name = coupon_name
end
def coupon()
inventory.coupons[@coupon_name]
end
end
class InvoiceWriter
DelimiterLine = "+------------------------------------------------+----------+\n"
TableHeadersLine = "| Name qty | price |\n"
ProductLine = "| %s %s | %s |\n"
PromotionLine = "| %s| %s |\n"
CouponDescription = "Coupon %s - %s off"
CouponLine = "| %s | %s |\n"
TotalLine = "| TOTAL | %s |\n"
Suffixes = Hash.new("th").merge({1 => "st", 2 => "nd", 3 => "rd"})
def invoice(cart)
result = DelimiterLine + TableHeadersLine + DelimiterLine
cart.quantities.each do |product_name, quantity|
product = cart.inventory.get_product(product_name)
result << get_product_line(product, quantity)
result << get_promotion_line(product, quantity) if product.promotion
end
result << get_coupon_line(cart) if cart.coupon
result << get_total_section(cart)
end
def get_product_line(product, quantity)
formatted_name = product.name.ljust(42)
formatted_quantity = quantity.to_s.rjust(3)
price = product.price * quantity
formatted_price = format_price(price)
ProductLine % [formatted_name, formatted_quantity, formatted_price]
end
def get_promotion_line(product, quantity)
promotion = product.promotion
formatted_name = get_promotion_text(promotion).ljust(45)
price = -promotion.get_discount(product, quantity)
formatted_price = format_price(price)
PromotionLine % [formatted_name, formatted_price]
end
def get_promotion_text(promotion)
if promotion.kind_of?(OneProductFreePromotion)
return "(buy %s, get 1 free)" % (promotion.free_product_index - 1)
end
if promotion.kind_of?(PackagePromotion)
return "(get %s off for every %d)" %
[promotion.discount.to_s + "%", promotion.package_size]
end
if promotion.kind_of?(ThresholdPromotion)
return "(%s off of every after the %s)" %
[promotion.discount.to_s + "%", get_formatted_threshold(promotion.threshold)]
end
end
def get_formatted_threshold(threshold)
threshold.to_s + Suffixes[threshold]
end
def get_coupon_line(cart)
formatted_name = get_coupon_text(cart.coupon_name, cart.coupon).ljust(46)
price = -cart.coupon.get_discount(cart.products_sum)
formatted_price = format_price(price)
CouponLine % [formatted_name, formatted_price]
end
def get_coupon_text(coupon_name, coupon)
if coupon.kind_of?(PercentCoupon)
return CouponDescription % [coupon_name, coupon.percent.to_s + "%"]
end
if coupon.kind_of?(AmountCoupon)
return CouponDescription % [coupon_name, "%.2f" % coupon.amount]
end
end
def get_total_section(cart)
result = ""
result << DelimiterLine
result << TotalLine % format_price(cart.total)
result << DelimiterLine
end
def format_price(price)
("%5.2f" % (price.to_f.round(2))).rjust(8)
end
end

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

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

Finished in 0.56527 seconds
19 examples, 0 failures

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

Деница обнови решението на 07.11.2011 02:55 (преди над 12 години)

+
+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class Product
+ attr_accessor :name, :price, :promotion
+
+ def initialize(name, price, promotion_hash = {})
+ @name = name
+ @price = price
+
+ if promotion_hash.has_key?(:get_one_free)
+ @promotion = OneProductFreePromotion.new(promotion_hash[:get_one_free])
+ end
+
+ if promotion_hash.has_key?(:package)
+ @promotion = PackagePromotion.new(promotion_hash[:package])
+ end
+
+ if promotion_hash.has_key?(:threshold)
+ @promotion = ThresholdPromotion.new(promotion_hash[:threshold])
+ end
+ end
+
+ def get_price_before_promotions(quantity)
+ @price * quantity
+ end
+
+ def get_price(quantity)
+ result = @price * quantity
+ result = result - @promotion.get_discount(self, quantity) if @promotion
+ result
+ end
+end
+
+class OneProductFreePromotion
+ attr_accessor :free_product_index
+
+ def initialize(free_product_index)
+ @free_product_index = free_product_index
+ end
+
+ def get_discount(product, quantity)
+ (quantity / @free_product_index) * product.price
+ end
+end
+
+class PackagePromotion
+ attr_accessor :package_size, :discount
+
+ def initialize(promotion_info)
+ @package_size = promotion_info.keys[0]
+ @discount = promotion_info[@package_size]
+ end
+
+ def get_discount(product, quantity)
+ products_with_discount = quantity - (quantity % @package_size)
+ products_with_discount * product.price * @discount / 100
+ end
+end
+
+class ThresholdPromotion
+ attr_accessor :threshold, :discount
+
+ def initialize(promotion_info)
+ @threshold = promotion_info.keys[0]
+ @discount = promotion_info[@threshold]
+ end
+
+ def get_discount(product, quantity)
+ if quantity < @threshold
+ return BigDecimal.new("0")
+ end
+
+ products_with_discount = quantity - @threshold
+ products_with_discount * product.price * @discount / 100
+ end
+end
+
+class Inventory
+ attr_accessor :products, :coupons
+
+ def initialize
+ @products = {}
+ @coupons = {}
+ end
+
+ def register(name, price, promotion = {})
+ if name.length > 40
+ raise "Invalid parameters passed."
+ end
+
+ product_price = BigDecimal(price)
+ if product_price < 0.01 or product_price > 999.99
+ raise "Invalid parameters passed."
+ end
+
+ product = Product.new(name, product_price, promotion)
+ @products[name] = product
+ end
+
+ def register_coupon(name, coupon_info)
+ if coupon_info.has_key?(:percent)
+ coupon = PercentCoupon.new(coupon_info[:percent])
+ end
+
+ if coupon_info.has_key?(:amount)
+ coupon = AmountCoupon.new(coupon_info[:amount])
+ end
+
+ coupons[name] = coupon
+ end
+
+ def get_product(name)
+ @products[name]
+ end
+
+ def new_cart
+ Cart.new(self)
+ end
+
+end
+
+class PercentCoupon
+ attr_accessor :percent
+
+ def initialize(percent)
+ @percent = percent
+ end
+
+ def get_discount(cart_total)
+ cart_total * @percent / 100
+ end
+end
+
+class AmountCoupon
+ attr_accessor :amount
+
+ def initialize(amount)
+ @amount = BigDecimal.new(amount)
+ end
+
+ def get_discount(cart_total)
+ if cart_total < @amount
+ return cart_total
+ end
+
+ @amount
+ end
+end
+
+class Cart
+ attr_accessor :inventory, :quantities, :coupon_name
+
+ def initialize(inventory)
+ @inventory = inventory
+ @quantities = {}
+ end
+
+ def add(product_name, quantity = 1)
+ if quantity < 1
+ raise "Invalid parameters passed."
+ end
+
+ if not @inventory.get_product(product_name)
+ raise "Trying to add in the cart a product that doesn't exist!"
+ end
+
+ new_quantity = @quantities.fetch(product_name, 0) + quantity
+ if new_quantity > 99
+ raise "Quantity should not exceed 99"
+ end
+
+ @quantities[product_name] = new_quantity
+ end
+
+ def products_sum
+ result = @quantities.inject(BigDecimal.new("0")) do |sum, pair|
+ product = @inventory.get_product(pair[0])
+ sum + product.get_price(pair[1])
+ end
+ end
+
+ def total
+ result = products_sum()
+
+ if @coupon_name
+ result = result - coupon.get_discount(result)
+ end
+
+ result
+ end
+
+ def invoice
+ InvoiceWriter.new.invoice(self)
+ end
+
+ def use(coupon_name)
+ if not inventory.coupons.has_key?(coupon_name)
+ raise "Trying to use a coupon that doesn't exist"
+ end
+
+ @coupon_name = coupon_name
+ end
+
+ def coupon()
+ inventory.coupons[@coupon_name]
+ end
+
+end
+
+class InvoiceWriter
+
+ DelimiterLine = "+------------------------------------------------+----------+\n"
+ TableHeadersLine = "| Name qty | price |\n"
+ ProductLine = "| %s %s | %s |\n"
+ PromotionLine = "| %s| %s |\n"
+ CouponDescription = "Coupon %s - %s off"
+ CouponLine = "| %s | %s |\n"
+ TotalLine = "| TOTAL | %s |\n"
+
+ Suffixes = Hash.new("th").merge({1 => "st", 2 => "nd", 3 => "rd"})
+
+ def invoice(cart)
+ result = DelimiterLine + TableHeadersLine + DelimiterLine
+
+ cart.quantities.each do |product_name, quantity|
+ product = cart.inventory.get_product(product_name)
+ result << get_product_line(product, quantity)
+ result << get_promotion_line(product, quantity) if product.promotion
+ end
+
+ result << get_coupon_line(cart) if cart.coupon
+ result << get_total_section(cart)
+ end
+
+ def get_product_line(product, quantity)
+ formatted_name = product.name.ljust(42)
+ formatted_quantity = quantity.to_s.rjust(3)
+ price = product.price * quantity
+ formatted_price = format_price(price)
+
+ ProductLine % [formatted_name, formatted_quantity, formatted_price]
+ end
+
+ def get_promotion_line(product, quantity)
+ promotion = product.promotion
+ formatted_name = get_promotion_text(promotion).ljust(45)
+ price = -promotion.get_discount(product, quantity)
+ formatted_price = format_price(price)
+ PromotionLine % [formatted_name, formatted_price]
+ end
+
+ def get_promotion_text(promotion)
+ if promotion.kind_of?(OneProductFreePromotion)
+ return "(buy %s, get 1 free)" % (promotion.free_product_index - 1)
+ end
+
+ if promotion.kind_of?(PackagePromotion)
+ return "(get %s off for every %d)" %
+ [promotion.discount.to_s + "%", promotion.package_size]
+ end
+
+ if promotion.kind_of?(ThresholdPromotion)
+ return "(%s off of every after the %s)" %
+ [promotion.discount.to_s + "%", get_formatted_threshold(promotion.threshold)]
+ end
+ end
+
+ def get_formatted_threshold(threshold)
+ threshold.to_s + Suffixes[threshold]
+ end
+
+ def get_coupon_line(cart)
+ formatted_name = get_coupon_text(cart.coupon_name, cart.coupon).ljust(46)
+ price = -cart.coupon.get_discount(cart.products_sum)
+ formatted_price = format_price(price)
+ CouponLine % [formatted_name, formatted_price]
+ end
+
+ def get_coupon_text(coupon_name, coupon)
+ if coupon.kind_of?(PercentCoupon)
+ return CouponDescription % [coupon_name, coupon.percent.to_s + "%"]
+ end
+ if coupon.kind_of?(AmountCoupon)
+ return CouponDescription % [coupon_name, "%.2f" % coupon.amount]
+ end
+ end
+
+ def get_total_section(cart)
+ result = ""
+ result << DelimiterLine
+ result << TotalLine % format_price(cart.total)
+ result << DelimiterLine
+ end
+
+ def format_price(price)
+ ("%5.2f" % (price.to_f.round(2))).rjust(8)
+ end
+end