テスト駆動開発入門を Ruby で写経する 9章〜16章
昨日に引き続き、今日も写経。
一部、未完成なところはあるけど、16章まで写経しました。
やったこと
9章〜16章までの写経。
テストコード
require 'test/unit' require 'money' class TC_Money < Test::Unit::TestCase def testMultiplication five = Money.dollar(5) assert_equal(Money.dollar(10), five.times(2)) assert_equal(Money.dollar(15), five.times(3)) end def testEquality assert(Money.dollar(5).equals(Money.dollar(5))) assert(!Money.dollar(5).equals(Money.dollar(6))) assert(Money.franc(5).equals(Money.franc(5))) end def testSimpleAddition five = Money.dollar(5) result = five.plus(five) sum = result assert_equal(five, sum.augend) assert_equal(five, sum.addend) end def testReduceSum sum = Sum.new(Money.dollar(3), Money.dollar(4)) bank = Bank.new result = bank.reduce(sum, "USD") assert_equal(Money.dollar(7), result) end def testReduceMoney bank = Bank.new result = bank.reduce(Money.dollar(1), "USD") assert_equal(Money.dollar(1), result) end def testReduceMoneyDifferentCurrency bank = Bank.new bank.addRate("CHF", "USD", 2) result = bank.reduce(Money.franc(2), "USD") assert_equal(Money.dollar(1), result) end def testIdentityRate assert_equal(1, Bank.new.rate("USD", "USD")) end def testMixedAdditionh fiveBucks = Money.dollar(5) tenFrancs = Money.franc(10) bank = Bank.new bank.addRate("CHF", "USD", 2) result = bank.reduce(fiveBucks.plus(tenFrancs), "USD") assert_equal(Money.dollar(10), result) end def testSumPlusMoney fiveBucks = Money.dollar(5) tenFrancs = Money.franc(10) bank = Bank.new bank.addRate("CHF", "USD", 2) sum = Sum.new(fiveBucks, tenFrancs).plus(fiveBucks) result = bank.reduce(sum, "USD") assert_equal(Money.dollar(15), result) end def testSumTimes fiveBucks = Money.dollar(5) tenFrancs = Money.franc(10) bank = Bank.new bank.addRate("CHF", "USD", 2) sum = Sum.new(fiveBucks, tenFrancs).times(2) result = bank.reduce(sum, "USD") assert_equal(Money.dollar(20), result) end def testPlusSameCurrencyReturnsMoney sum = Money.dollar(1).plus(Money.dollar(1)) assert(sum.class == Money) end end
プロダクトコード
class Money def initialize(amount, currency) @amount = amount @currency = currency end def equals(obj) return @amount == obj.amount && @currency == obj.currency end def ==(obj) @amount == obj.amount && @currency == obj.currency end def self.dollar(amount) return Money.new(amount, "USD") end def self.franc(amount) return Money.new(amount, "CHF") end def times(multiplier) return Money.new(@amount * multiplier, @currency) end def plus(addend) return Sum.new(self, addend) end def reduce(bank, to) rate = bank.rate(@currency, to) return Money.new(@amount / rate, to) end attr_accessor :amount attr_accessor :currency end class Bank def initialize @rates = Hash.new end def reduce(source, to) return source.reduce(self, to) end def rate(from, to) if from == to return 1 end rate = @rates[Pair.new(from, to)] return rate end def addRate(from, to, rate) @rates[Pair.new(from, to)] = rate end end class Sum attr_accessor :augend attr_accessor :addend attr_accessor :amount def initialize(augend, addend) @augend = augend @addend = addend end def reduce(bank, to) @amount = @augend.reduce(bank, to).amount \ + @addend.reduce(bank, to).amount return Money.new(@amount, to) end def plus addend return Sum.new(self, addend) end def times multiplier return Sum.new(@augend.times(multiplier), @addend.times(multiplier)) end end class Pair def initialize(from, to) @from = from @to = to end def eql?(obj) return @from == obj.from && @to == obj.to end def hash return 0 end attr_accessor :from attr_accessor :to end