3

mixin モジュールからステート マシンにコードを挿入できるように、pluginaweek ステート マシン (https://github.com/pluginaweek/state_machine) にモンキー パッチを適用したいと考えています。これを行うためにステートマシンで新しいメソッドを定義する方法を知っている人はいますか? または、おそらく私が達成したいことを行うためのより良い方法がありますか?

仮説として、

class Artifact < ActiveRecord::Base
  include Provisionable # << This module makes the magic method 'provision',
                        # << below, available

  state_machine :machine_state, :initial => :s_initial do
    # ...
    provision(:param1, :param2, :param3) # << The Question: how to define
                                         # << this in the Provisionable mixin
                                         # << module, below
    ...
  end
...
end

module Provisionable
  #
  # << provision() is supposed to inject the desired code into the state machine:
  #
  def provision

    # << Code sample to be injected begins here:
    event :parameterize do
      transition :s_unprovisioned => :s_initial
    end
    before_transition :s_unprovisioned => :s_initial do |artifact, transition|
      transition.args.each_pair do |param, value|
        # etc...
      end
    end
    # >> Code to be injected ends here.

  end
end

ステート マシンを購入する場合は、これを強くお勧めします。

ありがとう!

[後で追加:] 私は解決策を考え出しました。これが他の人に役立つことを願っています。モジュールを混在させる代わりに、state_machine にモンキー パッチを適用して、コードを挿入するインスタンス メソッドを追加しました。

StateMachine::Machine.class_eval do
    def inject_provisioning()

        event :start do
            transition :s_initial => :s_provisioning
        end
        after_transition :s_initial => :s_provisioning do |goal, transition|
            # Do useful stuff here
            true
        end

        event :provision do
            transition :s_provisioning => :s_completed
        end

        before_transition :s_provisioning => :s_completed do |goal, transition|
            artifact_type = transition.args[0]
            params = transition.args[1]
            # Useful stuff here
            true
        end

        after_transition :s_provisioning => :s_completed do |goal, transition|
            artifact_type = transition.args[0]
            params = transition.args[1]
            # Useful stuff here
        end
    end

    def inject_expiration()
        event :chron do
            expired_callback = lambda \
                do |goal|
                    return false if goal.expires_at == :never
                    goal.expires_at.to_i < DateTime.now.to_i
                end
            active_callback = lambda \
                do |goal|
                    return true if goal.expires_at == :never
                    goal.expires_at.to_i >= DateTime.now.to_i
                end
            transition all - :s_expired => :s_expired, :if => expired_callback
        end

        before_transition all - :s_expired => :s_expired do |goal, transition|
            goal.undo
        end
    end

これで、クラスで state_machine 定義を開いているときに、単純なマクロのような呼び出しを行ってコードを挿入できます。

state_machine :machine_state, :initial => :s_initial do
    inject_provisioning
    inject_expiration
end

他の誰かがこれが役に立つことを願っています。

4

1 に答える 1

0

あなたがやろうとしていることを正確に伝えるのは難しいですが、うまくいけば、このコードが役に立ちます

class Artifact < ActiveRecord::Base
  extend Provision

  attr_accessible :some_value, :state

  state_machine :state, :initial => :initial do
    event :foo do
      transition :initial => :bar
    end

    Artifact.provision(self, :param1, :param2, :param3)

    event :fud do
      transition :bar => :initial
    end

  end
end

extend注 -代わりに-を使用して混合しています。これはinclude、メソッドをインスタンスではなくクラス レベルに配置し、self(ステート マシンである) メソッドに渡します。

module Provision
  def provision(state_machine, *args)

    state_machine do
      event :provision do
        transition :initial => :provisioned
      end

      event :deprovision do
        transition :provisioned => :deprovisioned
      end

      before_transition :provisioned => :deprovisioned do |item, transition|
        # transition.args.length == 0
        args.each do |arg|
          puts arg
        end
      end
    end

  end
end
于 2012-08-28T23:21:34.587 に答える