Every repository with this icon (
Every repository with this icon (
tree 8647ac1eb4d583af47a0f1270d6a2bce2f2f012f
parent ba3975ed3b2040b9fec7e3e30fb4c413f6c64f2c
| name | age | message | |
|---|---|---|---|
| |
.gitignore | ||
| |
CHANGELOG.rdoc | ||
| |
LICENSE | Wed Jun 25 20:23:38 -0700 2008 | |
| |
README.rdoc | ||
| |
Rakefile | ||
| |
init.rb | Sun May 04 15:58:57 -0700 2008 | |
| |
lib/ | ||
| |
test/ |
state_machine
state_machine adds support for creating state machines for attributes within a model.
Resources
API
Bugs
Development
Source
- git://github.com/pluginaweek/state_machine.git
Description
State machines make it dead-simple to manage the behavior of a model. Too often, the status of a record is kept by creating multiple boolean columns in the table and deciding how to behave based on the values in those columns. This can become cumbersome and difficult to maintain when the complexity of your models starts to increase.
state_machine simplifies this design by introducing the various parts of a real state machine, including states, events, and transitions. However, the api is designed to be similar to ActiveRecord in terms of validations and callbacks, making it so simple you don’t even need to know what a state machine is :)
Usage
Example
Below is an example of many of the features offered by this plugin, including
- Initial states
- Transition callbacks
- Conditional transitions
class Vehicle < ActiveRecord::Base
state_machine :state, :initial => 'idling' do before_transition :from => %w(parked idling), :do => :put_on_seatbelt after_transition :to => 'parked', :do => lambda {|vehicle| vehicle.update_attribute(:seatbelt_on, false)} after_transition :on => 'crash', :do => :tow! after_transition :on => 'repair', :do => :fix! event :park do transition :to => 'parked', :from => %w(idling first_gear) end event :ignite do transition :to => 'stalled', :from => 'stalled' transition :to => 'idling', :from => 'parked' end event :idle do transition :to => 'idling', :from => 'first_gear' end event :shift_up do transition :to => 'first_gear', :from => 'idling' transition :to => 'second_gear', :from => 'first_gear' transition :to => 'third_gear', :from => 'second_gear' end event :shift_down do transition :to => 'second_gear', :from => 'third_gear' transition :to => 'first_gear', :from => 'second_gear' end event :crash do transition :to => 'stalled', :from => %w(first_gear second_gear third_gear), :unless => :auto_shop_busy? end event :repair do transition :to => 'parked', :from => 'stalled', :if => :auto_shop_busy? end end def tow! # do something here end def fix! # do something here end def auto_shop_busy? false endend
Using the above model as an example, you can interact with the state machine like so:
vehicle = Vehicle.create # => #<Vehicle id: 1, seatbelt_on: false, state: "parked"> vehicle.ignite # => true vehicle # => #<Vehicle id: 1, seatbelt_on: true, state: "idling"> vehicle.shift_up # => true vehicle # => #<Vehicle id: 1, seatbelt_on: true, state: "first_gear"> vehicle.shift_up # => true vehicle # => #<Vehicle id: 1, seatbelt_on: true, state: "second_gear"> # The bang (!) operator can raise exceptions if the event fails vehicle.park! # => PluginAWeek::StateMachine::InvalidTransition: Cannot transition via :park from "second_gear"
With enumerations
Using the acts_as_enumeration plugin states can be transparently stored using record ids in the database like so:
class VehicleState < ActiveRecord::Base
acts_as_enumeration
create :id => 1, :name => 'parked'
create :id => 2, :name => 'idling'
create :id => 3, :name => 'first_gear'
...
end
class Vehicle < ActiveRecord::Base
belongs_to :state, :class_name => 'VehicleState'
state_machine :state, :initial => 'idling' do
...
event :park do
transition :to => 'parked', :from => %w(idling first_gear)
end
event :ignite do
transition :to => 'stalled', :from => 'stalled'
transition :to => 'idling', :from => 'parked'
end
end
...
end
Notice in the above example, the state machine definition remains exactly the same. However, when interacting with the records, the actual state will be stored using the identifiers defined for the enumeration:
vehicle = Vehicle.create # => #<Vehicle id: 1, seatbelt_on: false, state_id: 1> vehicle.ignite # => true vehicle # => #<Vehicle id: 1, seatbelt_on: true, state_id: 2> vehicle.shift_up # => true vehicle # => #<Vehicle id: 1, seatbelt_on: true, state_id: 3>
This allows states to take on more complex functionality other than just being a string value.
Tools
Jean Bovet - Visual Automata Simulator. This is a great tool for "simulating, visualizing and transforming finite state automata and Turing Machines". This tool can help in the creation of states and events for your models. It is cross-platform, written in Java.
Testing
Before you can run any tests, the following gem must be installed:
To run against a specific version of Rails:
rake test RAILS_FRAMEWORK_ROOT=/path/to/rails
Dependencies
- Rails 2.1 or later
References
- Scott Barron - acts_as_state_machine
- acts_as_enumeration








