<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,5 +1,8 @@
 == master
 
+* Allow creating transitions with no from state (effectively allowing the transition for *any* from state)
+* Reduce the number of objects created for each transition
+
 == 0.2.0 / 2008-06-29
 
 * Add a non-bang version of events (e.g. park) that will return a boolean value for success</diff>
      <filename>CHANGELOG.rdoc</filename>
    </modified>
    <modified>
      <diff>@@ -31,12 +31,13 @@ module PluginAWeek #:nodoc:
       # 
       # Configuration options:
       # * +to+ - The state that being transitioned to
-      # * +from+ - A state or array of states that can be transitioned from
+      # * +from+ - A state or array of states that can be transitioned from. If not specified, then the transition can occur for *any* from state
       # * +if+ - Specifies a method, proc or string to call to determine if the validation should occur (e.g. :if =&gt; :moving?, or :if =&gt; Proc.new {|car| car.speed &gt; 60}). The method, proc or string should return or evaluate to a true or false value.
       # * +unless+ - Specifies a method, proc or string to call to determine if the transition should not occur (e.g. :unless =&gt; :stopped?, or :unless =&gt; Proc.new {|car| car.speed &lt;= 60}). The method, proc or string should return or evaluate to a true or false value.
       # 
       # == Examples
       # 
+      #   transition :to =&gt; 'parked'
       #   transition :to =&gt; 'parked', :from =&gt; 'first_gear'
       #   transition :to =&gt; 'parked', :from =&gt; %w(first_gear reverse)
       #   transition :to =&gt; 'parked', :from =&gt; 'first_gear', :if =&gt; :moving?
@@ -50,21 +51,19 @@ module PluginAWeek #:nodoc:
         to_state = options.delete(:to)
         from_states = Array(options.delete(:from))
         
-        from_states.collect do |from_state|
-          # Create the actual transition that will update records when performed
-          transition = Transition.new(self, from_state, to_state)
-          
-          # Add the callback to the model. If the callback fails, then the next
-          # available callback for the event will run until one is successful.
-          callback = Proc.new {|record, *args| try_transition(transition, false, record, *args)}
-          owner_class.send(&quot;transition_on_#{name}&quot;, callback, options)
-          
-          # Add the callback! to the model similar to above
-          callback = Proc.new {|record, *args| try_transition(transition, true, record, *args)}
-          owner_class.send(&quot;transition_bang_on_#{name}&quot;, callback, options)
-          
-          transition
-        end
+        # Create the actual transition that will update records when performed
+        transition = Transition.new(self, to_state, *from_states)
+        
+        # Add the callback to the model. If the callback fails, then the next
+        # available callback for the event will run until one is successful.
+        callback = Proc.new {|record, *args| try_transition(transition, false, record, *args)}
+        owner_class.send(&quot;transition_on_#{name}&quot;, callback, options)
+        
+        # Add the callback! to the model similar to above
+        callback = Proc.new {|record, *args| try_transition(transition, true, record, *args)}
+        owner_class.send(&quot;transition_bang_on_#{name}&quot;, callback, options)
+        
+        transition
       end
       
       # Attempts to perform one of the event's transitions for the given record</diff>
      <filename>lib/state_machine/event.rb</filename>
    </modified>
    <modified>
      <diff>@@ -7,38 +7,37 @@ module PluginAWeek #:nodoc:
     # A transition indicates a state change and is described by a condition
     # that would need to be fulfilled to enable the transition.  Transitions
     # consist of:
-    # * The starting state
+    # * The starting state(s)
     # * The ending state
     # * A guard to check if the transition is allowed
     class Transition
-      # The state from which the transition is being made
-      attr_reader :from_state
-      
       # The state to which the transition is being made
       attr_reader :to_state
       
+      # The states from which the transition can be made
+      attr_reader :from_states
+      
       # The event that caused the transition
       attr_reader :event
       
       delegate  :machine,
                   :to =&gt; :event
       
-      def initialize(event, from_state, to_state) #:nodoc:
+      def initialize(event, to_state, *from_states) #:nodoc:
         @event = event
-        @from_state = from_state
         @to_state = to_state
-        @loopback = from_state == to_state
+        @from_states = from_states
       end
       
       # Whether or not this is a loopback transition (i.e. from and to state are the same)
-      def loopback?(state = from_state)
-        state == to_state
+      def loopback?(from_state)
+        from_state == to_state
       end
       
       # Determines whether or not this transition can be performed on the given
       # states
       def can_perform_on?(record)
-        !from_state || from_state == record.send(machine.attribute)
+        from_states.empty? || from_states.include?(record.send(machine.attribute))
       end
       
       # Runs the actual transition and any callbacks associated with entering</diff>
      <filename>lib/state_machine/transition.rb</filename>
    </modified>
    <modified>
      <diff>@@ -69,12 +69,16 @@ class EventWithTransitionsTest &lt; Test::Unit::TestCase
     assert_nothing_raised {@event.transition(:to =&gt; 'on')}
   end
   
+  def test_should_allow_transitioning_without_a_state
+    assert @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]}
+    assert @event.transition(:to =&gt; 'on', :from =&gt; 'off')
   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]}
+    assert @event.transition(:to =&gt; 'on', :from =&gt; %w(off on))
   end
   
   def teardown
@@ -124,12 +128,24 @@ class EventAfterBeingFiredWithTransitionsTest &lt; Test::Unit::TestCase
     assert_equal 'off', @switch.state
   end
   
-  def test_should_fire_if_transition_is_matched
+  def test_should_fire_if_transition_with_no_from_state_is_matched
+    @event.transition :to =&gt; 'on'
+    assert @event.fire(@switch)
+    assert_equal 'on', @switch.state
+  end
+  
+  def test_should_fire_if_transition_with_from_state_is_matched
     @event.transition :to =&gt; 'on', :from =&gt; 'off'
     assert @event.fire(@switch)
     assert_equal 'on', @switch.state
   end
   
+  def test_should_fire_if_transition_with_multiple_from_states_is_matched
+    @event.transition :to =&gt; 'on', :from =&gt; %w(off on)
+    assert @event.fire(@switch)
+    assert_equal 'on', @switch.state
+  end
+  
   def test_should_not_fire_if_validation_failed
     @event.transition :to =&gt; 'on', :from =&gt; 'off'
     @switch.fail_validation = true</diff>
      <filename>test/unit/event_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -4,34 +4,39 @@ class TransitionTest &lt; Test::Unit::TestCase
   def setup
     @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
     @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
-    @transition = PluginAWeek::StateMachine::Transition.new(@event, 'off', 'on')
+    @transition = PluginAWeek::StateMachine::Transition.new(@event, 'on')
   end
   
-  def test_should_have_a_from_state
-    assert_equal 'off', @transition.from_state
+  def test_should_not_have_any_from_states
+    assert @transition.from_states.empty?
   end
   
-  def test_should_have_a_to_state
-    assert_equal 'on', @transition.to_state
+  def test_should_not_be_a_loopback_if_from_state_is_different
+    assert !@transition.loopback?('off')
   end
   
-  def test_should_not_be_a_loopback
-    assert !@transition.loopback?
+  def test_should_have_a_to_state
+    assert_equal 'on', @transition.to_state
   end
   
-  def test_should_not_be_able_to_perform_if_record_state_is_not_from_state
-    record = new_switch(:state =&gt; 'on')
-    assert !@transition.can_perform_on?(record)
+  def test_should_be_loopback_if_from_state_is_same
+    assert @transition.loopback?('on')
   end
   
-  def test_should_be_able_to_perform_if_record_state_is_from_state
+  def test_should_be_able_to_perform_on_all_states
     record = new_switch(:state =&gt; 'off')
     assert @transition.can_perform_on?(record)
+    
+    record = new_switch(:state =&gt; 'on')
+    assert @transition.can_perform_on?(record)
   end
   
-  def test_should_perform_for_valid_from_state
+  def test_should_perform_for_all_states
     record = new_switch(:state =&gt; 'off')
     assert @transition.perform(record)
+    
+    record = new_switch(:state =&gt; 'on')
+    assert @transition.perform(record)
   end
   
   def test_should_not_raise_exception_if_not_valid_during_perform
@@ -63,58 +68,81 @@ class TransitionTest &lt; Test::Unit::TestCase
   end
 end
 
-class TransitionWithoutFromStateTest &lt; Test::Unit::TestCase
+class TransitionWithLoopbackTest &lt; Test::Unit::TestCase
   def setup
     @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
     @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
-    @transition = PluginAWeek::StateMachine::Transition.new(@event, nil, 'on')
+    @transition = PluginAWeek::StateMachine::Transition.new(@event, 'on', 'on')
   end
   
-  def test_should_not_have_a_from_state
-    assert_nil @transition.from_state
+  def test_should_be_able_to_perform
+    record = new_switch(:state =&gt; 'on')
+    assert @transition.can_perform_on?(record)
   end
   
-  def test_should_be_able_to_perform_on_all_states
-    record = new_switch(:state =&gt; 'off')
-    assert @transition.can_perform_on?(record)
-    
+  def test_should_perform_for_valid_from_state
     record = new_switch(:state =&gt; 'on')
-    assert @transition.can_perform_on?(record)
+    assert @transition.perform(record)
   end
 end
 
-class TransitionWithLoopbackTest &lt; Test::Unit::TestCase
+class TransitionWithFromStateTest &lt; Test::Unit::TestCase
   def setup
     @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
     @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
-    @transition = PluginAWeek::StateMachine::Transition.new(@event, 'on', 'on')
+    @transition = PluginAWeek::StateMachine::Transition.new(@event, 'on', 'off')
   end
   
   def test_should_have_a_from_state
-    assert_equal 'on', @transition.from_state
+    assert_equal ['off'], @transition.from_states
   end
   
-  def test_should_have_a_to_state
-    assert_equal 'on', @transition.to_state
+  def test_should_not_be_able_to_perform_if_record_state_is_not_from_state
+    record = new_switch(:state =&gt; 'on')
+    assert !@transition.can_perform_on?(record)
   end
   
-  def test_should_be_a_loopback
-    assert @transition.loopback?
+  def test_should_be_able_to_perform_if_record_state_is_from_state
+    record = new_switch(:state =&gt; 'off')
+    assert @transition.can_perform_on?(record)
   end
   
-  def test_should_not_be_able_to_perform_if_record_state_is_not_from_state
+  def test_should_perform_for_valid_from_state
     record = new_switch(:state =&gt; 'off')
+    assert @transition.perform(record)
+  end
+end
+
+class TransitionWithMultipleFromStatesTest &lt; Test::Unit::TestCase
+  def setup
+    @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
+    @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
+    @transition = PluginAWeek::StateMachine::Transition.new(@event, 'on', 'off', 'on')
+  end
+  
+  def test_should_have_multiple_from_states
+    assert_equal ['off', 'on'], @transition.from_states
+  end
+  
+  def test_should_not_be_able_to_perform_if_record_state_is_not_from_state
+    record = new_switch(:state =&gt; 'unknown')
     assert !@transition.can_perform_on?(record)
   end
   
-  def test_should_be_able_to_perform_if_record_is_in_from_state
+  def test_should_be_able_to_perform_if_record_state_is_any_from_state
+    record = new_switch(:state =&gt; 'off')
+    assert @transition.can_perform_on?(record)
+    
     record = new_switch(:state =&gt; 'on')
     assert @transition.can_perform_on?(record)
   end
   
-  def test_should_perform_for_valid_from_state
-    record = new_switch(:state =&gt; 'on')
+  def test_should_perform_for_any_valid_from_state
+    record = new_switch(:state =&gt; 'off')
     assert @transition.perform(record)
+    
+    record = new_switch(:state =&gt; 'on')
+    assert @transition.can_perform_on?(record)
   end
 end
 
@@ -122,7 +150,7 @@ class TransitionAfterBeingPerformedTest &lt; Test::Unit::TestCase
   def setup
     @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
     @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
-    @transition = PluginAWeek::StateMachine::Transition.new(@event, 'off', 'on')
+    @transition = PluginAWeek::StateMachine::Transition.new(@event, 'on', 'off')
     
     @record = create_switch(:state =&gt; 'off')
     @transition.perform(@record)
@@ -162,7 +190,7 @@ class TransitionWithCallbacksTest &lt; Test::Unit::TestCase
   def setup
     @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
     @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
-    @transition = PluginAWeek::StateMachine::Transition.new(@event, 'off', 'on')
+    @transition = PluginAWeek::StateMachine::Transition.new(@event, 'on', 'off')
     @record = create_switch(:state =&gt; 'off')
     
     Switch.define_callbacks :before_exit_state_off, :before_enter_state_on, :after_exit_state_off, :after_enter_state_on
@@ -295,7 +323,7 @@ class TransitionWithoutFromStateAndCallbacksTest &lt; Test::Unit::TestCase
   def setup
     @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial =&gt; 'off')
     @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
-    @transition = PluginAWeek::StateMachine::Transition.new(@event, nil, 'on')
+    @transition = PluginAWeek::StateMachine::Transition.new(@event, 'on')
     @record = create_switch(:state =&gt; 'off')
     
     Switch.define_callbacks :before_exit_state_off, :before_enter_state_on, :after_exit_state_off, :after_enter_state_on</diff>
      <filename>test/unit/transition_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>4038912091b9205e8eca10d2130a64f2653851c7</id>
    </parent>
  </parents>
  <author>
    <name>Aaron Pfeifer</name>
    <email>aaron.pfeifer@gmail.com</email>
  </author>
  <url>http://github.com/pluginaweek/state_machine/commit/b90d731c157acfc564e61fedecb4819732536ec2</url>
  <id>b90d731c157acfc564e61fedecb4819732536ec2</id>
  <committed-date>2008-07-03T14:50:10-07:00</committed-date>
  <authored-date>2008-07-03T14:50:10-07:00</authored-date>
  <message>Allow creating transitions with no from state (effectively allowing the transition for *any* from state)
Reduce the number of objects created for each transition</message>
  <tree>7db5f5c0abd332d5603660455fdcc4b17933e460</tree>
  <committer>
    <name>Aaron Pfeifer</name>
    <email>aaron.pfeifer@gmail.com</email>
  </committer>
</commit>
