学習めも
理解が間違ってたら。ごめん。
require 'rubygems' require 'mongo_mapper' require 'pp' MongoMapper.database = 'accounting-patterns' # see accounting transaction http://martinfowler.com/apsupp/accounting.pdf class AccountService class AcccountingRunner def initialize @transaction = AccountingTransaction.new end attr_accessor :transaction 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 runner = AcccountingRunner.new yield runner if runner.valid? # runner.transaction.save! saveしてないんだが。。。 else runner.destory raise "バランスしません" end 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 describe "accounting transaction" do before(:each) do init_db end let(:account_service) { AccountService.new} context "送金 佐藤さんから田中さんへの例" do before(:each) do account_service.send_money do |runner| runner.from("佐藤", 99) runner.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 sato = Account.find_by_name("田中") sato.balance.should == 300 + 99 end end context "送金 鈴木さんから 佐藤さん,田中さんへの例" do before(:each) do account_service.send_money do |runner| runner.from("鈴木", 260) runner.to("佐藤", 110) runner.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 "バランスしない 送金のケース" do it "初期か状態であること" do AccountingTransaction.count.should == 0 lambda { account_service.send_money do |runner| runner.from("鈴木", 260) runner.to("田中", 150) end }.should raise_error("バランスしません") should_init end def should_init 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
本当は、DBトランザクションほしくなるから、Mongoは合わないね。