Edge State Machine is a complete state machine solution. It offers support for ActiveRecord, Mongoid and MongoMapper for persistence.
<img src=“https://secure.travis-ci.org/danpersa/edge-state-machine.png”/>
-
Multiple state machines per class each of them acting independently
-
Find errors in state machine definitions as early as possible
-
Transition guards
-
Multiple actions executed on transitions
-
Multiple actions executed on entering and exiting a state
-
No other dependencies for non-persistent state machines
-
Minimal dependencies for persistent ones
If you’re using Rails + ActiveRecord + Bundler
# in your Gemfile gem "edge-state-machine", :require => ["edge-state-machine", "active_record/edge-state-machine"] # in your AR models that will use the state machine include ::EdgeStateMachine include ActiveRecord::EdgeStateMachine state_machine do state :available # first one is initial state state :out_of_stock state :discontinue event :discontinue do transitions :to => :discontinue, :from => [:available, :out_of_stock], :on_transition => :do_discontinue end event :out_of_stock do transitions :to => :out_of_stock, :from => [:available, :discontinue] end event :available do transitions :to => :available, :from => [:out_of_stock], :on_transition => :send_alerts end end
If you’re using Rails + Mongoid + Bundler
# in your Gemfile gem "edge-state-machine", :require => ["edge-state-machine", "mongoid/edge-state-machine"] # in your AR models that will use the state machine include ::EdgeStateMachine include Mongoid::EdgeStateMachine state_machine do state :available # first one is initial state state :out_of_stock state :discontinue event :discontinue do transitions :to => :discontinue, :from => [:available, :out_of_stock], :on_transition => :do_discontinue end event :out_of_stock do transitions :to => :out_of_stock, :from => [:available, :discontinue] end event :available do transitions :to => :available, :from => [:out_of_stock], :on_transition => :send_alerts end end
If you’re using Rails + MongoMapper + Bundler
# in your Gemfile gem "edge-state-machine", :require => ["edge-state-machine", "mongo_mapper/edge-state-machine"] # in your models that will use the state machine include ::EdgeStateMachine include MongoMapper::EdgeStateMachine state_machine do state :available # first one is initial state state :out_of_stock state :discontinue event :discontinue do transitions :to => :discontinue, :from => [:available, :out_of_stock], :on_transition => :do_discontinue end event :out_of_stock do transitions :to => :out_of_stock, :from => [:available, :discontinue] end event :available do transitions :to => :available, :from => [:out_of_stock], :on_transition => :send_alerts end end
class Microwave state_machine :microwave do # name should be optional, if the name is not present, it should have a default name # we give state machines names, so we can pun many machines inside a class initial_state :unplugged # initial state should be optional, if the initial state is not present, the initial state will be the first defined state state :unplugged state :plugged state :door_opened do enter :light_on # enter should be executed on entering the state exit :light_off # exit method should be executed on exiting the state end state :door_closed state :started_in_grill_mode do enter lambda { |t| p "Entering hate" } # should have support for Procs exit :grill_off end state :started do enter :microwaves_on exit :microwaves_off end event :plug_in do transition :from => :unplugged, :to => :plugged end event :open_door do transition :from => :plugged, :to => :door_opened end event :close_door do transition :from => :door_opened, :to => :door_closed, :on_transition => :put_food_in_the_microwave # we can put many actions in an Array for the on_transition parameter end event :start do transition :from => :door_closed, :to => [:started, :started_in_grill_mode], :on_transition => :start_spinning_the_food, :guard => :grill_button_pressed? # the method grill_button_pressed? should choose the next state end event :stop do transition :from => [:started, :started_in_grill_mode], :to => :door_closed end end end
class Dice state_machine do state :one state :two state :three state :four state :five state :six event :roll do transition :from => [:one, :two, :three, :four, :five, :six], :to => [:one, :two, :three, :four, :five, :six], :guard => :roll_result, :on_transition => :display_dice_rolling_animation end end def roll_result # return one of the states end def display_dice_rolling_animation # draw the new position of the dice end end class User state_machine do state :pending # first one is initial state state :active state :blocked # the user in this state can't sign in event :activate do transition :from => [:pending], :to => :active, :on_transition => :do_activate end event :block do transition :from => [:pending, :active], :to => :blocked end end end
For other (more complex) examples, please check the following links:
For classes with multiple state machines, the state names, machine names must be unique per class.
The same thing with the event names.
The gem is based on Rick Olson’s code of ActiveModel::StateMachine, axed from ActiveModel in this commit.
And on Krzysiek Heród’s gem, Transitions, which added Mongoid support.