README.rdoc in state_machine-1.0.1 vs README.rdoc in state_machine-1.0.2
- old
+ new
@@ -1,6 +1,6 @@
-== state_machine
+== state_machine http://travis-ci.org/pluginaweek/state_machine.png
+state_machine+ adds support for creating state machines for attributes on any
Ruby class.
== Resources
@@ -9,20 +9,28 @@
* http://rdoc.info/github/pluginaweek/state_machine/master/frames
Bugs
-* http://pluginaweek.lighthouseapp.com/projects/13288-state_machine
+* http://github.com/pluginaweek/state_machine/issues
Development
* http://github.com/pluginaweek/state_machine
+Testing
+
+* http://travis-ci.org/pluginaweek/state_machine
+
Source
* git://github.com/pluginaweek/state_machine.git
+Mailing List
+
+* http://groups.google.com/group/pluginaweek-talk
+
== Description
State machines make it dead-simple to manage the behavior of a class. Too often,
the state of an object is kept by creating multiple boolean attributes and
deciding how to behave based on the values. This can become cumbersome and
@@ -47,10 +55,11 @@
* Attribute-based event transitions
* Path analysis
* Inheritance
* Internationalization
* GraphViz visualization creator
+* Flexible machine syntax
Examples of the usage patterns for some of the above features are shown below.
You can find much more detailed documentation in the actual API.
== Usage
@@ -579,16 +588,26 @@
end
For more information about the various behaviors added for Sequel state
machines, see StateMachine::Integrations::Sequel.
-== Compatibility
+== Syntax flexibility
Although state_machine introduces a simplified syntax, it still remains
-backwards compatible with previous versions and other state-related libraries.
-For example, transitions and callbacks can continue to be defined like so:
+backwards compatible with previous versions and other state-related libraries by
+providing some flexibility around how transitions are defined. See below for an
+overview of these syntaxes.
+=== Verbose syntax
+
+In general, it's recommended that state machines use the implicit syntax for
+transitions. However, you can be a little more explicit and verbose about
+transitions by using the <tt>:from</tt>, <tt>:except_from</tt>, <tt>:to</tt>,
+and <tt>:except_to</tt> options.
+
+For example, transitions and callbacks can be defined like so:
+
class Vehicle
state_machine :initial => :parked do
before_transition :from => :parked, :except_to => :parked, :do => :put_on_seatbelt
after_transition :to => :parked do |transition|
self.seatbelt = 'off' # self is the record
@@ -598,14 +617,69 @@
transition :from => :parked, :to => :idling
end
end
end
-Although this verbose syntax will most likely always be supported, it is
-recommended that any state machines eventually migrate to the syntax introduced
-in version 0.6.0.
+=== Transition context
+Some flexibility is provided around the context in which transitions can be
+defined. In almost all examples throughout the documentation, transitions are
+defined within the context of an event. If you prefer to have state machines
+defined in the context of a *state* either out of preference or in order to
+easily migrate from a different library, you can do so as shown below:
+
+ class Vehicle
+ state_machine :initial => :parked do
+ ...
+
+ state :parked do
+ transition :to => :idling, :on => [:ignite, :shift_up], :if => :seatbelt_on?
+
+ def speed
+ 0
+ end
+ end
+
+ state :first_gear do
+ transition :to => :second_gear, :on => :shift_up
+
+ def speed
+ 10
+ end
+ end
+
+ state :idling, :first_gear do
+ transition :to => :parked, :on => :park
+ end
+ end
+ end
+
+In the above example, there's no need to specify the +from+ state for each
+transition since it's inferred from the context.
+
+You can also define transitions completely outside the context of a particular
+state / event. This may be useful in cases where you're building a state
+machine from a data store instead of part of the class definition. See the
+example below:
+
+ class Vehicle
+ state_machine :initial => :parked do
+ ...
+
+ transition :parked => :idling, :on => [:ignite, :shift_up]
+ transition :first_gear => :second_gear, :second_gear => :third_gear, :on => :shift_up
+ transition [:idling, :first_gear] => :parked, :on => :park
+ transition [:idling, :first_gear] => :parked, :on => :park
+ transition all - [:parked, :stalled] => :stalled, :unless => :auto_shop_busy?
+ end
+ end
+
+Notice that in these alternative syntaxes:
+* You can continue to configure <tt>:if</tt> and <tt>:unless</tt> conditions
+* You can continue to define +from+ states (when in the machine context) using
+the +all+, +any+, and +same+ helper methods
+
== Tools
=== Generating graphs
This library comes with built-in support for generating di-graphs based on the
@@ -636,12 +710,68 @@
#{class_name}_#{machine_name}.#{format}.
For examples of actual images generated using this task, see those under the
examples folder.
-==== Ruby on Rails Integration
+=== Interactive graphs
+Jean Bovet's {Visual Automata Simulator}[http://www.cs.usfca.edu/~jbovet/vas.html]
+is a great tool for "simulating, visualizing and transforming finite state
+automata and Turing Machines". It can help in the creation of states and events
+for your models. It is cross-platform, written in Java.
+
+== Web Frameworks
+
+=== Ruby on Rails
+
+Integrating state_machine into your Ruby on Rails application is straightforward
+and provides a few additional features specific to the framework. To get
+started, following the steps below.
+
+==== 1. Install the gem
+
+If using Rails 2.x:
+
+ # In config/environment.rb
+ ...
+ Rails::Initializer.run do |config|
+ ...
+ config.gem 'state_machine', :version => '~> 1.0'
+ ...
+ end
+
+If using Rails 3.x or up:
+
+ # In Gemfile
+ ...
+ gem 'state_machine'
+ gem 'ruby-graphviz', :require => 'graphviz' # Optional: only required for graphing
+
+As usual, run <tt>bundle install</tt> to load the gems.
+
+==== 2. Create a model
+
+Create a model with a field to store the state, along with other any other
+fields your application requires:
+
+ $ rails generate model Vehicle state:string
+ $ rake db:migrate
+
+==== 3. Configure the state machine
+
+Add the state machine to your model. Following the examples above,
++app/models/vehicle.rb+ might become:
+
+ class Vehicle < ActiveRecord::Base
+ state_machine :initial => :parked do
+ before_transition :parked => any - :parked, :do => :put_on_seatbelt
+ ...
+ end
+ end
+
+==== Rake tasks
+
There is a special integration Rake task for generating state machines for
classes used in a Ruby on Rails application. This task will load the application
environment, meaning that it's unnecessary to specify the actual file to load.
For example,
@@ -651,46 +781,43 @@
If you are using this library as a gem in Rails 2.x, the following must be added
to the end of your application's Rakefile in order for the above task to work:
require 'tasks/state_machine'
-If you are using Rails 3.0+, you must also add the following to your
-application's Gemfile:
+=== Merb
- gem 'ruby-graphviz', :require => 'graphviz'
+==== Rake tasks
-==== Merb Integration
-
Like Ruby on Rails, there is a special integration Rake task for generating
state machines for classes used in a Merb application. This task will load the
application environment, meaning that it's unnecessary to specify the actual
files to load.
For example,
rake state_machine:draw CLASS=Vehicle
-=== Interactive graphs
-
-Jean Bovet's {Visual Automata Simulator}[http://www.cs.usfca.edu/~jbovet/vas.html]
-is a great tool for "simulating, visualizing and transforming finite state
-automata and Turing Machines". It can help in the creation of states and events
-for your models. It is cross-platform, written in Java.
-
== Testing
To run the core test suite (does *not* test any of the integrations):
- rake test
+ bundle install
+ bundle exec rake test
-Test specific versions of integrations like so:
+To run integration tests:
- rake test INTEGRATION=active_model VERSION=3.0.0
- rake test INTEGRATION=active_record VERSION=2.0.0
- rake test INTEGRATION=data_mapper VERSION=0.9.4
- rake test INTEGRATION=mongoid VERSION=2.0.0
- rake test INTEGRATION=mongo_mapper VERSION=0.5.5
- rake test INTEGRATION=sequel VERSION=2.8.0
+ bundle install
+ rake appraisal:install
+ rake appraisal:test
+
+You can also test a specific version:
+
+ rake appraisal:active_model-3.0.0 test
+ rake appraisal:active_record-2.0.0 test
+ rake appraisal:data_mapper-0.9.4 test
+ rake appraisal:mongoid-2.0.0 test
+ rake appraisal:mongo_mapper-0.5.5 test
+ rake appraisal:sequel-2.8.0 test
== Caveats
The following caveats should be noted when using state_machine: