<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>lib/state_machine.rb</filename>
    </added>
    <added>
      <filename>lib/state_machine/event.rb</filename>
    </added>
    <added>
      <filename>lib/state_machine/machine.rb</filename>
    </added>
    <added>
      <filename>lib/state_machine/transition.rb</filename>
    </added>
    <added>
      <filename>test/app_root/app/models/toggle_switch.rb</filename>
    </added>
    <added>
      <filename>test/factory.rb</filename>
    </added>
    <added>
      <filename>test/functional/state_machine_test.rb</filename>
    </added>
    <added>
      <filename>test/unit/machine_test.rb</filename>
    </added>
    <added>
      <filename>test/unit/state_machine_test.rb</filename>
    </added>
    <added>
      <filename>test/unit/transition_test.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,5 +1,23 @@
 *SVN*
 
+*0.1.0* (May 5th, 2008)
+
+* Completely rewritten from scratch
+
+* Renamed to state_machine
+
+* Removed database dependencies
+
+* Removed models in favor of an attribute-agnostic design
+
+* Use ActiveSupport::Callbacks instead of eval_call
+
+* Remove dry_transaction_rollbacks dependencies
+
+* Added functional tests
+
+* Updated documentation
+
 *0.0.1* (September 26th, 2007)
 
 * Add dependency on custom_callbacks</diff>
      <filename>CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-Copyright (c) 2006 Scott Barron, 2006-2007 Aaron Pfefier &amp; Neil Abraham
+Copyright (c) 2006 Scott Barron, 2006-2008 Aaron Pfefier
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the</diff>
      <filename>MIT-LICENSE</filename>
    </modified>
    <modified>
      <diff>@@ -1,29 +1,24 @@
-== has_states
+== state_machine
 
-+has_states+ adds support for managing states, events, and transitions within a
-model.
++state_machine+ support for creating state machines for attributes within a model.
 
 == Resources
 
-Announcement
-
-* http://www.pluginaweek.org
-
 Wiki
 
-* http://wiki.pluginaweek.org/Has_states
+* http://wiki.pluginaweek.org/State_machine
 
 API
 
-* http://api.pluginaweek.org/has_states
+* http://api.pluginaweek.org/state_machine
 
 Development
 
-* http://dev.pluginaweek.org/browser/trunk/plugins/active_record/has/has_states
+* http://dev.pluginaweek.org/browser/trunk/state_machine
 
 Source
 
-* http://svn.pluginaweek.org/trunk/plugins/active_record/has/has_states
+* http://svn.pluginaweek.org/trunk/state_machine
 
 == Description
 
@@ -33,30 +28,53 @@ and deciding how to behave based on the values in those columns.  This can becom
 cumbersome and difficult to maintain when the complexity of your models starts to
 increase.
 
-+has_states+ simplifies this design by introducing the various parts of a state
++state_machine+ simplifies this design by introducing the various parts of a state
 machine, including states, events, and transitions.  However, its 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
 
-=== Running migrations
-
-To migrate the tables required for has_states, you can either run the
-migration from the command line like so:
-
-  rake db:migrate:plugins PLUGIN=has_states
-
-or (more ideally) generate a migration file that will integrate into your main
-application's migration path:
-
-  ruby script/generate plugin_migration has_states
-
-== Testing
-
-Before you can run any tests, the following gems must be installed:
-* plugin_test_helper[http://wiki.pluginaweek.org/Plugin_test_helper]
-* dry_validity_assertions[http://wiki.pluginaweek.org/Dry_validity_assertions]
+=== Example
+
+  class Vehicle &lt; ActiveRecord::Base
+    state_machine :state, :initial =&gt; 'idling' do
+      before_exit   'parked', :put_on_seatbelt
+      after_enter   'parked', Proc.new {|vehicle| vehicle.update_attribute(:seatbelt_on, false)}
+      
+      event :park do
+        transition :to =&gt; 'parked', :from =&gt; %w(idling first_gear)
+      end
+      
+      event :ignite do
+        transition :to =&gt; 'stalled', :from =&gt; 'stalled'
+        transition :to =&gt; 'idling', :from =&gt; 'parked'
+      end
+      
+      event :idle do
+        transition :to =&gt; 'idling', :from =&gt; 'first_gear'
+      end
+      
+      event :shift_up do
+        transition :to =&gt; 'first_gear', :from =&gt; 'idling'
+        transition :to =&gt; 'second_gear', :from =&gt; 'first_gear'
+        transition :to =&gt; 'third_gear', :from =&gt; 'second_gear'
+      end
+      
+      event :shift_down do
+        transition :to =&gt; 'second_gear', :from =&gt; 'third_gear'
+        transition :to =&gt; 'first_gear', :from =&gt; 'second_gear'
+      end
+      
+      event :crash, :after =&gt; :tow! do
+        transition :to =&gt; 'stalled', :from =&gt; %w(first_gear second_gear third_gear), :unless =&gt; :auto_shop_busy?
+      end
+      
+      event :repair, :after =&gt; :fix! do
+        transition :to =&gt; 'parked', :from =&gt; 'stalled', :if =&gt; :auto_shop_busy?
+      end
+    end
+  end
 
 == Tools
 
@@ -67,23 +85,12 @@ events for your models.  It is cross-platform, written in Java.
 
 == Dependencies
 
-This plugin depends on the presence of the following plugins:
-* class_associations[http://wiki.pluginaweek.org/Class_associations]
-* custom_callbacks[http://wiki.pluginaweek.org/Custom_callbacks]
-* dry_transaction_rollbacks[http://wiki.pluginaweek.org/Dry_transaction_callbacks]
-* eval_call[http://wiki.pluginaweek.org/Eval_call]
-
-This plugin is also plugin+.  That means that it contains a slice of an
-application, such as models and migrations.  To test or use a plugin+, you
-must have the following plugins/gems installed:
-* plugin_dependencies[http://wiki.pluginaweek.org/Plugin_dependencies]
-* loaded_plugins[http://wiki.pluginaweek.org/Loaded_plugins]
-* appable_plugins[http://wiki.pluginaweek.org/Appable_plugins]
-* plugin_migrations[http://wiki.pluginaweek.org/Plugin_migrations]
-
-Instead of installing each individual plugin+ feature, you can install them all
-at once using the plugins+[http://wiki.pluginaweek.org/Plugins_plus] meta package,
-which contains all additional features.
+None.
+
+== Testing
+
+Before you can run any tests, the following gem must be installed:
+* plugin_test_helper[http://wiki.pluginaweek.org/Plugin_test_helper]
 
 == References
 </diff>
      <filename>README</filename>
    </modified>
    <modified>
      <diff>@@ -3,25 +3,25 @@ require 'rake/rdoctask'
 require 'rake/gempackagetask'
 require 'rake/contrib/sshpublisher'
 
-PKG_NAME           = 'has_states'
-PKG_VERSION        = '0.0.1'
+PKG_NAME           = 'state_machine'
+PKG_VERSION        = '0.1.0'
 PKG_FILE_NAME      = &quot;#{PKG_NAME}-#{PKG_VERSION}&quot;
 RUBY_FORGE_PROJECT = 'pluginaweek'
 
 desc 'Default: run unit tests.'
 task :default =&gt; :test
 
-desc 'Test the has_states plugin.'
+desc 'Test the state_machine plugin.'
 Rake::TestTask.new(:test) do |t|
   t.libs &lt;&lt; 'lib'
-  t.pattern = 'test/unit/**/*_test.rb'
+  t.pattern = 'test/**/*_test.rb'
   t.verbose = true
 end
 
-desc 'Generate documentation for the has_states plugin.'
+desc 'Generate documentation for the state_machine plugin.'
 Rake::RDocTask.new(:rdoc) do |rdoc|
   rdoc.rdoc_dir = 'rdoc'
-  rdoc.title    = 'HasStates'
+  rdoc.title    = 'StateMachine'
   rdoc.options &lt;&lt; '--line-numbers' &lt;&lt; '--inline-source'
   rdoc.rdoc_files.include('README')
   rdoc.rdoc_files.include('lib/**/*.rb')
@@ -31,18 +31,15 @@ spec = Gem::Specification.new do |s|
   s.name            = PKG_NAME
   s.version         = PKG_VERSION
   s.platform        = Gem::Platform::RUBY
-  s.summary         = 'Adds support for managing states, events, and transitions within a model'
+  s.summary         = 'Adds support for creating state machines for attributes within a model'
   
-  s.files           = FileList['{app,db,lib,test}/**/*'].to_a + %w(CHANGELOG init.rb MIT-LICENSE Rakefile README)
+  s.files           = FileList['{lib,test}/**/*'].to_a + %w(CHANGELOG init.rb MIT-LICENSE Rakefile README)
   s.require_path    = 'lib'
-  s.autorequire     = 'has_states'
+  s.autorequire     = 'state_machine'
   s.has_rdoc        = true
-  s.test_files      = Dir['test/unit/**/*_test.rb']
-  s.add_dependency  'class_associations', '&gt;= 0.0.1'
-  s.add_dependency  'custom_callbacks', '&gt;= 0.0.1'
-  s.add_dependency  'eval_call', '&gt;= 0.0.1'
+  s.test_files      = Dir['test/**/*_test.rb']
   
-  s.author          = 'Aaron Pfeifer, Neil Abraham'
+  s.author          = 'Aaron Pfeifer'
   s.email           = 'info@pluginaweek.org'
   s.homepage        = 'http://www.pluginaweek.org'
 end</diff>
      <filename>Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -1 +1 @@
-require 'has_states'
\ No newline at end of file
+require 'state_machine'</diff>
      <filename>init.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,24 +1,34 @@
 class AutoShop &lt; ActiveRecord::Base
-  has_states :initial =&gt; :available, :record_changes =&gt; false
-  
-  state :available,
-    :after_exit =&gt; :increment_customers
-  state :busy,
-    :after_exit =&gt; :decrement_customers
+  state_machine :state, :initial =&gt; 'available' do
+    after_exit 'available', :increment_customers
+    after_exit 'busy', :decrement_customers
+    
+    event :tow_vehicle do
+      transition :to =&gt; 'busy', :from =&gt; 'available'
+    end
+    
+    event :fix_vehicle do
+      transition :to =&gt; 'available', :from =&gt; 'busy'
+    end
+  end
   
-  event :tow_vehicle do
-    transition_to :busy, :from =&gt; :available
+  # Is the Auto Shop available for new customers?
+  def available?
+    state == 'available'
   end
   
-  event :fix_vehicle do
-    transition_to :available, :from =&gt; :busy
+  # Is the Auto Shop currently not taking new customers?
+  def busy?
+    state == 'busy'
   end
   
+  # Increments the number of customers in service
   def increment_customers
-    update_attribute(:num_customers, self.num_customers + 1)
+    update_attribute(:num_customers, num_customers + 1)
   end
   
+  # Decrements the number of customers in service
   def decrement_customers
-    update_attribute(:num_customers, self.num_customers - 1)
+    update_attribute(:num_customers, num_customers - 1)
   end
-end
\ No newline at end of file
+end</diff>
      <filename>test/app_root/app/models/auto_shop.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,19 +1,19 @@
 class Car &lt; Vehicle
-  state :backing_up
-  
-  event :reverse do
-    transition_to :backing_up, :from =&gt; [:parked, :idling, :first_gear]
+  state_machine :state do
+    event :reverse do
+      transition :to =&gt; 'backing_up', :from =&gt; %w(parked idling first_gear)
+    end
+    
+    event :park do
+      transition :to =&gt; 'parked', :from =&gt; 'backing_up'
+    end
+    
+    event :idle do
+      transition :to =&gt; 'idling', :from =&gt; 'backing_up'
+    end
+    
+    event :shift_up do
+      transition :to =&gt; 'first_gear', :from =&gt; 'backing_up'
+    end
   end
-  
-  event :park do
-    transition_to :parked, :from =&gt; :backing_up
-  end
-  
-  event :idle do
-    transition_to :idling, :from =&gt; :backing_up
-  end
-  
-  event :shift_up do
-    transition_to :first_gear, :from =&gt; :backing_up
-  end
-end
\ No newline at end of file
+end</diff>
      <filename>test/app_root/app/models/car.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,3 @@
 class Motorcycle &lt; Vehicle
-  self.initial_state = :idling
-end
\ No newline at end of file
+  state_machine :state, :initial =&gt; 'idling'
+end</diff>
      <filename>test/app_root/app/models/motorcycle.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,54 +1,12 @@
 class Switch &lt; ActiveRecord::Base
-  cattr_accessor :active_states
-  cattr_accessor :record_state_changes
-  attr_accessor :state
-  attr_reader :callbacks, :state_id, :recorded_event, :recorded_from_state, :recorded_to_state
+  # Tracks the callbacks that were invoked
+  attr_reader :callbacks
   
-  def initialize
-    @callbacks = []
-  end
-  
-  def before_turn_on
-    @callbacks &lt;&lt; 'before_turn_on'
-  end
-  
-  def after_turn_on
-    @callbacks &lt;&lt; 'after_turn_on'
-  end
+  # Dynamic sets the initial state
+  attr_accessor :initial_state
   
-  def turn_key
-    @callbacks &lt;&lt; 'turn_key'
-  end
-  
-  def remove_key
-    @callbacks &lt;&lt; 'remove_key'
-  end
-  
-  def return_false
-    false
-  end
-  
-  def return_true
-    true
-  end
-  
-  def return_param(param)
-    param
-  end
-  
-  def callback(method)
-    @callbacks &lt;&lt; method
+  def initialize(attributes = nil)
+    @callbacks = []
     super
   end
-  
-  def update_attributes!(attrs)
-    @state_id = attrs[:state_id]
-  end
-  
-  private
-  def record_state_change(event, from_state, to_state)
-    @recorded_event = event.record if event
-    @recorded_from_state = from_state.record if from_state
-    @recorded_to_state = to_state.record if to_state
-  end
 end</diff>
      <filename>test/app_root/app/models/switch.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,71 +1,71 @@
 class Vehicle &lt; ActiveRecord::Base
-  has_states :initial =&gt; Proc.new {|vehicle| vehicle.force_idle? ? :idling : :parked}
-  
   belongs_to :auto_shop
-  delegate :tow_vehicle!, :fix_vehicle!, :to =&gt; :auto_shop
+  belongs_to :highway
   
   attr_accessor :force_idle
   
-  validates_presence_of :highway_id
-  
-  state :parked,
-          :before_exit =&gt; :put_on_seatbelt,
-          :after_enter =&gt; Proc.new {|vehicle| vehicle.update_attribute(:seatbelt_on, false)}
-  state :idling,
-        :first_gear,
-        :second_gear,
-        :third_gear
-  state :stalled,
-          :before_enter =&gt; :increase_insurance_premium
-  
-  event :park do
-    transition_to :parked, :from =&gt; [:idling, :first_gear]
-  end
-  
-  event :ignite do
-    transition_to :stalled, :from =&gt; :stalled
-    transition_to :idling, :from =&gt; :parked
-  end
-  
-  event :idle do
-    transition_to :idling, :from =&gt; :first_gear
-  end
-  
-  event :shift_up do
-    transition_to :first_gear, :from =&gt; :idling
-    transition_to :second_gear, :from =&gt; :first_gear
-    transition_to :third_gear, :from =&gt; :second_gear
+  # Defines the state machine for the state of the vehicle
+  state_machine :state, :initial =&gt; Proc.new {|vehicle| vehicle.force_idle ? 'idling' : 'parked'} do
+    before_exit   'parked', :put_on_seatbelt
+    after_enter   'parked', Proc.new {|vehicle| vehicle.update_attribute(:seatbelt_on, false)}
+    before_enter  'stalled', :increase_insurance_premium
+    
+    event :park do
+      transition :to =&gt; 'parked', :from =&gt; %w(idling first_gear)
+    end
+    
+    event :ignite do
+      transition :to =&gt; 'stalled', :from =&gt; 'stalled'
+      transition :to =&gt; 'idling', :from =&gt; 'parked'
+    end
+    
+    event :idle do
+      transition :to =&gt; 'idling', :from =&gt; 'first_gear'
+    end
+    
+    event :shift_up do
+      transition :to =&gt; 'first_gear', :from =&gt; 'idling'
+      transition :to =&gt; 'second_gear', :from =&gt; 'first_gear'
+      transition :to =&gt; 'third_gear', :from =&gt; 'second_gear'
+    end
+    
+    event :shift_down do
+      transition :to =&gt; 'second_gear', :from =&gt; 'third_gear'
+      transition :to =&gt; 'first_gear', :from =&gt; 'second_gear'
+    end
+    
+    event :crash, :after =&gt; :tow! do
+      transition :to =&gt; 'stalled', :from =&gt; %w(first_gear second_gear third_gear), :if =&gt; Proc.new {|vehicle| vehicle.auto_shop.available?}
+    end
+    
+    event :repair, :after =&gt; :fix! do
+      transition :to =&gt; 'parked', :from =&gt; 'stalled', :if =&gt; :auto_shop_busy?
+    end
   end
   
-  event :shift_down do
-    transition_to :second_gear, :from =&gt; :third_gear
-    transition_to :first_gear, :from =&gt; :second_gear
+  # Tows the vehicle to the auto shop
+  def tow!
+    auto_shop.tow_vehicle!
   end
   
-  event :crash, :after =&gt; :tow_vehicle! do
-    transition_to :stalled, :from =&gt; [:first_gear, :second_gear, :third_gear],
-                    :if =&gt; Proc.new {|vehicle| vehicle.auto_shop.available?}
-  end
-  
-  event :repair, :after =&gt; :fix_vehicle! do
-    transition_to :parked, :from =&gt; :stalled,
-                    :if =&gt; :auto_shop_busy?
-  end
-  
-  def force_idle?
-    @force_idle
+  # Fixes the vehicle; it will no longer be in the auto shop
+  def fix!
+    auto_shop.fix_vehicle!
   end
   
   private
-  def put_on_seatbelt
-    self.seatbelt_on = true
-  end
-  
-  def increase_insurance_premium
-    update_attribute(:insurance_premium, self.insurance_premium + 100)
-  end
-  
-  def auto_shop_busy?
-    auto_shop.busy?
-  end
-end
\ No newline at end of file
+    # Safety first! Puts on our seatbelt
+    def put_on_seatbelt
+      self.seatbelt_on = true
+    end
+    
+    # We crashed! Increase the insurance premium on the vehicle
+    def increase_insurance_premium
+      update_attribute(:insurance_premium, self.insurance_premium + 100)
+    end
+    
+    # Is the auto shop currently servicing another customer?
+    def auto_shop_busy?
+      auto_shop.busy?
+    end
+end</diff>
      <filename>test/app_root/app/models/vehicle.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,15 +1,12 @@
 class CreateSwitches &lt; ActiveRecord::Migration
   def self.up
     create_table :switches do |t|
-      t.column :device, :string, :null =&gt; false, :default =&gt; 'light'
+      t.string :state, :null =&gt; false
+      t.string :kind
     end
-    
-    PluginAWeek::Has::States.migrate_up(:switches)
   end
   
   def self.down
-    PluginAWeek::Has::States.migrate_down(:switches)
-    
     drop_table :switches
   end
-end
\ No newline at end of file
+end</diff>
      <filename>test/app_root/db/migrate/001_create_switches.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,16 +1,13 @@
 class CreateAutoShops &lt; ActiveRecord::Migration
   def self.up
     create_table :auto_shops do |t|
-      t.column :name, :string, :null =&gt; false
-      t.column :num_customers, :integer, :null =&gt; false, :default =&gt; 0
+      t.string :name, :null =&gt; false
+      t.integer :num_customers, :null =&gt; false
+      t.string :state, :null =&gt; false
     end
-    
-    PluginAWeek::Has::States.migrate_up(:auto_shops)
   end
   
   def self.down
-    PluginAWeek::Has::States.migrate_down(:switches)
-    
     drop_table :auto_shops
   end
-end
\ No newline at end of file
+end</diff>
      <filename>test/app_root/db/migrate/002_create_auto_shops.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,11 +1,11 @@
 class CreateHighways &lt; ActiveRecord::Migration
   def self.up
     create_table :highways do |t|
-      t.column :name, :string, :null =&gt; false
+      t.string :name, :null =&gt; false
     end
   end
   
   def self.down
     drop_table :highways
   end
-end
\ No newline at end of file
+end</diff>
      <filename>test/app_root/db/migrate/003_create_highways.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,19 +1,16 @@
 class CreateVehicles &lt; ActiveRecord::Migration
   def self.up
     create_table :vehicles do |t|
-      t.column :highway_id, :integer, :null =&gt; false, :default =&gt; 1
-      t.column :auto_shop_id, :integer, :null =&gt; false, :default =&gt; 1
-      t.column :seatbelt_on, :boolean, :null =&gt; false, :default =&gt; true
-      t.column :insurance_premium, :integer, :null =&gt; false, :default =&gt; 50
-      t.column :type, :string
+      t.references :highway, :null =&gt; false
+      t.references :auto_shop, :null =&gt; false
+      t.boolean :seatbelt_on, :null =&gt; false
+      t.integer :insurance_premium, :null =&gt; false
+      t.string :state, :null =&gt; false
+      t.string :type
     end
-    
-    PluginAWeek::Has::States.migrate_up(:vehicles)
   end
   
   def self.down
-    PluginAWeek::Has::States.migrate_down(:vehicles)
-    
     drop_table :vehicles
   end
-end
\ No newline at end of file
+end</diff>
      <filename>test/app_root/db/migrate/004_create_vehicles.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,25 +1,13 @@
-# Load local repository plugin paths
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../associations/class_associations/lib&quot;)
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../miscellaneous/custom_callbacks/lib&quot;)
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../miscellaneous/dry_transaction_rollbacks/lib&quot;)
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../../ruby/object/eval_call/lib&quot;)
-
 # Load the plugin testing framework
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../../test/plugin_test_helper/lib&quot;)
+$:.unshift(&quot;#{File.dirname(__FILE__)}/../../plugin_test_helper/lib&quot;)
 require 'rubygems'
 require 'plugin_test_helper'
 
-PluginAWeek::PluginMigrations.migrate('has_states')
-
 # Run the migrations
 ActiveRecord::Migrator.migrate(&quot;#{RAILS_ROOT}/db/migrate&quot;)
 
+# Mixin the factory helper
+require File.expand_path(&quot;#{File.dirname(__FILE__)}/factory&quot;)
 class Test::Unit::TestCase #:nodoc:
-  fixtures :states, :events
-  
-  def self.require_fixture_classes(table_names=nil)
-    # Don't allow fixture classes to be required because classes like Switch are
-    # going to throw an error since the states and events have not yet been
-    # loaded
-  end
+  include Factory
 end</diff>
      <filename>test/test_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,40 +1,234 @@
-require File.dirname(__FILE__) + '/../test_helper'
+require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
 
 class EventTest &lt; Test::Unit::TestCase
-  fixtures :state_changes
+  def setup
+    @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
+    @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
+  end
+  
+  def test_should_have_a_machine
+    assert_equal @machine, @event.machine
+  end
+  
+  def test_should_have_a_name
+    assert_equal 'turn_on', @event.name
+  end
+  
+  def test_should_define_an_event_action_on_the_owner_class
+    switch = new_switch
+    assert switch.respond_to?(:turn_on!)
+  end
+  
+  def test_should_define_transition_callbacks
+    assert Switch.respond_to?(:transition_on_turn_on)
+  end
   
-  def test_should_be_valid
-    assert_valid events(:switch_turn_on)
+  def test_should_define_before_event_callbacks
+    assert Switch.respond_to?(:before_turn_on)
+  end
+  
+  def test_should_define_after_event_callbacks
+    assert Switch.respond_to?(:after_turn_on)
+  end
+end
+
+class EventWithInvalidOptionsTest &lt; Test::Unit::TestCase
+  def setup
+    @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
+  end
+  
+  def test_should_raise_exception
+    assert_raise(ArgumentError) {PluginAWeek::StateMachine::Event.new(@machine, 'turn_on', :invalid =&gt; true)}
+  end
+end
+
+class EventWithTransitionsTest &lt; Test::Unit::TestCase
+  def setup
+    @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
+    @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
   end
   
-  def test_should_require_name
-    assert_invalid events(:switch_turn_on), :name, nil
+  def test_should_raise_exception_if_invalid_option_specified
+    assert_raise(ArgumentError) {@event.transition(:invalid =&gt; true)}
   end
   
-  def test_should_require_unique_name
-    assert_invalid events(:switch_turn_on).clone, :name
+  def test_should_raise_exception_if_to_option_not_specified
+    assert_raise(ArgumentError) {@event.transition(:from =&gt; 'off')}
+  end
+  
+  def test_should_not_raise_exception_if_from_option_not_specified
+    assert_nothing_raised {@event.transition(:to =&gt; 'on')}
+  end
+  
+  def test_should_allow_transitioning_from_a_single_state
+    assert_equal [%w(off on)], @event.transition(:to =&gt; 'on', :from =&gt; 'off').map {|t| [t.from_state, t.to_state]}
+  end
+  
+  def test_should_allow_transitioning_from_multiple_states
+    assert_equal [%w(off on), %w(on on)], @event.transition(:to =&gt; 'on', :from =&gt; %w(off on)).map {|t| [t.from_state, t.to_state]}
+  end
+  
+  def teardown
+    Switch.class_eval do
+      @transition_on_turn_on_callbacks = nil
+    end
+  end
+end
+
+class EventAfterBeingFiredWithNoTransitionsTest &lt; Test::Unit::TestCase
+  def setup
+    @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
+    @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
+    @switch = create_switch(:state =&gt; 'off')
+  end
+  
+  def test_should_not_fire
+    assert !@event.fire!(@switch)
+  end
+  
+  def test_should_not_change_the_current_state
+    @event.fire!(@switch)
+    assert_equal 'off', @switch.state
+  end
+end
+
+class EventAfterBeingFiredWithTransitionsTest &lt; Test::Unit::TestCase
+  def setup
+    @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
+    @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
+    @event.transition :to =&gt; 'error', :from =&gt; 'on'
+    @switch = create_switch(:state =&gt; 'off')
   end
   
-  def test_should_have_state_changes_association
-    event = events(:project_design)
-    expected = [
-      state_changes(:rss_reader_design)
-    ]
+  def test_should_not_fire_if_no_transitions_are_matched
+    assert !@event.fire!(@switch)
+    assert_equal 'off', @switch.state
+  end
+  
+  def test_should_fire_if_transition_is_matched
+    @event.transition :to =&gt; 'on', :from =&gt; 'off'
+    assert @event.fire!(@switch)
+    assert_equal 'on', @switch.state
+  end
+  
+  def teardown
+    Switch.class_eval do
+      @transition_on_turn_on_callbacks = nil
+    end
+  end
+end
+
+class EventAfterBeingFiredWithConditionalTransitionsTest &lt; Test::Unit::TestCase
+  def setup
+    @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
+    @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
+    @event.transition :to =&gt; 'if_not_evaluated', :from =&gt; 'off', :if =&gt; Proc.new {false}
+    @event.transition :to =&gt; 'unless_not_evaluated', :from =&gt; 'off', :unless =&gt; Proc.new {true}
+    @event.transition :to =&gt; 'no_record', :from =&gt; 'off', :if =&gt; Proc.new {|record, value| record.nil?}
+    @event.transition :to =&gt; 'no_arguments', :from =&gt; 'off', :if =&gt; Proc.new {|record, value| value.nil?}
+    
+    @switch = create_switch(:state =&gt; 'off')
+  end
+  
+  def test_should_not_fire_of_no_transitions_are_matched
+    assert !@event.fire!(@switch, 1)
+    assert_equal 'off', @switch.state
+  end
+  
+  def test_should_fire_if_transition_is_matched
+    @event.transition :to =&gt; 'on', :from =&gt; 'off', :if =&gt; Proc.new {|record, value| value == 1}
+    assert @event.fire!(@switch, 1)
+    assert_equal 'on', @switch.state
+  end
+  
+  def teardown
+    Switch.class_eval do
+      @transition_on_turn_on_callbacks = nil
+    end
+  end
+end
+
+class EventWithinTransactionTest &lt; Test::Unit::TestCase
+  def setup
+    @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
+    @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
+    @event.transition :to =&gt; 'on', :from =&gt; 'off'
+    @switch = create_switch(:state =&gt; 'off')
+    
+    Switch.define_callbacks :after_enter_state_on
+  end
+  
+  def test_should_save_all_records_within_transaction_if_performed
+    Switch.after_enter_state_on Proc.new {|record| Switch.create(:state =&gt; 'pending'); true}
+    assert @event.fire!(@switch)
+    assert_equal 'on', @switch.state
+    assert_equal 'pending', Switch.find(:all).last.state
+  end
+  
+  uses_transaction :test_should_rollback_all_records_within_transaction_if_not_performed
+  def test_should_rollback_all_records_within_transaction_if_not_performed
+    Switch.after_enter_state_on Proc.new {|record| Switch.create(:state =&gt; 'pending'); false}
+    assert !@event.fire!(@switch)
+    assert_equal 1, Switch.count
+  ensure
+    Switch.destroy_all
+  end
+  
+  def teardown
+    Switch.class_eval do
+      @transition_on_turn_on_callbacks = nil
+      @after_enter_state_on_callbacks = nil
+    end
+  end
+end
+
+class EventWithCallbacksTest &lt; Test::Unit::TestCase
+  def setup
+    @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
+    @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
+    @event.transition :from =&gt; 'off', :to =&gt; 'on'
+    @record = create_switch(:state =&gt; 'off')
     
-    assert_equal expected, event.state_changes
+    Switch.define_callbacks :before_turn_on, :after_turn_on
   end
   
-  def test_should_use_name_as_default_human_name
-    event = Event.new(:name =&gt; 'test')
-    assert_equal 'Test', event.human_name
+  def test_should_not_perform_if_before_callback_fails
+    Switch.before_turn_on Proc.new {|record| false}
+    Switch.after_turn_on Proc.new {|record| record.callbacks &lt;&lt; 'after'; true}
+    
+    assert !@event.fire!(@record)
+    assert_equal %w(), @record.callbacks
+  end
+  
+  def test_should_not_perform_if_after_callback_fails
+    Switch.before_turn_on Proc.new {|record| record.callbacks &lt;&lt; 'before'; true}
+    Switch.after_turn_on Proc.new {|record| false}
+    
+    assert !@event.fire!(@record)
+    assert_equal %w(before), @record.callbacks
   end
   
-  def test_should_use_custom_human_name_if_specified
-    event = Event.new(:name =&gt; 'test', :human_name =&gt; 'Custom')
-    assert_equal 'Custom', event.human_name
+  def test_should_perform_if_all_callbacks_are_successful
+    Switch.before_turn_on Proc.new {|record| record.callbacks &lt;&lt; 'before'; true}
+    Switch.after_turn_on Proc.new {|record| record.callbacks &lt;&lt; 'after'; true}
+    
+    assert @event.fire!(@record)
+    assert_equal %w(before after), @record.callbacks
+  end
+  
+  def test_should_pass_additional_arguments_to_callbacks
+    Switch.before_turn_on Proc.new {|record, value| record.callbacks &lt;&lt; &quot;before-#{value}&quot;; true}
+    Switch.after_turn_on Proc.new {|record, value| record.callbacks &lt;&lt; &quot;after-#{value}&quot;; true}
+    
+    assert @event.fire!(@record, 'light')
+    assert_equal %w(before-light after-light), @record.callbacks
   end
   
-  def test_should_convert_to_symbol
-    assert_equal :turn_on, events(:switch_turn_on).to_sym
+  def teardown
+    Switch.class_eval do
+      @before_turn_on_callbacks = nil
+      @after_turn_on_callbacks = nil
+      @transition_on_turn_on_callbacks = nil
+    end
   end
-end
\ No newline at end of file
+end</diff>
      <filename>test/unit/event_test.rb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>app/models/event.rb</filename>
    </removed>
    <removed>
      <filename>app/models/state.rb</filename>
    </removed>
    <removed>
      <filename>app/models/state_change.rb</filename>
    </removed>
    <removed>
      <filename>db/migrate/001_create_states.rb</filename>
    </removed>
    <removed>
      <filename>db/migrate/002_create_events.rb</filename>
    </removed>
    <removed>
      <filename>db/migrate/003_create_state_changes.rb</filename>
    </removed>
    <removed>
      <filename>lib/has_states.rb</filename>
    </removed>
    <removed>
      <filename>lib/has_states/active_event.rb</filename>
    </removed>
    <removed>
      <filename>lib/has_states/active_state.rb</filename>
    </removed>
    <removed>
      <filename>lib/has_states/state_transition.rb</filename>
    </removed>
    <removed>
      <filename>test/app_root/app/models/message.rb</filename>
    </removed>
    <removed>
      <filename>test/app_root/app/models/project.rb</filename>
    </removed>
    <removed>
      <filename>test/app_root/app/models/task.rb</filename>
    </removed>
    <removed>
      <filename>test/app_root/config/environment.rb</filename>
    </removed>
    <removed>
      <filename>test/app_root/db/migrate/005_create_messages.rb</filename>
    </removed>
    <removed>
      <filename>test/app_root/db/migrate/006_create_projects.rb</filename>
    </removed>
    <removed>
      <filename>test/app_root/db/migrate/007_create_tasks.rb</filename>
    </removed>
    <removed>
      <filename>test/fixtures/auto_shops.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/events.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/highways.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/messages.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/projects.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/state_changes.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/states.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/switches.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/vehicles.yml</filename>
    </removed>
    <removed>
      <filename>test/unit/active_event_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/active_state_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/event_not_active_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/event_not_found_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/has_states_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/no_initial_state_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/state_already_active_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/state_change_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/state_not_active_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/state_not_found_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/state_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/state_transition_test.rb</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>1c257492a5efdd15e92d4239a4e94b6a19e4e709</id>
    </parent>
  </parents>
  <author>
    <name>Aaron Pfeifer</name>
    <email>aaron.pfeifer@gmail.com</email>
  </author>
  <url>http://github.com/pluginaweek/state_machine/commit/f3565041379fdcfd94cce18438c361e942bcdddb</url>
  <id>f3565041379fdcfd94cce18438c361e942bcdddb</id>
  <committed-date>2008-05-04T15:58:57-07:00</committed-date>
  <authored-date>2008-05-04T15:58:57-07:00</authored-date>
  <message>Completely rewritten from scratch
Renamed to state_machine
Removed database dependencies
Removed models in favor of an attribute-agnostic design
Use ActiveSupport::Callbacks instead of eval_call
Remove dry_transaction_rollbacks dependencies
Added functional tests
Updated documentation</message>
  <tree>ee1f6486117baa3ffe86be24beac10a1d7755eec</tree>
  <committer>
    <name>Aaron Pfeifer</name>
    <email>aaron.pfeifer@gmail.com</email>
  </committer>
</commit>
