Решение на Трета задача от Васил Гочев

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

Към профила на Васил Гочев

Резултати

  • 3 точки от тестове
  • 0 бонус точки
  • 3 точки общо
  • 11 успешни тест(а)
  • 8 неуспешни тест(а)

Код

require 'bigdecimal'
require 'bigdecimal/util'
module Ordinalize
def ordinalize(number)
if (11..13).include?(number % 100)
"#{number}th"
else
case number % 10
when 1 then "#{number}st"
when 2 then "#{number}nd"
when 3 then "#{number}rd"
else "#{number}th"
end
end
end
end
class Promotion
attr_accessor :promotion, :name, :value, :action
include Ordinalize
def initialize(promotion)
name = promotion.keys.first
details = promotion.values.first
case name
when :get_one_free then get_one_free(details)
when :package then package(details)
when :threshold then threshold(details)
when nil then no_promotion
else raise "No such promotion!"
end
end
def get_one_free(details)
value = details
@name = "(buy #{value - 1}, get 1 free)"
@action = lambda { |quantity| quantity / value }
end
def package(details)
percentage = details.values.first
value = details.keys.first
discount = percentage.to_f / 100
@name = "(get #{percentage}% off for every #{value})"
@action = lambda { |qty| ((qty / value).to_int * value) * discount }
end
def threshold(details)
percentage = details.values.first
value = details.keys.first
discount = percentage.to_f / 100
@name = "(#{percentage}% off of every after the #{ordinalize(value)}) "
@action = lambda { |qty| ((qty - value) * discount) }
end
def no_promotion
@name = nil
@value = nil
end
end
class Product
attr_accessor :name, :price, :promotion
def initialize(name, price, promotion)
if valid_product?(name, price)
@name = name
@price = price.to_d
@promotion = Promotion.new(promotion)
else
raise "Invalid product name or price"
end
end
def valid_product?(name, price)
valid_name?(name) and valid_price?(price)
end
def valid_name?(name)
name.length <= 40
end
def valid_price?(price)
price.to_d >= 0.01 and price.to_d <= 999.99
end
end
class Coupon
attr_accessor :name, :value
def initialize(name, value)
@name = name
case value.keys.first
when 'percent' then coupon_percent(value)
when 'amount' then coupon_amount(value)
else raise "No such coupon!"
end
end
def coupon_percent(value)
end
def coupon_amount(value)
end
end
class Inventory
attr_accessor :products
def initialize
@products = []
end
def register(name, price, promotion = {})
product = Product.new(name, price, promotion)
check_product(product)
end
def check_product(product)
if valid_product?(product)
@products << product
else
raise "There's already a product with the name '#{product.name}'."
end
end
def valid_product?(in_product)
@products.select { |product| product.name == in_product.name }.length == 0
end
def new_cart
cart = Cart.new(@products)
end
def register_coupon(name, value)
@coupon = Coupon.new(name, value)
end
end
class Cart
attr_accessor :cart, :inventory, :total
def initialize(inv)
@cart = {}
@inventory = inv.map { |product| [product.name, product.price, product.promotion] }
@total = 0
end
def add(name, quantity=1)
unless valid_name? name and valid_quantity? quantity
raise "Invalid parameters passed."
end
promotion, price, promotion_action = *get_price_n_promotion(name)
if name_exists? name
quantity = @cart[name].last + quantity
end
@cart[name] = [price, quantity]
if promotion and promotion_action.call(quantity) != 0
@cart[promotion] = [price * (-1), promotion_action.call(quantity)]
end
end
def get_price_n_promotion(product_name)
product = @inventory.select { |product| product.first == product_name }
[product.last.last.name, product.last[1], product.last.last.action]
end
def name_exists?(name)
@cart.include? name
end
def valid_quantity?(quantity)
quantity > 0 and
quantity <= 99 and
quantity.integer?
end
def valid_name?(name)
@inventory.flatten.include? name
end
def total
@total = []
@cart.each do |key, value|
@total << (value.first * value.last)
end
@total.inject(0) { |element, another_element| element + another_element }
end
def invoice
invoice = Invoice.new(@cart, total)
invoice.string
end
def use
end
end
class Invoice
attr_accessor :line, :columns, :products, :total, :string
def initialize(cart, total)
@string = generate_string(cart, total)
end
def generate_string(cart, total)
line +
columns +
line +
products(cart) +
line +
format_total(total) +
line
end
def line
@line = '+' + ('-' * 48) + '+' + ('-' * 10) + '+' + "\n"
end
def columns
@columns = "| %-37s %8s | %8s |\n" % ["Name", "qty", "price"]
end
def products(cart)
string = ""
cart.each do |key, value|
name, qty, price = key, value.last, value.last * value.first
if is_promotion? price
string += "| %-44s | %8.2f |\n" % ["#{name}", "#{price}"]
else
string += "| %-37s %8.0d | %8.2f |\n" % ["#{name}", "#{qty}", "#{price}"]
end
end
string
end
def is_promotion?(price)
price < 0
end
def format_total(total)
@total = "|%-47s | %8.2f |\n" % [" TOTAL", total.to_f]
end
end

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

..........F.FFFFFFF

Failures:

  1) Inventory with a '% off of every item after the nth' promotion does not give a discount if there are no more than n items in the cart
     Failure/Error: cart.total.should eq '8.00'.to_d
       
       expected: #<BigDecimal:9f07c70,'0.8E1',4(8)>
            got: 8.4
       
       (compared using ==)
     # /tmp/d20111115-5847-1yy9iq9/spec.rb:181:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) Inventory with a '% off' coupon gives % off of the total
     Failure/Error: inventory.register_coupon 'TEATIME', percent: 20
     RuntimeError:
       No such coupon!
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:101:in `initialize'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `new'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `register_coupon'
     # /tmp/d20111115-5847-1yy9iq9/spec.rb:215:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) Inventory with a '% off' coupon applies the coupon discount after product promotions
     Failure/Error: inventory.register_coupon 'TEATIME', percent: 10
     RuntimeError:
       No such coupon!
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:101:in `initialize'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `new'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `register_coupon'
     # /tmp/d20111115-5847-1yy9iq9/spec.rb:225:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  4) Inventory with a '% off' coupon shows the discount in the invoice
     Failure/Error: inventory.register_coupon 'TEA-TIME', percent: 20
     RuntimeError:
       No such coupon!
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:101:in `initialize'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `new'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `register_coupon'
     # /tmp/d20111115-5847-1yy9iq9/spec.rb:235:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  5) Inventory with an 'amount off' coupon subtracts the amount form the total
     Failure/Error: inventory.register_coupon 'TEATIME', amount: '10.00'.to_d
     RuntimeError:
       No such coupon!
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:101:in `initialize'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `new'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `register_coupon'
     # /tmp/d20111115-5847-1yy9iq9/spec.rb:256:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  6) Inventory with an 'amount off' coupon does not result in a negative total
     Failure/Error: inventory.register_coupon 'TEATIME', amount: '10.00'.to_d
     RuntimeError:
       No such coupon!
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:101:in `initialize'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `new'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `register_coupon'
     # /tmp/d20111115-5847-1yy9iq9/spec.rb:266:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  7) Inventory with an 'amount off' coupon shows the discount in the invoice
     Failure/Error: inventory.register_coupon 'TEA-TIME', amount: '10.00'.to_d
     RuntimeError:
       No such coupon!
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:101:in `initialize'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `new'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `register_coupon'
     # /tmp/d20111115-5847-1yy9iq9/spec.rb:276:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  8) Inventory with multiple discounts can print an invoice
     Failure/Error: inventory.register_coupon 'BREAKFAST', percent: 10
     RuntimeError:
       No such coupon!
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:101:in `initialize'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `new'
     # /tmp/d20111115-5847-1yy9iq9/solution.rb:144:in `register_coupon'
     # /tmp/d20111115-5847-1yy9iq9/spec.rb:301:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.56277 seconds
19 examples, 8 failures

Failed examples:

rspec /tmp/d20111115-5847-1yy9iq9/spec.rb:177 # Inventory with a '% off of every item after the nth' promotion does not give a discount if there are no more than n items in the cart
rspec /tmp/d20111115-5847-1yy9iq9/spec.rb:213 # Inventory with a '% off' coupon gives % off of the total
rspec /tmp/d20111115-5847-1yy9iq9/spec.rb:223 # Inventory with a '% off' coupon applies the coupon discount after product promotions
rspec /tmp/d20111115-5847-1yy9iq9/spec.rb:233 # Inventory with a '% off' coupon shows the discount in the invoice
rspec /tmp/d20111115-5847-1yy9iq9/spec.rb:254 # Inventory with an 'amount off' coupon subtracts the amount form the total
rspec /tmp/d20111115-5847-1yy9iq9/spec.rb:264 # Inventory with an 'amount off' coupon does not result in a negative total
rspec /tmp/d20111115-5847-1yy9iq9/spec.rb:274 # Inventory with an 'amount off' coupon shows the discount in the invoice
rspec /tmp/d20111115-5847-1yy9iq9/spec.rb:295 # Inventory with multiple discounts can print an invoice

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

Васил обнови решението на 07.11.2011 16:29 (преди около 13 години)

+require 'bigdecimal'
+require 'bigdecimal/util'
+
+module Ordinalize
+ def ordinalize(number)
+ if (11..13).include?(number % 100)
+ "#{number}th"
+ else
+ case number % 10
+ when 1 then "#{number}st"
+ when 2 then "#{number}nd"
+ when 3 then "#{number}rd"
+ else "#{number}th"
+ end
+ end
+ end
+end
+
+class Promotion
+ attr_accessor :promotion, :name, :value, :action
+
+ include Ordinalize
+
+ def initialize(promotion)
+ name = promotion.keys.first
+ details = promotion.values.first
+ case name
+ when :get_one_free then get_one_free(details)
+ when :package then package(details)
+ when :threshold then threshold(details)
+ when nil then no_promotion
+ else raise "No such promotion!"
+ end
+ end
+
+ def get_one_free(details)
+ value = details
+
+ @name = "(buy #{value - 1}, get 1 free)"
+ @action = lambda { |quantity| quantity / value }
+ end
+
+ def package(details)
+ percentage = details.values.first
+ value = details.keys.first
+ discount = percentage.to_f / 100
+
+ @name = "(get #{percentage}% off for every #{value})"
+ @action = lambda { |qty| ((qty / value).to_int * value) * discount }
+ end
+
+ def threshold(details)
+ percentage = details.values.first
+ value = details.keys.first
+ discount = percentage.to_f / 100
+
+ @name = "(#{percentage}% off of every after the #{ordinalize(value)}) "
+ @action = lambda { |qty| ((qty - value) * discount) }
+ end
+
+ def no_promotion
+ @name = nil
+ @value = nil
+ end
+end
+
+class Product
+ attr_accessor :name, :price, :promotion
+
+ def initialize(name, price, promotion)
+ if valid_product?(name, price)
+ @name = name
+ @price = price.to_d
+ @promotion = Promotion.new(promotion)
+ else
+ raise "Invalid product name or price"
+ end
+ end
+
+ def valid_product?(name, price)
+ valid_name?(name) and valid_price?(price)
+ end
+
+ def valid_name?(name)
+ name.length <= 40
+ end
+
+ def valid_price?(price)
+ price.to_d >= 0.01 and price.to_d <= 999.99
+ end
+end
+
+class Coupon
+ attr_accessor :name, :value
+
+ def initialize(name, value)
+ @name = name
+ case value.keys.first
+ when 'percent' then coupon_percent(value)
+ when 'amount' then coupon_amount(value)
+ else raise "No such coupon!"
+ end
+ end
+
+ def coupon_percent(value)
+
+ end
+
+ def coupon_amount(value)
+
+ end
+
+end
+
+class Inventory
+ attr_accessor :products
+
+ def initialize
+ @products = []
+ end
+
+ def register(name, price, promotion = {})
+ product = Product.new(name, price, promotion)
+ check_product(product)
+ end
+
+ def check_product(product)
+ if valid_product?(product)
+ @products << product
+ else
+ raise "There's already a product with the name '#{product.name}'."
+ end
+ end
+
+ def valid_product?(in_product)
+ @products.select { |product| product.name == in_product.name }.length == 0
+ end
+
+ def new_cart
+ cart = Cart.new(@products)
+ end
+
+ def register_coupon(name, value)
+ @coupon = Coupon.new(name, value)
+ end
+
+end
+
+class Cart
+ attr_accessor :cart, :inventory, :total
+
+ def initialize(inv)
+ @cart = {}
+ @inventory = inv.map { |product| [product.name, product.price, product.promotion] }
+ @total = 0
+ end
+
+ def add(name, quantity=1)
+ unless valid_name? name and valid_quantity? quantity
+ raise "Invalid parameters passed."
+ end
+
+ promotion, price, promotion_action = *get_price_n_promotion(name)
+
+ if name_exists? name
+ quantity = @cart[name].last + quantity
+ end
+
+ @cart[name] = [price, quantity]
+
+ if promotion and promotion_action.call(quantity) != 0
+ @cart[promotion] = [price * (-1), promotion_action.call(quantity)]
+ end
+ end
+
+ def get_price_n_promotion(product_name)
+ product = @inventory.select { |product| product.first == product_name }
+ [product.last.last.name, product.last[1], product.last.last.action]
+ end
+
+ def name_exists?(name)
+ @cart.include? name
+ end
+
+ def valid_quantity?(quantity)
+ quantity > 0 and
+ quantity <= 99 and
+ quantity.integer?
+ end
+
+ def valid_name?(name)
+ @inventory.flatten.include? name
+ end
+
+ def total
+ @total = []
+ @cart.each do |key, value|
+ @total << (value.first * value.last)
+ end
+ @total.inject(0) { |element, another_element| element + another_element }
+ end
+
+ def invoice
+ invoice = Invoice.new(@cart, total)
+ invoice.string
+ end
+
+ def use
+
+ end
+end
+
+class Invoice
+ attr_accessor :line, :columns, :products, :total, :string
+
+ def initialize(cart, total)
+ @string = generate_string(cart, total)
+ end
+
+ def generate_string(cart, total)
+ line +
+ columns +
+ line +
+ products(cart) +
+ line +
+ format_total(total) +
+ line
+ end
+
+ def line
+ @line = '+' + ('-' * 48) + '+' + ('-' * 10) + '+' + "\n"
+ end
+
+ def columns
+ @columns = "| %-37s %8s | %8s |\n" % ["Name", "qty", "price"]
+ end
+
+ def products(cart)
+ string = ""
+ cart.each do |key, value|
+ name, qty, price = key, value.last, value.last * value.first
+
+ if is_promotion? price
+ string += "| %-44s | %8.2f |\n" % ["#{name}", "#{price}"]
+ else
+ string += "| %-37s %8.0d | %8.2f |\n" % ["#{name}", "#{qty}", "#{price}"]
+ end
+ end
+ string
+ end
+
+ def is_promotion?(price)
+ price < 0
+ end
+
+ def format_total(total)
+ @total = "|%-47s | %8.2f |\n" % [" TOTAL", total.to_f]
+ end
+end