学習めも 書き直し
subject.send_money do from("鈴木", 260) to("佐藤", 110) to("田中", 150) end
のように書く方法をRackのソースを調べて思い出した。
これにパタン名かイディオム名とか付いてるのかな。
require 'rubygems' require 'mongo_mapper' MongoMapper.database = 'accounting-patterns' # see accounting transaction http://martinfowler.com/apsupp/accounting.pdf describe "accounting transaction" do before(:each) do init_db end subject{ AccountService.new } context "送金 佐藤さんから田中さんへの例" do before(:each) do subject.send_money do from("佐藤", 99) to("田中", 99) end end it "移動の総量は0であること" do trn = AccountingTransaction.last :order => "timestamps" trn.should be_total_zero end it "送り元の balance が減っていること" do sato = Account.find_by_name("佐藤") sato.balance.should == 200 - 99 end it "送り先の balance が増えていること" do tanaka = Account.find_by_name("田中") tanaka.balance.should == 300 + 99 end end context "送金 鈴木さんから 佐藤さん,田中さんへの例" do before(:each) do subject.send_money do from("鈴木", 260) to("佐藤", 110) to("田中", 150) end end it "移動の総量は0であること" do AccountingTransaction.count.should == 1 trn = AccountingTransaction.last :order => "timestamps" trn.should be_total_zero end it "送り元の balance が減っていること" do suzuki = Account.find_by_name("鈴木") suzuki.balance.should == 700 - 260 end it "送り先1の balance が増えていること" do sato = Account.find_by_name("佐藤") sato.balance.should == 200 + 110 end it "送り先2の balance が増えていること" do tanaka = Account.find_by_name("田中") tanaka.balance.should == 300 + 150 end end context "入金出金の総和が 0 にならないケース" do it "初期か状態であること" do lambda { subject.send_money do from("鈴木", 260) to("田中", 150) end }.should raise_error("入出の総和が0になりませんでした") should_init_status end def should_init_status AccountingTransaction.count.should == 0 Entry.count.should == 3 Account.count.should == 3 suzuki = Account.find_by_name("鈴木") suzuki.balance.should == 700 sato = Account.find_by_name("佐藤") sato.balance.should == 200 tanaka = Account.find_by_name("田中") tanaka.balance.should == 300 end end def init_db Account.delete_all Entry.delete_all AccountingTransaction.delete_all sato = Account.new (:name => "佐藤") sato.entries << Entry.new(:amount => 200) # sato.save saveしていないんだが。。。。 こうゆうもの? tanaka = Account.new (:name => "田中") tanaka.entries << Entry.new(:amount => 300) # tanaka.save tanaka = Account.new (:name => "鈴木") tanaka.entries << Entry.new(:amount => 700) #tanaka.save end end class AccountService class AcccountingRunner attr_accessor :transaction def initialize @transaction = AccountingTransaction.new end def send_money(&block) instance_eval(&block) if valid? # runner.transaction.save! saveしてないんだが。。。 else destory raise "入出の総和が0になりませんでした" end end def from(name, amount) entry = Entry.new(:amount => -amount) entry.tmp_account = Account.find_by_name name entry.account = Account.find_by_name name @transaction.entries << entry end def to(name, amount) entry = Entry.new(:amount => amount) entry.tmp_account = Account.find_by_name name entry.account = Account.find_by_name name @transaction.entries << entry end def valid? @transaction.total_zero? end def destory @transaction.entries.delete_all @transaction.delete end end def send_money(&block) runner = AcccountingRunner.new runner.send_money(&block) end end class Account include MongoMapper::Document key :name, String, :required => true, :unique => true many :entries, :order => 'create_at asc' def balance entries.inject(0) do |result, entry| result + entry.amount end end end class Entry attr_accessor :tmp_account include MongoMapper::Document key :amount, Integer belongs_to :account timestamps! end class AccountingTransaction include MongoMapper::Document many :entries timestamps! def total_zero? entries.inject(0) {|result, entry| result + entry.amount } == 0 end end