= Edge State Machine Edge State Machine is a complete state machine solution. It offers support for ActiveRecord, Mongoid and MongoMapper for persistence. {}[http://travis-ci.org/danpersa/edge-state-machine] == Supported Features * 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 == Installation 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 == State Machine Examples === Microwave State Machine 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 === Dice State Machine 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 === Other Examples For other (more complex) examples, please check the following links: * {Examples without Persistence}[https://github.com/danpersa/edge-state-machine/tree/master/spec/non_persistent/samples] * {Examples with ActiveRecord}[https://github.com/danpersa/edge-state-machine/tree/master/spec/active_record/samples] * {Examples with Mongoid}[https://github.com/danpersa/edge-state-machine/tree/master/spec/mongoid/samples] * {Examples with Mongoid}[https://github.com/danpersa/edge-state-machine/tree/master/spec/mongoid/samples] * {Examples with MongoMapper}[https://github.com/danpersa/edge-state-machine/tree/master/spec/mongo_mapper/samples] == Notes For classes with multiple state machines, the state names, machine names must be unique per class. The same thing with the event names. == Credits The gem is based on Rick Olson's code of ActiveModel::StateMachine, axed from ActiveModel in {this commit}[http://github.com/rails/rails/commit/db49c706b62e7ea2ab93f05399dbfddf5087ee0c]. And on Krzysiek HerĂ³d's gem, {Transitions}[https://github.com/netizer/transitions], which added Mongoid support.