API仕様的には筋が通るのか…
上の記事の続き。
よくaasmを追っていったら、transitionsメソッドの:toオプションは複数を許容していたことが判明。とすれば、変更先ステートの指定が出来るのも頷けなくはない。
ただ、私のステートマシンへの理解だと、同じイベントによって状態遷移が異なることの対応は、ガード条件で行うべきであって、引数指定はやっぱり邪道だと思うんだけどな。
どの状態に遷移すべきかはステートマシンが知っているべき、つまり、遷移状態の決定はステートマシンの責務であるべきで、イベントをキックする側の責務ではないはず。
aasmの作るイベントメソッドがちょっと変
aasm_eventで定義されるイベントメソッドは、引数を取ることができる。これは、lib/aasm/aasm.rbに定義されているとおり。
def aasm_event(name, options = {}, &block) sm = AASM::StateMachine[self] unless sm.events.has_key?(name) sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block) end define_method("#{name.to_s}!") do |*args| aasm_fire_event(name, true, *args) end define_method("#{name.to_s}") do |*args| aasm_fire_event(name, false, *args) end end
というわけで、こんなのを作ってみた。
class Hoge < ActiveRecord::Base include AASM has_one :hoges_fuga has_one :fuga, :through => :hoges_fuga attr_accessor :target_activity aasm_column :state aasm_initial_state :inactive aasm_state :inactive aasm_state :active aasm_event :activate do transitions :from => :inactive, :to => :active, :on_transition => :on_activation end def on_activation(arg) puts arg.inspect true end end
で、こんなのを実行。
h = Hoge.create(:name => 'a name') h.activate('activated!!') => false
なん…だと…
そもそも、on_activationも実行されていないというのか…
というわけで、aasmの内部を解析。
まずは、aasm#aasm_fire_eventを調査。
def aasm_fire_event(name, persist, *args) old_state = aasm_state_object_for_state(aasm_current_state) event = self.class.aasm_events[name] old_state.call_action(:exit, self) # new event before callback event.call_action(:before, self) new_state_name = event.fire(self, *args) ...
というわけで、event(lib/aasm/event.rb)の定義を参照。
def fire(obj, to_state=nil, *args) transitions = @transitions.select { |t| t.from == obj.aasm_current_state } raise AASM::InvalidTransition, "Event '#{name}' cannot transition from '#{obj.aasm_current_state}'" if transitions.size == 0 next_state = nil transitions.each do |transition| next if to_state and !Array(transition.to).include?(to_state) if transition.perform(obj) next_state = to_state || Array(transition.to).first transition.execute(obj, *args) break end end next_state end
あれ?
ってことは…
fireには、第2引数はto_stateで渡っているから*1、そのままnext_stateがnilとしてaasm_fire_eventに返る、よってイベントメソッドの結果はreturn false、となるのね。了解。
ということは、イベントハンドラには引数を指定していても、実際にイベントを起動するときには、上記の例で言えば
hoge.activate!(nil, 'activated!!!')
と渡さないといけない、というわけだ。
しかし、ステートマシンのそもそものあり方から言えば、イベントの引数で遷移先状態を渡す、というのは邪道であって、aasm_fire_eventのevent.fireを呼び出す場合、to_stateはnilで渡すべきなのでは、と考えると、バグのような気もするが、はてさて。
というか、aasmでイベントに引数を渡したいと考えるのは少数なのか…
*1:transitions.each doの直後のnext if条件に抵触するため
4/22の続き
$ sudo dscl . -create /Groups/dba $ sudo dscl . -create /Groups/dba RealName 'Oracle dba' $ sudo dscl . -create /Groups/dba PrimaryGroupID 103 $ sudo dscl . -create /Groups/oper $ sudo dscl . -create /Groups/oper RealName 'Oracle sysoper' $ sudo dscl . -create /Groups/oper PrimaryGroupID 104
oracle 10gのMacへのインストール
まずは、ユーザoracleの追加。
$ sudo dscl . -create /Users/oracle UserShell /usr/bin/false $ sudo dscl . -create /Users/oracle RealName 'Oracle user' $ sudo dscl . -create /Users/oracle UniqueID 102 $ sudo dscl . -create /Users/oracle PrimaryGroupID 102 $ sudo dscl . -create /Users/oracle NFSHomeDirectory /opt/oracle $ sudo dscl . -create /Groups/oracle $ sudo dscl . -create /Groups/oracle name 'Oracle group' $ sudo dscl . -create /Groups/oracle PrimaryGroupID 102
(以下続く…かも)
cucumber-webrat-selenium
CucumberでAJAXのテストをしたいと思ったらこの組み合わせだと思うのだが、案外事例が少ない。
世の中的には他の手法が一般的なのだろうか…。
世の中一般に
GDは、何の注釈もなしに「グループディスカッション」の略として通じるものなのだろうか。
まともな就職活動をしたことのない身には、どうも違和感があって仕方がない。
私がGDと聞くと、
グランドデザインのことか、*1
あるいはとあるオープンソースのグラフィックライブラリかを思い浮かべるのだが。
#この発想を「一般的」というつもりは毛頭ありませんが。
*1:多分お仕事のせい