素振り take2
もっと静的に
# -*- encoding: UTF-8 -*- describe "Accounting Transactionパターンの素振り" do before do AccountingTransaction.clear @sato = Account.new do |a| a.name = "佐藤" a.entries = [Entry.new(101), Entry.new(200), Entry.new(-100)] end @tanaka = Account.new do |a| a.name = "田中" a.entries = [Entry.new(102), Entry.new(200), Entry.new(-100)] end Account[@sato.name] = @sato Account[@tanaka.name] = @tanaka end describe "success send money. amount:100 from:sato to:tanaka " do let(:move_amount) {100} before(:each) do SendMoneyContext.new do |c| c.from_account = Account["佐藤"] c.to_account = Account["田中"] c.amount = move_amount end.run end describe "transaction" do subject { AccountingTransaction.last } it { should_not be_nil} it(:from_entry) { should_not be_nil } it(:to_entry) { should_not be_nil } end describe "from_entry" do subject { AccountingTransaction.last.from_entry } its(:amount) { should == -move_amount } end describe "to_entry" do subject { AccountingTransaction.last.to_entry } its(:amount) { should == move_amount } end describe "佐藤:from_account" do subject { Account["佐藤"] } its(:balance) { should == 201 - move_amount } end describe "田中:to_account " do subject { Account["田中"] } its(:balance) { should == 202 + move_amount } end end end class SendMoneyContext attr_accessor :from_account, :to_account, :amount def initialize &block yield self Thread.current[:context] = self end def run t = AccountingTransaction.new do |t| t.from_entry = from_account.send_money t.to_entry = to_account.receive_money end AccountingTransaction.add t end end class AccountingTransaction attr_accessor :from_entry, :to_entry @@transaction = [] def initialize &block yield self end def self.add node @@transaction << node end def self.last @@transaction.last end def self.clear @@transaction = [] end end class Entry attr_accessor :amount def initialize amount @amount = amount end end class Account @@accounts = {} attr_accessor :name def initialize &block yield self end def self.[]=key, value @@accounts[key] = value end def self.[] key @@accounts[key] end module ForEntry def add_entiry entry @entries << entry end def entries= entries @entries = entries end end module ExecutionContextAPI def amount amount = Thread.current[:context].amount end end module FromRole def send_money s = Entry.new(-amount) add_entiry s s end end module ToRole def receive_money d = Entry.new(amount) add_entiry d d end end module BalanceRole def balance @entries.inject(0) do |result, e| result + e.amount end end end include ExecutionContextAPI, ForEntry, FromRole, ToRole, BalanceRole end