将代码注入ruby状态机?

时间:2012-08-27 22:23:51

标签: ruby-on-rails ruby state-machine

我想修补pluginaweek状态机(https://github.com/pluginaweek/state_machine),以便我可以从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

希望别人觉得这很有用。

1 个答案:

答案 0 :(得分: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