我想对pluginaweek状态机(https://github.com/pluginaweek/state_machine)进行monkey补丁,以便从mixin模块向状态机注入代码。有人知道如何在状态机中定义一个新的方法来实现这一点吗?或者,也许有更好的方法做我想做的事?
假设,

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

希望其他人觉得这有用。

最佳答案

很难说清楚你到底想做什么,但希望这段代码能有所帮助

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

关于ruby-on-rails - 注入(inject)代码到 ruby 状态机?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12150448/

10-09 17:00