っていうか

ステートの遷移時に正しくない遷移先を指定したら、エラーを投げるべきなのでは…。
ガード条件はその前にチェックするのだから、あとは「ガード条件に合って、サポートしてない状態に落ちる」ようなtransitionsの定義がまずいような気がするのだが、どうだろう。

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

(以下続く…かも)

世の中一般に

GDは、何の注釈もなしに「グループディスカッション」の略として通じるものなのだろうか。
まともな就職活動をしたことのない身には、どうも違和感があって仕方がない。


私がGDと聞くと、
グランドデザインのことか、*1
あるいはとあるオープンソースのグラフィックライブラリかを思い浮かべるのだが。


#この発想を「一般的」というつもりは毛頭ありませんが。

*1:多分お仕事のせい