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: