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

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

Към профила на Тони Ризов

Резултати

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

Код

require 'bigdecimal'
require 'bigdecimal/util'
class Coupon
attr_reader :name, :kind, :amount
def initialize(name, kind, amount)
@name = name
@kind = kind
@amount = amount
end
def coupon_discount(total)
if kind == :percent
total * (@amount / '100'.to_d)
else
@amount.to_d > total ? total : @amount.to_d
end
end
def invoice_info(total)
discount = coupon_discount(total)
if kind == :amount
info = "| Coupon " + @name + " - " + sprintf("%.2f", @amount.to_d) + " off"
info += " " * (33 - @name.length - sprintf("%.2f", @amount.to_d).length)
else
info = "| Coupon " + @name + " - " + @amount.to_s
info += "% off" + " " * (32 - @name.length - @amount.to_s.length)
end
info += "|" + " " * (5 - discount.floor.to_s.length) + "-"
info + sprintf("%.2f", discount) + " |\n"
end
end
class Product
attr_reader :name, :price, :prom
def initialize(name, price, prom)
@name = name
@price = price
if prom
args = prom.flatten
if args[0] == :get_one_free
@prom = Promotion.new(*args)
else
@prom = Promotion.new(args[0], args[1].flatten)
end
end
end
def multi_price(product_count)
@price * product_count
end
def discount(product_count)
@prom ? @prom.discount(@price, product_count) : "0".to_d
end
def invoice_info(product_count)
info = "| " + @name
info += " " * (46 - @name.length - product_count.to_s.length)
multi = multi_price(product_count)
info += product_count.to_s + " |" + " " * (6 - multi.floor.to_s.length)
info += sprintf("%.2f", multi) + " |\n"
@prom ? info + @prom.invoice_info(@price, product_count) : info
end
end
class Promotion
attr_reader :kind, :spec
def initialize(kind, spec)
@kind = kind
@spec = spec
end
def discount(price, count)
if @kind == :get_one_free
(count / @spec) * price
elsif @kind == :package
((count - count % @spec[0]) * price) * (@spec[1] / '100'.to_d)
else
if count > @spec[0]
((count - @spec[0]) * price) * (@spec[1] / '100'.to_d)
else
"0".to_d
end
end
end
def get_one_free_info(price, count, discount)
info = "| (buy " + (@spec - 1).to_s
info += ", get 1 free)" + " " * (27 - (@spec - 1).to_s.length)
info += "|" + " " * (5 - discount.floor.to_s.length) + "-"
info + sprintf("%.2f", discount) + " |\n"
end
def package_info(price, count, discount)
info = "| (get " + @spec[1].to_s + "% off for every " + @spec[0].to_s
info += ")" + " " * (23 - @spec[1].to_s.length - @spec[0].to_s.length)
info += "|" + " " * (5 - discount.floor.to_s.length) + "-"
info + sprintf("%.2f", discount) + " |\n"
end
def threshold_info(price, count, discount)
info = "| (" + @spec[1].to_s + "% off of every after the "
info += @spec[0].to_s
info += number_suffix(@spec[0] % 10) + ")"
info += " " * (16 - @spec[1].to_s.length - @spec[0].to_s.length)
info += "|" + " " * (5 - discount.floor.to_s.length) + "-"
info + sprintf("%.2f", discount) + " |\n"
end
def number_suffix(digit)
if digit == 1
"st"
elsif digit == 2
"nd"
elsif digit == 3
"rd"
else
"th"
end
end
def invoice_info(price, count)
discount = discount(price, count)
if discount != 0
if @kind == :get_one_free
get_one_free_info(price, count, discount)
elsif @kind == :package
package_info(price, count, discount)
else
threshold_info(price, count, discount)
end
else
""
end
end
end
class Inventory
attr_reader :products, :coupons
def initialize
@products = {}
@coupons = {}
end
def register(product_name, price_string, promotion = nil)
price = price_string.to_d
if @products.include? product_name or
product_name.length > 40 or price < 0.01 or price > 999.99
raise "Invalid product name/price - " + product_name + "/" + price_string + "."
end
@products[product_name] = Product.new(product_name, price, promotion)
end
def register_coupon(name, kind)
if @coupons.include? name
raise "Existing coupon - " + name + "."
end
@coupons[name] = Coupon.new(name, *kind.flatten)
end
def new_cart
Cart.new(self)
end
end
class Cart
def initialize(inventory)
@inventory = inventory
@purchased = Hash.new(0)
end
def add(product_name, qty = 1)
if not @inventory.products.include? product_name or
@purchased[product_name] + qty < 1 or @purchased[product_name] + qty > 99
raise "Invalid product (" + product_name + ") count - "
+ (product_name[product_name] + qty).to_s + "."
end
@purchased[product_name] += qty
end
def total_no_coupon
no_coupon = "0".to_d
@purchased.each do |product_name, qty|
multi_price = @inventory.products[product_name].multi_price(qty)
discount = @inventory.products[product_name].discount(qty)
no_coupon += multi_price - discount
end
no_coupon
end
def total
total_price = total_no_coupon
total_price -= @used_coupon.coupon_discount(total_price) if @used_coupon
total_price < 0 ? "0".to_d : total_price
end
def use(coupon_name)
if not @inventory.coupons.include? coupon_name or @used_coupon
raise "Invalid coupon - " + coupon_name + "."
end
@used_coupon = @inventory.coupons[coupon_name]
end
def invoice_header
header = "+" + "-" * 48 + "+----------+\n"
header += "| Name" + " " * 39 + "qty | price |\n"
header + "+" + "-" * 48 + "+----------+\n"
end
def invoice_footer(final_price)
footer = "+" + "-" * 48 + "+----------+\n"
footer += "| TOTAL" + " " * 42 + "|"
footer += " " * (6 - final_price.floor.to_s.length)
footer += sprintf("%.2f", final_price) + " |\n"
footer + "+" + "-" * 48 + "+----------+\n"
end
def invoice
invoice = invoice_header
@purchased.each do |product_name, qty|
invoice += @inventory.products[product_name].invoice_info(qty)
end
final_price = total_no_coupon
if @used_coupon
invoice += @used_coupon.invoice_info final_price
final_price -= @used_coupon.coupon_discount final_price
end
invoice += invoice_footer(final_price < 0 ? "0".to_d : final_price)
end
end

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

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

Finished in 0.56518 seconds
19 examples, 0 failures

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

Тони обнови решението на 04.11.2011 00:11 (преди над 12 години)

+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class Coupon
+ attr_reader :name, :kind, :amount
+
+ def initialize(name, kind, amount)
+ @name = name
+ @kind = kind
+ @amount = amount
+ end
+
+ def coupon_discount(total)
+ if kind == :percent
+ total * (@amount / '100'.to_d)
+ else
+ @amount.to_d > total ? total : @amount.to_d
+ end
+ end
+
+ def invoice_info(total)
+ discount = coupon_discount(total)
+ if kind == :amount
+ info = "| Coupon " + @name + " - " + sprintf("%.2f", @amount.to_d) + " off"
+ info += " " * (33 - @name.length - sprintf("%.2f", @amount.to_d).length)
+ else
+ info = "| Coupon " + @name + " - " + @amount.to_s
+ info += "% off" + " " * (32 - @name.length - @amount.to_s.length)
+ end
+ info += "|" + " " * (5 - discount.floor.to_s.length) + "-"
+ info + sprintf("%.2f", discount) + " |\n"
+ end
+end
+
+class Product
+ attr_reader :name, :price, :prom
+
+ def initialize(name, price, prom)
+ @name = name
+ @price = price
+ if prom
+ args = prom.flatten
+ if args[0] == :get_one_free
+ @prom = Promotion.new(*args)
+ else
+ @prom = Promotion.new(args[0], args[1].flatten)
+ end
+ end
+ end
+
+ def multi_price(product_count)
+ @price * product_count
+ end
+
+ def discount(product_count)
+ @prom ? @prom.discount(@price, product_count) : "0".to_d
+ end
+
+ def invoice_info(product_count)
+ info = "| " + @name
+ info += " " * (46 - @name.length - product_count.to_s.length)
+ multi = multi_price(product_count)
+ info += product_count.to_s + " |" + " " * (6 - multi.floor.to_s.length)
+ info += sprintf("%.2f", multi) + " |\n"
+ @prom ? info + @prom.invoice_info(@price, product_count) : info
+ end
+end
+
+class Promotion
+ attr_reader :kind, :spec
+
+ def initialize(kind, spec)
+ @kind = kind
+ @spec = spec
+ end
+
+ def discount(price, count)
+ if @kind == :get_one_free
+ (count / @spec) * price
+ elsif @kind == :package
+ ((count - count % @spec[0]) * price) * (@spec[1] / '100'.to_d)
+ else
+ if count > @spec[0]
+ ((count - @spec[0]) * price) * (@spec[1] / '100'.to_d)
+ else
+ "0".to_d
+ end
+ end
+ end
+
+ def get_one_free_info(price, count, discount)
+ info = "| (buy " + (@spec - 1).to_s
+ info += ", get 1 free)" + " " * (27 - (@spec - 1).to_s.length)
+ info += "|" + " " * (5 - discount.floor.to_s.length) + "-"
+ info + sprintf("%.2f", discount) + " |\n"
+ end
+
+ def package_info(price, count, discount)
+ info = "| (get " + @spec[1].to_s + "% off for every " + @spec[0].to_s
+ info += ")" + " " * (23 - @spec[1].to_s.length - @spec[0].to_s.length)
+ info += "|" + " " * (5 - discount.floor.to_s.length) + "-"
+ info + sprintf("%.2f", discount) + " |\n"
+ end
+
+ def threshold_info(price, count, discount)
+ info = "| (" + @spec[1].to_s + "% off of every after the "
+ info += @spec[0].to_s
+ info += number_suffix(@spec[0] % 10) + ")"
+ info += " " * (16 - @spec[1].to_s.length - @spec[0].to_s.length)
+ info += "|" + " " * (5 - discount.floor.to_s.length) + "-"
+ info + sprintf("%.2f", discount) + " |\n"
+ end
+
+ def number_suffix(digit)
+ if digit == 1
+ "st"
+ elsif digit == 2
+ "nd"
+ elsif digit == 3
+ "rd"
+ else
+ "th"
+ end
+ end
+
+ def invoice_info(price, count)
+ discount = discount(price, count)
+ if discount != 0
+ if @kind == :get_one_free
+ get_one_free_info(price, count, discount)
+ elsif @kind == :package
+ package_info(price, count, discount)
+ else
+ threshold_info(price, count, discount)
+ end
+ else
+ ""
+ end
+ end
+end
+
+class Inventory
+ attr_reader :products, :coupons
+
+ def initialize
+ @products = {}
+ @coupons = {}
+ end
+
+ def register(product_name, price_string, promotion = nil)
+ price = price_string.to_d
+ if @products.include? product_name or
+ product_name.length > 40 or price < 0.01 or price > 999.99
+ raise "Invalid product name/price - " + product_name + "/" + price_string + "."
+ end
+ @products[product_name] = Product.new(product_name, price, promotion)
+ end
+
+ def register_coupon(name, kind)
+ if @coupons.include? name
+ raise "Existing coupon - " + name + "."
+ end
+ @coupons[name] = Coupon.new(name, *kind.flatten)
+ end
+
+ def new_cart
+ Cart.new(self)
+ end
+end
+
+class Cart
+ def initialize(inventory)
+ @inventory = inventory
+ @purchased = Hash.new(0)
+ end
+
+ def add(product_name, qty = 1)
+ if not @inventory.products.include? product_name or
+ @purchased[product_name] + qty < 1 or @purchased[product_name] + qty > 99
+ raise "Invalid product (" + product_name + ") count - "
+ + (product_name[product_name] + qty).to_s + "."
+ end
+ @purchased[product_name] += qty
+ end
+
+ def total_no_coupon
+ no_coupon = "0".to_d
+ @purchased.each do |product_name, qty|
+ multi_price = @inventory.products[product_name].multi_price(qty)
+ discount = @inventory.products[product_name].discount(qty)
+ no_coupon += multi_price - discount
+ end
+ no_coupon
+ end
+
+ def total
+ total_price = total_no_coupon
+ total_price -= @used_coupon.coupon_discount(total_price) if @used_coupon
+ total_price < 0 ? "0".to_d : total_price
+ end
+
+ def use(coupon_name)
+ if not @inventory.coupons.include? coupon_name or @used_coupon
+ raise "Invalid coupon - " + coupon_name + "."
+ end
+ @used_coupon = @inventory.coupons[coupon_name]
+ end
+
+ def invoice_header
+ header = "+" + "-" * 48 + "+----------+\n"
+ header += "| Name" + " " * 39 + "qty | price |\n"
+ header + "+" + "-" * 48 + "+----------+\n"
+ end
+
+ def invoice_footer(final_price)
+ footer = "+" + "-" * 48 + "+----------+\n"
+ footer += "| TOTAL" + " " * 42 + "|"
+ footer += " " * (6 - final_price.floor.to_s.length)
+ footer += sprintf("%.2f", final_price) + " |\n"
+ footer + "+" + "-" * 48 + "+----------+\n"
+ end
+
+ def invoice
+ invoice = invoice_header
+ @purchased.each do |product_name, qty|
+ invoice += @inventory.products[product_name].invoice_info(qty)
+ end
+ final_price = total_no_coupon
+ if @used_coupon
+ invoice += @used_coupon.invoice_info final_price
+ final_price -= @used_coupon.coupon_discount final_price
+ end
+ invoice += invoice_footer(final_price < 0 ? "0".to_d : final_price)
+ end
+end