memo money
# -*- encoding: UTF-8 -*- describe "Money" do it "3000.yen で Moneyオブジェクトが生成できること" do 3000.yen.should == Money.create(3000, :yen) end describe "比較演算" do it " == できること " do (1000.yen == 1000.yen).should be_true (1000.yen == 1000.dollar).should be_false (1000.yen == 1001.yen).should be_false end it "!= できること" do (1000.yen != 1000.yen).should be_false (1000.yen != 1000.dollar).should be_true (1000.yen != 1001.yen).should be_true end it "> できること" do (1000.yen > 1001.yen).should be_false (1000.yen > 1000.yen).should be_false (1000.yen > 999.yen).should be_true end it "< できること" do (1000.yen < 1001.yen).should be_true (1000.yen < 1000.yen).should be_false (1000.yen < 999.yen).should be_false end it ">= できること" do (1000.yen >= 1001.yen).should be_false (1000.yen >= 1000.yen).should be_true (1000.yen >= 999.yen).should be_true end it "<= できること" do (1000.yen <= 1001.yen).should be_true (1000.yen <= 1000.yen).should be_true (1000.yen <= 999.yen).should be_false end ["<", ">", ">=", "<="].each do |op| it "異なる単位は比較できないこと #{op}" do eval %Q{ expect do 3000.yen #{op} 2000.dollar end.to raise_error } end end end describe "足し算と引き算" do it "引き算が計算できること" do (3000.yen - 2000.yen).should == 1000.yen (3000.yen - 2000.yen).should_not == 0.yen end it "足し算が計算できること" do (3000.yen + 999.yen).should == 3999.yen (3000.yen + 999.yen).should_not == 3998.yen end it "異なる単位は計算できないこと" do expect do 3000.yen - 2000.dollar end.to raise_error expect do 3000.yen + 2000.dollar end.to raise_error end end describe "ソート" do it "ソートできること" do [200.yen, 100.yen, 300.yen].sort.should == [100.yen, 200.yen, 300.yen] [200.yen, 100.yen, 300.yen].sort.reverse.should == [300.yen, 200.yen, 100.yen] end it "ソートできないこと。異なる単位が混ざっている場合" do expect do [100.yen, 300.yen, 400.dollar, 200.dollar, 500.yen].sort end.to raise_error end end end class Money # @@money = {} def self.create amount, currency = :yen # @@money["#{amount}/#{currency}"] || Money.new(amount, currency) Money.new(amount, currency) end attr_reader :amount, :currency def initialize(amount, currency) @amount, @currency = amount, currency # @@money["#{amount}/#{currency}"] = self end # 比較 def ==(other) self.class == other.class && self.amount == other.amount && self.currency == other.currency end def <=> other assert_same_currency other self.amount <=> other.amount end def < other (self <=> other) == -1 end def > other (self <=> other) == 1 end def >= other (self <=> other) >= 0 end def <= other (self <=> other) <= 0 end # 演算 def +(other) assert_same_currency other Money.create(self.amount + other.amount, self.currency) end def -(other) assert_same_currency other Money.create(self.amount - other.amount, self.currency) end # TODO 割り算、 かけ算 def assert_same_currency other raise "単位が一致しませんでした。 #{self.currency}/#{other.currency}" if self.currency != other.currency end end class Fixnum def yen Money.create(self, :yen) end def dollar Money.create(self, :dollar) end end
hashはオーバライドすべきなのか。かけ算、割り算が残っている.
itの文字列テンプレート化、二次元配列、 evalを使えば、重複を削れそうなんだが、読みにくかったのでやめた。
RSpecは、Data Driven Testの文法を用意してたっけ。よく欲しくなる