def assert_equal(expected, actual) print expected == actual ? "." : "Expected #{expected.inspect} but got #{actual.inspect}\n" end class SummingRule def initialize(item, price) @item = item @price = price end def apply(basket) basket.count(@item) * @price end end class DiscountRule def initialize(item, count, discount) @item = item @count = count @discount = discount end def apply(basket) (basket.count(@item) / @count) * -@discount end end class Checkout def initialize @basket = [] @rules = [ SummingRule.new("A", 50), SummingRule.new("B", 30), DiscountRule.new("A", 3, 20), DiscountRule.new("B", 2, 15) ] end def total total = 0 @rules.each do |rule| total += rule.apply(@basket) end total end def scan(item) @basket.push(item) end end checkout = Checkout.new assert_equal(0, checkout.total) checkout.scan("A") assert_equal(50, checkout.total) checkout.scan("B") assert_equal(80, checkout.total) checkout = Checkout.new checkout.scan("A") checkout.scan("A") checkout.scan("A") assert_equal(130, checkout.total) checkout = Checkout.new checkout.scan("B") checkout.scan("B") assert_equal(45, checkout.total) puts