Решение на Трета задача от Иван Арабаджиев

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

Към профила на Иван Арабаджиев

Резултати

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

Код

require 'bigdecimal'
require 'bigdecimal/util'
TableLine = "+".ljust(49,'-') + "+".ljust(11,'-') + "+\n"
MinPrice = BigDecimal.new('0.01')
MaxPrice = BigDecimal.new('999.99')
class Numeric
def ordinal
cardinal = self.to_i.abs
if (10...20).include?(cardinal) then
cardinal.to_s << 'th'
else
cardinal.to_s << %w{th st nd rd th th th th th th}[cardinal % 10]
end
end
end
class NthDiscount
def initialize(needed_for_disctount)
@needed = needed_for_disctount
end
def discount_value(item_price, item_count)
-( (item_count / @needed) * item_price )
end
def to_s
"(buy %1.0f, get 1 free)" % [@needed - 1]
end
end
class PackDiscount
def initialize(pack_description)
pack_description = pack_description.shift
@pack_size = pack_description.first
@percentage = pack_description.last
@discount_factor = @percentage / BigDecimal('100.00')
end
def discount_value(item_price, item_count)
-(item_price * (item_count / @pack_size) * @pack_size * @discount_factor)
end
def to_s
"(get %1.0f%% off for every %1.0f)" % [@percentage,@pack_size]
end
end
class ThresholdDiscount
def initialize(set_threshold)
set_threshold = set_threshold.shift
@threshold = set_threshold.first
@percentage = set_threshold.last
@discount_factor = @percentage / BigDecimal('100.00')
end
def discount_value(item_price, item_count)
return BigDecimal('0.00') unless item_count > @threshold
-((item_count - @threshold) * item_price * @discount_factor)
end
def to_s
"(%1.0f%% off of every after the %s)" % [@percentage, @threshold.ordinal]
end
end
class DummyDiscount
def discount_value(unused_price, unused_count)
0.0
end
end
class FixedCoupon
def initialize(name, amount)
@amount = BigDecimal(amount)
@name = name
end
def apply(original_amount)
@amount < original_amount ? -@amount : -original_amount
end
def to_s
"Coupon %s - %1.2f off" % [@name, @amount]
end
end
class PercentCoupon
def initialize(name, percent)
@percent = percent
@koef = percent / BigDecimal('100.00')
@name = name
end
def apply(original_amount)
-(original_amount * @koef)
end
def to_s
"Coupon %s - %1.0f%% off" % [@name, @percent]
end
end
class CartItem
attr_reader :item, :quantity
def initialize(item)
@item = item
@quantity = 0
end
def total
@item.price * @quantity
end
def add(how_much)
raise 'Don`t get greedy!' unless @quantity + how_much < 100
@quantity += how_much
end
def total_discount
@item.discount.discount_value(@item.price, @quantity)
end
def to_s
lines = "| %-40s%6.0f |%9.2f |\n" % [@item.name, @quantity, total]
discount = total_discount
lines += "| %-45s|%9.2f |\n" % [@item.discount.to_s, discount] unless discount.zero?
lines
end
end
class InventoryItem
attr_reader :name, :price, :discount
def initialize(item_name, item_price, the_discount = {})
@name, @price = item_name, item_price
@discount = if the_discount.has_key? :get_one_free
NthDiscount.new(the_discount[:get_one_free])
elsif the_discount.has_key? :package
PackDiscount.new(the_discount[:package])
elsif the_discount.has_key? :threshold
ThresholdDiscount.new(the_discount[:threshold])
else
DummyDiscount.new
end
end
end
class ItemCart
def initialize(parent)
@inventory = parent
@item_list = {}
@discount = nil
end
def add(item_name, item_quantity = 1)
raise 'Can`t sell that!' unless @inventory.item_registered? item_name
raise 'We don`t do returns!' if item_quantity < 1
unless @item_list.has_key? item_name
@item_list[item_name] = CartItem.new(@inventory.get_item item_name)
end
@item_list[item_name].add item_quantity
end
def total
raw_sum + (@discount.nil? ? BigDecimal('0.00') : @discount.apply(raw_sum))
end
def raw_sum
@item_list.values.inject (BigDecimal('0.00')) do |sum, item|
sum + item.total + item.total_discount
end
end
def invoice
to_return = TableLine
to_return += "| %-40s%6s |%9s |\n" % ['Name', 'qty', 'price'] + TableLine
to_return = @item_list.values.inject(to_return) { |so_far, item| so_far + item.to_s }
to_return += get_coupon_line + TableLine + "| %-47s|%9.2f |\n" % ['TOTAL', total]
to_return += TableLine
end
def get_coupon_line
@discount.nil? ? '' : "| %-47s|%9.2f |\n" % [@discount.to_s, @discount.apply(raw_sum)]
end
def use(coupon_name)
raise 'You`re getting greedy again!' unless @discount.nil?
@discount = @inventory.get_coupon coupon_name
raise 'No such coupon!' if @discount.nil?
end
end
class Inventory
def initialize
@registered_items = {}
@registered_coupons = {}
end
def register(item_name, item_price, discount_type = {})
raise 'Give me a name, not a novell!' if item_name.length > 40
item_price = BigDecimal(item_price)
raise 'I don`t like the price!' if (item_price < MinPrice or item_price > MaxPrice)
raise 'I`ve seen that one already!' if @registered_items.has_key? item_name
@registered_items[item_name] = InventoryItem.new(item_name, item_price, discount_type)
end
def register_coupon(coupon_name, bonus)
raise 'Enough already!' if @registered_coupons.has_key? coupon_name
@registered_coupons[coupon_name] = if bonus.has_key? :percent
PercentCoupon.new(coupon_name, bonus[:percent])
else
FixedCoupon.new(coupon_name, bonus[:amount])
end
end
def item_registered?(item_name)
@registered_items.has_key? item_name
end
def new_cart
ItemCart.new(self)
end
def get_item(item_name)
@registered_items[item_name]
end
def get_coupon(coupon_name)
@registered_coupons[coupon_name]
end
end

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

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

Finished in 0.56861 seconds
19 examples, 0 failures

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

Иван обнови решението на 06.11.2011 00:44 (преди над 12 години)

+require 'bigdecimal'
+require 'bigdecimal/util'
+
+TableLine = "+".ljust(49,'-') + "+".ljust(11,'-') + "+\n"
+MinPrice = BigDecimal.new('0.01')
+MaxPrice = BigDecimal.new('999.99')
+
+class Numeric
+ def ordinal
+ cardinal = self.to_i.abs
+ if (10...20).include?(cardinal) then
+ cardinal.to_s << 'th'
+ else
+ cardinal.to_s << %w{th st nd rd th th th th th th}[cardinal % 10]
+ end
+ end
+end
+
+class NthDiscount
+ def initialize(needed_for_disctount)
+ @needed = needed_for_disctount
+ end
+
+ def discount_value(item_price, item_count)
+ -( (item_count / @needed) * item_price )
+ end
+
+ def to_s
+ "(buy %1.0f, get 1 free)" % [@needed - 1]
+ end
+end
+
+class PackDiscount
+ def initialize(pack_description)
+ pack_description = pack_description.shift
+ @pack_size = pack_description.first
+ @percentage = pack_description.last
+ @discount_factor = @percentage / BigDecimal('100.00')
+ end
+
+ def discount_value(item_price, item_count)
+ -(item_price * (item_count / @pack_size) * @pack_size * @discount_factor)
+ end
+
+ def to_s
+ "(get %1.0f%% off for every %1.0f)" % [@percentage,@pack_size]
+ end
+end
+
+class ThresholdDiscount
+ def initialize(set_threshold)
+ set_threshold = set_threshold.shift
+ @threshold = set_threshold.first
+ @percentage = set_threshold.last
+ @discount_factor = @percentage / BigDecimal('100.00')
+ end
+
+ def discount_value(item_price, item_count)
+ return BigDecimal('0.00') unless item_count > @threshold
+ -((item_count - @threshold) * item_price * @discount_factor)
+ end
+
+ def to_s
+ "(%1.0f%% off of every after the %s)" % [@percentage, @threshold.ordinal]
+ end
+end
+
+class DummyDiscount
+ def discount_value(unused_price, unused_count)
+ 0.0
+ end
+end
+
+class FixedCoupon
+ def initialize(name, amount)
+ @amount = BigDecimal(amount)
+ @name = name
+ end
+
+ def apply(original_amount)
+ @amount < original_amount ? -@amount : -original_amount
+ end
+
+ def to_s
+ "Coupon %s - %1.2f off" % [@name, @amount]
+ end
+end
+
+class PercentCoupon
+ def initialize(name, percent)
+ @percent = percent
+ @koef = percent / BigDecimal('100.00')
+ @name = name
+ end
+
+ def apply(original_amount)
+ -(original_amount * @koef)
+ end
+
+ def to_s
+ "Coupon %s - %1.0f%% off" % [@name, @percent]
+ end
+end
+class CartItem
+ attr_reader :item, :quantity
+ def initialize(item)
+ @item = item
+ @quantity = 0
+ end
+
+ def total
+ @item.price * @quantity
+ end
+
+ def add(how_much)
+ raise 'Don`t get greedy!' unless @quantity + how_much < 100
+ @quantity += how_much
+ end
+
+ def total_discount
+ @item.discount.discount_value(@item.price, @quantity)
+ end
+
+ def to_s
+ lines = "| %-40s%6.0f |%9.2f |\n" % [@item.name, @quantity, total]
+ discount = total_discount
+ lines += "| %-45s|%9.2f |\n" % [@item.discount.to_s, discount] unless discount.zero?
+ lines
+ end
+end
+
+class InventoryItem
+ attr_reader :name, :price, :discount
+
+ def initialize(item_name, item_price, the_discount = {})
+ @name, @price = item_name, item_price
+ @discount = if the_discount.has_key? :get_one_free
+ NthDiscount.new(the_discount[:get_one_free])
+ elsif the_discount.has_key? :package
+ PackDiscount.new(the_discount[:package])
+ elsif the_discount.has_key? :threshold
+ ThresholdDiscount.new(the_discount[:threshold])
+ else
+ DummyDiscount.new
+ end
+ end
+end
+
+class ItemCart
+ def initialize(parent)
+ @inventory = parent
+ @item_list = {}
+ @discount = nil
+ end
+
+ def add(item_name, item_quantity = 1)
+ raise 'Can`t sell that!' unless @inventory.item_registered? item_name
+ raise 'We don`t do returns!' if item_quantity < 1
+ unless @item_list.has_key? item_name
+ @item_list[item_name] = CartItem.new(@inventory.get_item item_name)
+ end
+ @item_list[item_name].add item_quantity
+ end
+
+ def total
+ raw_sum + (@discount.nil? ? BigDecimal('0.00') : @discount.apply(raw_sum))
+ end
+
+ def raw_sum
+ @item_list.values.inject (BigDecimal('0.00')) do |sum, item|
+ sum + item.total + item.total_discount
+ end
+ end
+
+ def invoice
+ to_return = TableLine
+ to_return += "| %-40s%6s |%9s |\n" % ['Name', 'qty', 'price'] + TableLine
+ to_return = @item_list.values.inject(to_return) { |so_far, item| so_far + item.to_s }
+ to_return += get_coupon_line + TableLine + "| %-47s|%9.2f |\n" % ['TOTAL', total]
+ to_return += TableLine
+ end
+
+ def get_coupon_line
+ @discount.nil? ? '' : "| %-47s|%9.2f |\n" % [@discount.to_s, @discount.apply(raw_sum)]
+ end
+
+ def use(coupon_name)
+ raise 'You`re getting greedy again!' unless @discount.nil?
+ @discount = @inventory.get_coupon coupon_name
+ raise 'No such coupon!' if @discount.nil?
+ end
+end
+
+class Inventory
+ def initialize
+ @registered_items = {}
+ @registered_coupons = {}
+ end
+
+ def register(item_name, item_price, discount_type = {})
+ raise 'Give me a name, not a novell!' if item_name.length > 40
+ item_price = BigDecimal(item_price)
+ raise 'I don`t like the price!' if (item_price < MinPrice or item_price > MaxPrice)
+ raise 'I`ve seen that one already!' if @registered_items.has_key? item_name
+ @registered_items[item_name] = InventoryItem.new(item_name, item_price, discount_type)
+ end
+
+ def register_coupon(coupon_name, bonus)
+ raise 'Enough already!' if @registered_coupons.has_key? coupon_name
+ @registered_coupons[coupon_name] = if bonus.has_key? :percent
+ PercentCoupon.new(coupon_name, bonus[:percent])
+ else
+ FixedCoupon.new(coupon_name, bonus[:amount])
+ end
+ end
+
+ def item_registered?(item_name)
+ @registered_items.has_key? item_name
+ end
+
+ def new_cart
+ ItemCart.new(self)
+ end
+
+ def get_item(item_name)
+ @registered_items[item_name]
+ end
+
+ def get_coupon(coupon_name)
+ @registered_coupons[coupon_name]
+ end
+end