ryanza / stateflow

State machine that allows dynamic transitions for business workflows
MIT License
123 stars 41 forks source link

= Stateflow

Now Rails 5 ready :)

== INSTALL

gem install stateflow

== Usage

As you can see below, Stateflow's API is very similar to AASM, but allows for a more dynamic state transition flow. Stateflow supports persistence/storage with Mongoid, MongoMapper, and ActiveRecord. Request any others or push them to me.

Stateflow defaults to ActiveRecord but you can set the persistence layer with:

Stateflow.persistence = :mongo_mapper OR Stateflow.persistence = :active_record OR Stateflow.persistence = :mongoid

Stateflow allows dynamic :to transitions with :decide. The result :decide returns needs to be one of the states listed in the :to array, otherwise it wont allow the transition. Please view the advanced example below for usage.

You can set the default column with the state_column function in the stateflow block. The default state column is "state".

state_column :state

== Rails 3 Stateflow now automatically tries to detect your persistence from your applications default ORM config. If the ORM you are using does not have a persistence layer it will default to ActiveRecord.

== Basic Example

require 'rubygems' require 'stateflow'

No persistence

Stateflow.persistence = :none

class Stoplight include Stateflow

stateflow do
  initial :green

  state :green, :yellow, :red

  event :change_color do
    transitions :from => :green, :to => :yellow
    transitions :from => :yellow, :to => :red
    transitions :from => :red, :to => :green
  end
end

end

== Advanced Example

require 'rubygems' require 'stateflow'

No persistence

Stateflow.persistence = :none

class Test include Stateflow

stateflow do

  initial :love

  state :love do
    enter lambda { |t| p "Entering love" }
    exit :exit_love
  end

  state :hate do
    enter lambda { |t| p "Entering hate" }
    exit lambda { |t| p "Exiting hate" }
  end

  state :mixed do
    enter lambda { |t| p "Entering mixed" }
    exit lambda { |t| p "Exiting mixed" }
  end

  event :b do
    transitions :from => :love, :to => :hate, :if => :no_ice_cream
    transitions :from => :hate, :to => :love
  end

  event :a do
    transitions :from => :love, :to => [:hate, :mixed], :decide => :likes_ice_cream?
    transitions :from => [:hate, :mixed], :to => :love
  end
end

def likes_ice_cream?
  rand(10) > 5 ? :mixed : :hate
end

def exit_love
  p "Exiting love"
end

def no_ice_cream
  rand(4) > 2 ? true : false
end

end

== Bang event vs non-bang event

Bang events will save the model after call, where the non bang event will just update the state and call the transitions. (ie. model.change! vs model.change)

== Extras

== Note on Patches/Pull Requests

== Copyright

Copyright (c) 2010 Ryan Oberholzer. See LICENSE for details.