<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>lib/state_machine/matcher_helpers.rb</filename>
    </added>
    <added>
      <filename>test/unit/matcher_helpers_test.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,5 +1,9 @@
 == master
 
+* Fix nil from/to states not being handled properly
+* Simplify hooking callbacks into loopbacks
+* Add simplified transition/callback requirement syntax
+
 == 0.5.2 / 2009-02-17
 
 * Improve pretty-print of events</diff>
      <filename>CHANGELOG.rdoc</filename>
    </modified>
    <modified>
      <diff>@@ -69,43 +69,39 @@ Class definition:
     attr_accessor :seatbelt_on
     
     state_machine :state, :initial =&gt; :parked do
-      before_transition :from =&gt; [:parked, :idling], :do =&gt; :put_on_seatbelt
+      before_transition any =&gt; [:parked, :idling], :do =&gt; :put_on_seatbelt
       after_transition :on =&gt; :crash, :do =&gt; :tow
       after_transition :on =&gt; :repair, :do =&gt; :fix
-      after_transition :to =&gt; :parked do |vehicle, transition|
+      after_transition any =&gt; :parked do |vehicle, transition|
         vehicle.seatbelt_on = false
       end
       
       event :park do
-        transition :to =&gt; :parked, :from =&gt; [:idling, :first_gear]
+        transition [:idling, :first_gear] =&gt; :parked
       end
       
       event :ignite do
-        transition :to =&gt; :stalled, :from =&gt; :stalled
-        transition :to =&gt; :idling, :from =&gt; :parked
+        transition :stalled =&gt; :stalled, :parked =&gt; :idling
       end
       
       event :idle do
-        transition :to =&gt; :idling, :from =&gt; :first_gear
+        transition :first_gear =&gt; :idling
       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
+        transition :idling =&gt; :first_gear, :first_gear =&gt; :second_gear, :second_gear =&gt; :third_gear
       end
       
       event :shift_down do
-        transition :to =&gt; :second_gear, :from =&gt; :third_gear
-        transition :to =&gt; :first_gear, :from =&gt; :second_gear
+        transition :third_gear =&gt; :second_gear, :second_gear =&gt; :first_gear
       end
       
       event :crash do
-        transition :to =&gt; :stalled, :from =&gt; [:first_gear, :second_gear, :third_gear], :unless =&gt; :auto_shop_busy?
+        transition [:first_gear, :second_gear, :third_gear] =&gt; :stalled, :unless =&gt; :auto_shop_busy?
       end
       
       event :repair do
-        transition :to =&gt; :parked, :from =&gt; :stalled, :if =&gt; :auto_shop_busy?
+        transition :stalled =&gt; :parked, :if =&gt; :auto_shop_busy?
       end
       
       state :parked do
@@ -129,11 +125,11 @@ Class definition:
     
     state_machine :hood_state, :initial =&gt; :closed, :namespace =&gt; 'hood' do
       event :open do
-        transition :to =&gt; :opened
+        transition all =&gt; :opened
       end
       
       event :close do
-        transition :to =&gt; :closed
+        transition all =&gt; :closed
       end
       
       state :opened, :value =&gt; 1
@@ -232,13 +228,13 @@ saving the record, named scopes, and observers.  For example,
 
   class Vehicle &lt; ActiveRecord::Base
     state_machine :initial =&gt; :parked do
-      before_transition :to =&gt; :idling, :do =&gt; :put_on_seatbelt
-      after_transition :to =&gt; :parked do |vehicle, transition|
+      before_transition any =&gt; :idling, :do =&gt; :put_on_seatbelt
+      after_transition any =&gt; :parked do |vehicle, transition|
         vehicle.seatbelt = 'off'
       end
       
       event :ignite do
-        transition :to =&gt; :idling, :from =&gt; :parked
+        transition :parked =&gt; :idling
       end
     end
     
@@ -275,13 +271,13 @@ callbacks, and observers.  For example,
     property :state, String
     
     state_machine :initial =&gt; :parked do
-      before_transition :to =&gt; :idling, :do =&gt; :put_on_seatbelt
-      after_transition :to =&gt; :parked do |transition|
+      before_transition any =&gt; :idling, :do =&gt; :put_on_seatbelt
+      after_transition any =&gt; :parked do |transition|
         self.seatbelt = 'off' # self is the record
       end
       
       event :ignite do
-        transition :to =&gt; :idling, :from =&gt; :parked
+        transition :parked =&gt; :idling
       end
     end
     
@@ -320,13 +316,13 @@ callbacks.  For example,
 
   class Vehicle &lt; Sequel::Model
     state_machine :initial =&gt; :parked do
-      before_transition :to =&gt; :idling, :do =&gt; :put_on_seatbelt
-      after_transition :to =&gt; :parked do |transition|
+      before_transition any =&gt; :idling, :do =&gt; :put_on_seatbelt
+      after_transition any =&gt; :parked do |transition|
         self.seatbelt = 'off' # self is the record
       end
       
       event :ignite do
-        transition :to =&gt; :idling, :from =&gt; :parked
+        transition :parked =&gt; :idling
       end
     end
     </diff>
      <filename>README.rdoc</filename>
    </modified>
    <modified>
      <diff>@@ -1,11 +1,11 @@
 class AutoShop
   state_machine :initial =&gt; :available do
     event :tow_vehicle do
-      transition :to =&gt; :busy, :from =&gt; :available
+      transition :available =&gt; :busy
     end
     
     event :fix_vehicle do
-      transition :to =&gt; :available, :from =&gt; :busy
+      transition :busy =&gt; :available 
     end
   end
 end</diff>
      <filename>examples/auto_shop.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,19 +1,19 @@
 class Car &lt; Vehicle
   state_machine do
     event :reverse do
-      transition :to =&gt; :backing_up, :from =&gt; [:parked, :idling, :first_gear]
+      transition [:parked, :idling, :first_gear] =&gt; :backing_up
     end
     
     event :park do
-      transition :to =&gt; :parked, :from =&gt; :backing_up
+      transition :backing_up =&gt; :parked
     end
     
     event :idle do
-      transition :to =&gt; :idling, :from =&gt; :backing_up
+      transition :backing_up =&gt; :idling
     end
     
     event :shift_up do
-      transition :to =&gt; :first_gear, :from =&gt; :backing_up
+      transition :backing_up =&gt; :first_gear
     end
   end
 end</diff>
      <filename>examples/car.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,9 +1,7 @@
 class TrafficLight
   state_machine :initial =&gt; :stop do
     event :cycle do
-      transition :to =&gt; :proceed, :from =&gt; :stop
-      transition :to =&gt; :caution, :from =&gt; :proceed
-      transition :to =&gt; :stop, :from =&gt; :caution
+      transition :stop =&gt; :proceed, :proceed =&gt; :caution, :caution =&gt; :stop
     end
   end
 end</diff>
      <filename>examples/traffic_light.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,35 +1,31 @@
 class Vehicle
   state_machine :initial =&gt; :parked do
     event :park do
-      transition :to =&gt; :parked, :from =&gt; [:idling, :first_gear]
+      transition [:idling, :first_gear] =&gt; :parked
     end
     
     event :ignite do
-      transition :to =&gt; :stalled, :from =&gt; :stalled
-      transition :to =&gt; :idling, :from =&gt; :parked
+      transition :stalled =&gt; same, :parked =&gt; :idling
     end
     
     event :idle do
-      transition :to =&gt; :idling, :from =&gt; :first_gear
+      transition :first_gear =&gt; :idling
     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
+      transition :idling =&gt; :first_gear, :first_gear =&gt; :second_gear, :second_gear =&gt; :third_gear
     end
     
     event :shift_down do
-      transition :to =&gt; :second_gear, :from =&gt; :third_gear
-      transition :to =&gt; :first_gear, :from =&gt; :second_gear
+      transition :third_gear =&gt; :second_gear, :second_gear =&gt; :first_gear
     end
     
     event :crash do
-      transition :to =&gt; :stalled, :from =&gt; [:first_gear, :second_gear, :third_gear]
+      transition [:first_gear, :second_gear, :third_gear] =&gt; :stalled
     end
     
     event :repair do
-      transition :to =&gt; :parked, :from =&gt; :stalled
+      transition :stalled =&gt; :parked
     end
   end
 end</diff>
      <filename>examples/vehicle.rb</filename>
    </modified>
    <modified>
      <diff>@@ -199,7 +199,7 @@ module StateMachine
     #   class Vehicle
     #     state_machine :initial =&gt; :parked do
     #       event :ignite do
-    #         transition :to =&gt; :idling
+    #         transition all =&gt; :idling
     #       end
     #     end
     #   end
@@ -242,21 +242,21 @@ module StateMachine
     #   class Vehicle
     #     state_machine :heater_state, :initial =&gt; :off :namespace =&gt; 'heater' do
     #       event :turn_on do
-    #         transition :to =&gt; :on
+    #         transition all =&gt; :on
     #       end
     #       
     #       event :turn_off do
-    #         transition :to =&gt; :off
+    #         transition all =&gt; :off
     #       end
     #     end
     #     
     #     state_machine :hood_state, :initial =&gt; :closed, :namespace =&gt; 'hood' do
     #       event :open do
-    #         transition :to =&gt; :opened
+    #         transition all =&gt; :opened
     #       end
     #       
     #       event :close do
-    #         transition :to =&gt; :closed
+    #         transition all =&gt; :closed
     #       end
     #     end
     #   end</diff>
      <filename>lib/state_machine.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,7 @@
 require 'state_machine/transition'
 require 'state_machine/guard'
 require 'state_machine/assertions'
+require 'state_machine/matcher_helpers'
 
 module StateMachine
   # An event defines an action that transitions an attribute from one state to
@@ -8,6 +9,7 @@ module StateMachine
   # guards configured for the event.
   class Event
     include Assertions
+    include MatcherHelpers
     
     # The state machine for which this event is defined
     attr_accessor :machine
@@ -41,15 +43,75 @@ module StateMachine
       @known_states = @known_states.dup
     end
     
-    # Creates a new transition that will be evaluated when the event is fired.
+    # Creates a new transition that determines what to change the current state
+    # to when this event fires.
     # 
-    # Configuration options:
+    # == Defining transitions
+    # 
+    # The options for a new transition uses the Hash syntax to map beginning
+    # states to ending states.  For example,
+    # 
+    #   transition :parked =&gt; :idling, :idling =&gt; :first_gear
+    # 
+    # In this case, when the event is fired, this transition will cause the
+    # state to be +idling+ if it's current state is +parked+ or +first_gear+ if
+    # it's current state is +idling+.
+    # 
+    # To help defining these implicit transitions, a set of helpers are available
+    # for defining slightly more complex matching:
+    # * &lt;tt&gt;all&lt;/tt&gt; - Matches every state in the machine
+    # * &lt;tt&gt;all - [:parked, :idling, ...]&lt;/tt&gt; - Matches every state except those specified
+    # * &lt;tt&gt;any&lt;/tt&gt; - An alias for +all+ (matches every state in the machine)
+    # * &lt;tt&gt;same&lt;/tt&gt; - Matches the same state being transitioned from
+    # 
+    # See StateMachine::MatcherHelpers for more information.
+    # 
+    # === Examples
+    # 
+    #   transition all =&gt; nil                               # Transitions to nil regardless of the current state
+    #   transition all =&gt; :idling                           # Transitions to :idling regardless of the current state
+    #   transition all - [:idling, :first_gear] =&gt; :idling  # Transitions every state but :idling and :first_gear to :idling
+    #   transition nil =&gt; :idling                           # Transitions to :idling from the nil state
+    #   transition :parked =&gt; :idling                       # Transitions to :idling if :parked
+    #   transition [:parked, :stalled] =&gt; :idling           # Transitions to :idling if :parked or :stalled
+    #   
+    #   transition :parked =&gt; same                          # Loops :parked back to :parked
+    #   transition [:parked, :stalled] =&gt; same              # Loops either :parked or :stalled back to the same state
+    #   transition all - :parked =&gt; same                    # Loops every state but :parked back to the same state
+    # 
+    # == Verbose transitions
+    # 
+    # Transitions can also be defined use an explicit set of deprecated
+    # configuration options:
     # * &lt;tt&gt;:from&lt;/tt&gt; - A state or array of states that can be transitioned from.
     #   If not specified, then the transition can occur for *any* state.
     # * &lt;tt&gt;:to&lt;/tt&gt; - The state that's being transitioned to.  If not specified,
     #   then the transition will simply loop back (i.e. the state will not change).
     # * &lt;tt&gt;:except_from&lt;/tt&gt; - A state or array of states that *cannot* be
     #   transitioned from.
+    # 
+    # === Examples
+    # 
+    #   transition :to =&gt; nil
+    #   transition :to =&gt; :idling
+    #   transition :except_from =&gt; [:idling, :first_gear], :to =&gt; :idling
+    #   transition :from =&gt; nil, :to =&gt; :idling
+    #   transition :from =&gt; [:parked, :stalled], :to =&gt; :idling
+    #   
+    #   transition :from =&gt; :parked
+    #   transition :from =&gt; [:parked, :stalled]
+    #   transition :except_from =&gt; :parked
+    # 
+    # Notice that the above examples are the verbose equivalent of the examples
+    # described initially.
+    # 
+    # == Conditions
+    # 
+    # In addition to the state requirements for each transition, a condition
+    # can also be defined to help determine whether that transition is
+    # available.  These options will work on both the normal and verbose syntax.
+    # 
+    # Configuration options:
     # * &lt;tt&gt;:if&lt;/tt&gt; - A method, proc or string to call to determine if the
     #   transition should occur (e.g. :if =&gt; :moving?, or :if =&gt; lambda {|vehicle| vehicle.speed &gt; 60}).
     #   The condition should return or evaluate to true or false.
@@ -57,26 +119,25 @@ module StateMachine
     #   transition should not occur (e.g. :unless =&gt; :stopped?, or :unless =&gt; lambda {|vehicle| vehicle.speed &lt;= 60}).
     #   The condition should return or evaluate to true or false.
     # 
+    # === Examples
+    # 
+    #   transition :parked =&gt; :idling, :if =&gt; :moving?
+    #   transition :parked =&gt; :idling, :unless =&gt; :stopped?
+    #   
+    #   transition :from =&gt; :parked, :to =&gt; :idling, :if =&gt; :moving?
+    #   transition :from =&gt; :parked, :to =&gt; :idling, :unless =&gt; :stopped?
+    # 
     # == Order of operations
     # 
     # Transitions are evaluated in the order in which they're defined.  As a
     # result, if more than one transition applies to a given object, then the
     # first transition that matches will be performed.
-    # 
-    # == Examples
-    # 
-    #   transition :from =&gt; nil, :to =&gt; :parked
-    #   transition :from =&gt; [:first_gear, :reverse]
-    #   transition :except_from =&gt; :parked
-    #   transition :to =&gt; nil
-    #   transition :to =&gt; :parked
-    #   transition :to =&gt; :parked, :from =&gt; :first_gear
-    #   transition :to =&gt; :parked, :from =&gt; [:first_gear, :reverse]
-    #   transition :to =&gt; :parked, :from =&gt; :first_gear, :if =&gt; :moving?
-    #   transition :to =&gt; :parked, :from =&gt; :first_gear, :unless =&gt; :stopped?
-    #   transition :to =&gt; :parked, :except_from =&gt; :parked
     def transition(options)
-      assert_valid_keys(options, :from, :to, :except_from, :if, :unless)
+      raise ArgumentError, 'Must specify as least one transition requirement' if options.empty?
+      
+      # Only a certain subset of explicit options are allowed for transition
+      # requirements
+      assert_valid_keys(options, :from, :to, :except_from, :if, :unless) if (options.keys - [:from, :to, :on, :except_from, :except_to, :except_on, :if, :unless]).empty?
       
       guards &lt;&lt; guard = Guard.new(options)
       @known_states |= guard.known_states
@@ -96,11 +157,17 @@ module StateMachine
     def next_transition(object)
       from = machine.state_for(object).name
       
-      if guard = guards.find {|guard| guard.matches?(object, :from =&gt; from)}
-        # Guard allows for the transition to occur
-        to = guard.state_requirement[:to].values.any? ? guard.state_requirement[:to].values.first : from
-        Transition.new(object, machine, name, from, to)
+      guards.each do |guard|
+        if match = guard.match(object, :from =&gt; from)
+          # Guard allows for the transition to occur
+          to = match[:to].values.empty? ? from : match[:to].values.first
+          
+          return Transition.new(object, machine, name, from, to)
+        end
       end
+      
+      # No transition matched
+      nil
     end
     
     # Attempts to perform the next available transition on the given object.
@@ -143,7 +210,9 @@ module StateMachine
     #   event   # =&gt; #&lt;StateMachine::Event name=:park transitions=[:idling =&gt; :parked]&gt;
     def inspect
       transitions = guards.map do |guard|
-        &quot;#{guard.state_requirement[:from].description} =&gt; #{guard.state_requirement[:to].description}&quot;
+        guard.state_requirements.map do |state_requirement|
+          &quot;#{state_requirement[:from].description} =&gt; #{state_requirement[:to].description}&quot;
+        end * ', '
       end
       
       &quot;#&lt;#{self.class} name=#{name.inspect} transitions=[#{transitions * ', '}]&gt;&quot;</diff>
      <filename>lib/state_machine/event.rb</filename>
    </modified>
    <modified>
      <diff>@@ -17,58 +17,61 @@ module StateMachine
     # The condition that must *not* be met on an object
     attr_reader :unless_condition
     
-    # The requirement for verifying the event being guarded (includes :on and
-    # :except_on).
+    # The requirement for verifying the event being guarded
     attr_reader :event_requirement
     
-    # The requirement for verifying the states being guarded (includes :from,
-    # :to, :except_from, and :except_to).  All options map to
-    # either nil (if not specified) or an array of state names.
-    attr_reader :state_requirement
+    # One or more requrirements for verifying the states being guarded.  All
+    # requirements contain a mapping of {:from =&gt; matcher, :to =&gt; matcher}.
+    attr_reader :state_requirements
     
     # A list of all of the states known to this guard.  This will pull states
-    # from the following options in +state_requirements+ (in the same order):
+    # from the following options (in the same order):
     # * +from+ / +except_from+
     # * +to+ / +except_to+
     attr_reader :known_states
     
     # Creates a new guard
     def initialize(options = {}) #:nodoc:
-      assert_valid_keys(options, :from, :to, :on, :except_from, :except_to, :except_on, :if, :unless)
-      
       # Build conditionals
       assert_exclusive_keys(options, :if, :unless)
       @if_condition = options.delete(:if)
       @unless_condition = options.delete(:unless)
       
-      # Build event/state requirements
+      # Build event requirement
       @event_requirement = build_matcher(options, :on, :except_on)
-      @state_requirement = {:from =&gt; build_matcher(options, :from, :except_from), :to =&gt; build_matcher(options, :to, :except_to)}
+      
+      if (options.keys - [:from, :to, :on, :except_from, :except_to, :except_on]).empty?
+        # Explicit from/to requirements specified
+        @state_requirements = [{:from =&gt; build_matcher(options, :from, :except_from), :to =&gt; build_matcher(options, :to, :except_to)}]
+      else
+        # Separate out the event requirement
+        options.delete(:on)
+        options.delete(:except_on)
+        
+        # Implicit from/to requirements specified
+        @state_requirements = options.collect do |from, to|
+          from = WhitelistMatcher.new(from) unless from.is_a?(Matcher)
+          to = WhitelistMatcher.new(to) unless to.is_a?(Matcher)
+          {:from =&gt; from, :to =&gt; to}
+        end
+      end
       
       # Track known states.  The order that requirements are iterated is based
       # on the priority in which tracked states should be added.
       @known_states = []
-      [:from, :to].each {|option| @known_states |= @state_requirement[option].values}
+      @state_requirements.each do |state_requirement|
+        [:from, :to].each {|option| @known_states |= state_requirement[option].values}
+      end
     end
     
-    # Attempts to match the given object / query against the set of requirements
+    # Determines whether the given object / query matches the requirements
     # configured for this guard.  In addition to matching the event, from state,
     # and to state, this will also check whether the configured :if/:unless
     # conditions pass on the given object.
     # 
-    # This will return true or false depending on whether a match is found.
-    # 
-    # Query options:
-    # * &lt;tt&gt;:from&lt;/tt&gt; - One or more states being transitioned from.  If none
-    #   are specified, then this will always match.
-    # * &lt;tt&gt;:to&lt;/tt&gt; - One or more states being transitioned to.  If none are
-    #   specified, then this will always match.
-    # * &lt;tt&gt;:on&lt;/tt&gt; - One or more events that fired the transition.  If none
-    #   are specified, then this will always match.
-    # 
     # == Examples
     # 
-    #   guard = StateMachine::Guard.new(:from =&gt; [nil, :parked], :to =&gt; :idling, :on =&gt; :ignite)
+    #   guard = StateMachine::Guard.new(:parked =&gt; :idling, :on =&gt; :ignite)
     #   
     #   # Successful
     #   guard.matches?(object, :on =&gt; :ignite)                                    # =&gt; true
@@ -85,7 +88,36 @@ module StateMachine
     #   guard.matches?(object, :from =&gt; :parked, :to =&gt; :first_gear)              # =&gt; false
     #   guard.matches?(object, :on =&gt; :park, :from =&gt; :parked, :to =&gt; :idling)    # =&gt; false
     def matches?(object, query = {})
-      matches_query?(query) &amp;&amp; matches_conditions?(object)
+      !match(object, query).nil?
+    end
+    
+    # Attempts to match the given object / query against the set of requirements
+    # configured for this guard.  In addition to matching the event, from state,
+    # and to state, this will also check whether the configured :if/:unless
+    # conditions pass on the given object.
+    # 
+    # If a match is found, then the event/state requirements that the query
+    # passed successfully will be returned.  Otherwise, nil is returned if there
+    # was no match.
+    # 
+    # Query options:
+    # * &lt;tt&gt;:from&lt;/tt&gt; - One or more states being transitioned from.  If none
+    #   are specified, then this will always match.
+    # * &lt;tt&gt;:to&lt;/tt&gt; - One or more states being transitioned to.  If none are
+    #   specified, then this will always match.
+    # * &lt;tt&gt;:on&lt;/tt&gt; - One or more events that fired the transition.  If none
+    #   are specified, then this will always match.
+    # 
+    # == Examples
+    # 
+    #   guard = StateMachine::Guard.new(:parked =&gt; :idling, :on =&gt; :ignite)
+    #   
+    #   guard.match(object, :on =&gt; :ignite) # =&gt; {:to =&gt; ..., :from =&gt; ..., :on =&gt; ...}
+    #   guard.match(object, :on =&gt; :park)   # =&gt; nil
+    def match(object, query = {})
+      if (match = match_query(query)) &amp;&amp; matches_conditions?(object)
+        match
+      end
     end
     
     # Draws a representation of this guard on the given graph.  This will draw
@@ -108,26 +140,28 @@ module StateMachine
     # 
     # The collection of edges generated on the graph will be returned.
     def draw(graph, event, valid_states)
-      edges = []
-      
-      # From states determined based on the known valid states
-      from_states = state_requirement[:from].filter(valid_states)
-      
-      # If a to state is not specified, then it's a loopback and each from
-      # state maps back to itself
-      if state_requirement[:to].values.any?
-        to_state = state_requirement[:to].values.first
-        loopback = false
-      else
-        loopback = true
-      end
-      
-      # Generate an edge between each from and to state
-      from_states.each do |from_state|
-        edges &lt;&lt; graph.add_edge(from_state.to_s, (loopback ? from_state : to_state).to_s, :label =&gt; event.to_s)
+      state_requirements.inject([]) do |edges, state_requirement|
+        # From states determined based on the known valid states
+        from_states = state_requirement[:from].filter(valid_states)
+        
+        # If a to state is not specified, then it's a loopback and each from
+        # state maps back to itself
+        if state_requirement[:to].values.empty?
+          loopback = true
+        else
+          to_state = state_requirement[:to].values.first
+          to_state = to_state ? to_state.to_s : 'nil'
+          loopback = false
+        end
+        
+        # Generate an edge between each from and to state
+        from_states.each do |from_state|
+          from_state = from_state ? from_state.to_s : 'nil'
+          edges &lt;&lt; graph.add_edge(from_state, loopback ? from_state : to_state, :label =&gt; event.to_s)
+        end
+        
+        edges
       end
-      
-      edges
     end
     
     protected
@@ -149,20 +183,25 @@ module StateMachine
       # Verifies that all configured requirements (event and state) match the
       # given query.  If a match is return, then a hash containing the
       # event/state requirements that passed will be returned; otherwise, nil.
-      def matches_query?(query)
+      def match_query(query)
         query ||= {}
-        matches_event?(query) &amp;&amp; matches_states?(query)
+        
+        if match_event(query) &amp;&amp; (state_requirement = match_states(query))
+          state_requirement.merge(:on =&gt; event_requirement)
+        end
       end
       
       # Verifies that the event requirement matches the given query
-      def matches_event?(query)
+      def match_event(query)
         matches_requirement?(query, :on, event_requirement)
       end
       
       # Verifies that the state requirements match the given query.  If a
       # matching requirement is found, then it is returned.
-      def matches_states?(query)
-        [:from, :to].all? {|option| matches_requirement?(query, option, state_requirement[option])}
+      def match_states(query)
+        state_requirements.detect do |state_requirement|
+          [:from, :to].all? {|option| matches_requirement?(query, option, state_requirement[option])}
+        end
       end
       
       # Verifies that an option in the given query matches the values required</diff>
      <filename>lib/state_machine/guard.rb</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,7 @@ module StateMachine
     #   class Vehicle &lt; ActiveRecord::Base
     #     state_machine :initial =&gt; :parked do
     #       event :ignite do
-    #         transition :to =&gt; :idling, :from =&gt; :parked
+    #         transition :parked =&gt; :idling
     #       end
     #     end
     #   end
@@ -95,7 +95,7 @@ module StateMachine
     # 
     #   class Vehicle &lt; ActiveRecord::Base
     #     state_machine :initial =&gt; :parked do
-    #       before_transition :to =&gt; :idling do |vehicle|
+    #       before_transition any =&gt; :idling do |vehicle|
     #         vehicle.put_on_seatbelt
     #       end
     #       
@@ -104,7 +104,7 @@ module StateMachine
     #       end
     #       
     #       event :ignite do
-    #         transition :to =&gt; :idling, :from =&gt; :parked
+    #         transition :parked =&gt; :idling
     #       end
     #     end
     #     </diff>
      <filename>lib/state_machine/integrations/active_record.rb</filename>
    </modified>
    <modified>
      <diff>@@ -16,7 +16,7 @@ module StateMachine
     #     
     #     state_machine :initial =&gt; :parked do
     #       event :ignite do
-    #         transition :to =&gt; :idling, :from =&gt; :parked
+    #         transition :parked =&gt; :idling
     #       end
     #     end
     #   end
@@ -122,7 +122,7 @@ module StateMachine
     #     property :state, String
     #     
     #     state_machine :initial =&gt; :parked do
-    #       before_transition :to =&gt; :idling do
+    #       before_transition any =&gt; :idling do
     #         put_on_seatbelt
     #       end
     #       
@@ -131,7 +131,7 @@ module StateMachine
     #       end
     #       
     #       event :ignite do
-    #         transition :to =&gt; :idling, :from =&gt; :parked
+    #         transition :parked =&gt; :idling
     #       end
     #     end
     #     </diff>
      <filename>lib/state_machine/integrations/data_mapper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -37,6 +37,8 @@ module StateMachine
       # If dm-observer is not available, then this feature will be skipped.
       # 
       module Observer
+        include MatcherHelpers
+        
         # Creates a callback that will be invoked *before* a transition is
         # performed, so long as the given configuration options match the
         # transition.  Each part of the transition (event, to state, from state)
@@ -55,7 +57,7 @@ module StateMachine
         #     
         #     state_machine :initial =&gt; :parked do
         #       event :ignite do
-        #         transition :to =&gt; :idling, :from =&gt; :parked
+        #         transition :parked =&gt; :idling
         #       end
         #     end
         #   end
@@ -70,12 +72,12 @@ module StateMachine
         #     end
         #     
         #     # Target all state machines
-        #     before_transition :to =&gt; :idling, :from =&gt; :parked, :on =&gt; :ignite do
+        #     before_transition :parked =&gt; :idling, :on =&gt; :ignite do
         #       # put on seatbelt
         #     end
         #     
         #     # Target a specific state machine
-        #     before_transition :state, :to =&gt; :idling do
+        #     before_transition :state, any =&gt; :idling do
         #       # put on seatbelt
         #     end
         #     
@@ -111,7 +113,7 @@ module StateMachine
         #     
         #     state_machine :initial =&gt; :parked do
         #       event :ignite do
-        #         transition :to =&gt; :idling, :from =&gt; :parked
+        #         transition :parked =&gt; :idling
         #       end
         #     end
         #   end
@@ -126,12 +128,12 @@ module StateMachine
         #     end
         #     
         #     # Target all state machines
-        #     after_transition :to =&gt; :idling, :from =&gt; :parked, :on =&gt; :ignite do
+        #     after_transition :parked =&gt; :idling, :on =&gt; :ignite do
         #       # put on seatbelt
         #     end
         #     
         #     # Target a specific state machine
-        #     after_transition :state, :to =&gt; :idling do
+        #     after_transition :state, any =&gt; :idling do
         #       # put on seatbelt
         #     end
         #     </diff>
      <filename>lib/state_machine/integrations/data_mapper/observer.rb</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,7 @@ module StateMachine
     #   class Vehicle &lt; Sequel::Model
     #     state_machine :initial =&gt; :parked do
     #       event :ignite do
-    #         transition :to =&gt; :idling, :from =&gt; :parked
+    #         transition :parked =&gt; :idling
     #       end
     #     end
     #   end
@@ -101,7 +101,7 @@ module StateMachine
     # 
     #   class Vehicle &lt; Sequel::Model
     #     state_machine :initial =&gt; :parked do
-    #       before_transition :to =&gt; :idling do
+    #       before_transition any =&gt; :idling do
     #         put_on_seatbelt
     #       end
     #       
@@ -110,7 +110,7 @@ module StateMachine
     #       end
     #       
     #       event :ignite do
-    #         transition :to =&gt; :idling, :from =&gt; :parked
+    #         transition :parked =&gt; :idling
     #       end
     #     end
     #     </diff>
      <filename>lib/state_machine/integrations/sequel.rb</filename>
    </modified>
    <modified>
      <diff>@@ -7,6 +7,7 @@ require 'state_machine/event'
 require 'state_machine/callback'
 require 'state_machine/node_collection'
 require 'state_machine/state_collection'
+require 'state_machine/matcher_helpers'
 
 module StateMachine
   # Represents a state machine for a particular attribute.  State machines
@@ -44,7 +45,7 @@ module StateMachine
   # 
   #   class Vehicle
   #     state_machine, :initial =&gt; :parked do
-  #       before_transition :to =&gt; :idling, :do =&gt; lambda {|vehicle| throw :halt}
+  #       before_transition any =&gt; :idling, :do =&gt; lambda {|vehicle| throw :halt}
   #       ...
   #     end
   #   end
@@ -64,7 +65,7 @@ module StateMachine
   #   class Vehicle
   #     state_machine do
   #       event :park do
-  #         transition :to =&gt; :parked, :from =&gt; :idling
+  #         transition :idling =&gt; :parked
   #       end
   #       ...
   #     end
@@ -115,8 +116,8 @@ module StateMachine
   #     end
   #   end
   # 
-  # Additional observer-like behavior may be exposed by the various
-  # integrations available.  See below for more information.
+  # Additional observer-like behavior may be exposed by the various integrations
+  # available.  See below for more information.
   # 
   # == Integrations
   # 
@@ -138,6 +139,7 @@ module StateMachine
   # constants defined under the StateMachine::Integrations namespace.
   class Machine
     include Assertions
+    include MatcherHelpers
     
     class &lt;&lt; self
       # Attempts to find or create a state machine for the given class.  For
@@ -369,7 +371,7 @@ module StateMachine
     #   class Vehicle
     #     state_machine :initial =&gt; :parked do
     #       event :ignite do
-    #         transition :to =&gt; :idling, :from =&gt; :parked
+    #         transition :parked =&gt; :idling
     #       end
     #     end
     #   end
@@ -387,7 +389,7 @@ module StateMachine
     #   class Vehicle
     #     state_machine :initial =&gt; :parked do
     #       event :ignite do
-    #         transition :to =&gt; :idling, :from =&gt; :parked
+    #         transition :parked =&gt; :idling
     #       end
     #       
     #       state :idling, :value =&gt; 'IDLING'
@@ -405,7 +407,7 @@ module StateMachine
     #   class Vehicle &lt; ActiveRecord::Base
     #     state_machine :state_id, :initial =&gt; :parked do
     #       event :ignite do
-    #         transition :to =&gt; :idling, :from =&gt; :parked
+    #         transition :parked =&gt; :idling
     #       end
     #       
     #       states.each {|state| self.state(state.name, :value =&gt; VehicleState.find_by_name(state.name.to_s).id)}
@@ -424,11 +426,11 @@ module StateMachine
     #   class Vehicle
     #     state_machine :purchased_at, :initial =&gt; :available do
     #       event :purchase do
-    #         transition :to =&gt; :purchased
+    #         transition all =&gt; :purchased
     #       end
     #       
     #       event :restock do
-    #         transition :to =&gt; :available
+    #         transition all =&gt; :available
     #       end
     #       
     #       state :available, :value =&gt; nil
@@ -464,7 +466,7 @@ module StateMachine
     #     
     #     state_machine :initial =&gt; :parked do
     #       event :ignite do
-    #         transition :to =&gt; :idling, :from =&gt; :parked
+    #         transition :parked =&gt; :idling
     #       end
     #       
     #       state :parked do
@@ -643,11 +645,11 @@ module StateMachine
     # transitions that can happen as a result of that event.  For example,
     # 
     #   event :park, :stop do
-    #     transition :to =&gt; :parked, :from =&gt; :idling
+    #     transition :idling =&gt; :parked
     #   end
     #   
     #   event :first_gear do
-    #     transition :to =&gt; :first_gear, :from =&gt; :parked, :if =&gt; :seatbelt_on?
+    #     transition :parked =&gt; :first_gear, :if =&gt; :seatbelt_on?
     #   end
     # 
     # See StateMachine::Event#transition for more information on
@@ -664,7 +666,7 @@ module StateMachine
     #     
     #     state_machine do
     #       event :park do
-    #         transition :to =&gt; :parked, :from =&gt; Vehicle.safe_states
+    #         transition Vehicle.safe_states =&gt; :parked
     #       end
     #     end
     #   end 
@@ -675,15 +677,15 @@ module StateMachine
     #     state_machine do
     #       # The park, stop, and halt events will all share the given transitions
     #       event :park, :stop, :halt do
-    #         transition :to =&gt; :parked, :from =&gt; [:idling, :backing_up]
+    #         transition [:idling, :backing_up] =&gt; :parked
     #       end
     #       
     #       event :stop do
-    #         transition :to =&gt; :idling, :from =&gt; :first_gear
+    #         transition :first_gear =&gt; :idling
     #       end
     #       
     #       event :ignite do
-    #         transition :to =&gt; :idling, :from =&gt; :parked
+    #         transition :parked =&gt; :idling
     #       end
     #     end
     #   end
@@ -705,106 +707,66 @@ module StateMachine
     end
     
     # Creates a callback that will be invoked *before* a transition is
-    # performed so long as the given configuration options match the transition.
-    # Each part of the transition (event, to state, from state) must match in
-    # order for the callback to get invoked.
-    # 
-    # Configuration options:
-    # * &lt;tt&gt;:from&lt;/tt&gt; - One or more states being transitioned from.  If none
-    #   are specified, then all states will match.
-    # * &lt;tt&gt;:to&lt;/tt&gt; - One or more states being transitioned to.  If none are
-    #   specified, then all states will match.
-    # * &lt;tt&gt;:on&lt;/tt&gt; - One or more events that fired the transition.  If none
-    #   are specified, then all events will match.
-    # * &lt;tt&gt;:except_from&lt;/tt&gt; - One or more states *not* being transitioned from
-    # * &lt;tt&gt;:except_to&lt;/tt&gt; - One more states *not* being transitioned to
-    # * &lt;tt&gt;:except_on&lt;/tt&gt; - One or more events that *did not* fire the transition
-    # * &lt;tt&gt;:do&lt;/tt&gt; - The callback to invoke when a transition matches. This
-    #   can be a method, proc or string.
-    # * &lt;tt&gt;:if&lt;/tt&gt; - A method, proc or string to call to determine if the
-    #   callback should occur (e.g. :if =&gt; :allow_callbacks, or
-    #   :if =&gt; lambda {|user| user.signup_step &gt; 2}). The method, proc or string
-    #   should return or evaluate to a true or false value. 
-    # * &lt;tt&gt;:unless&lt;/tt&gt; - A method, proc or string to call to determine if the
-    #   callback should not occur (e.g. :unless =&gt; :skip_callbacks, or
-    #   :unless =&gt; lambda {|user| user.signup_step &lt;= 2}). The method, proc or
-    #   string should return or evaluate to a true or false value. 
-    # 
-    # The +except+ group of options (+except_to+, +exception_from+, and
-    # +except_on+) acts as the +unless+ equivalent of their counterparts (+to+,
-    # +from+, and +on+, respectively)
+    # performed so long as the given requirements match the transition.
     # 
     # == The callback
     # 
-    # When defining additional configuration options, callbacks must be defined
-    # in either the :do option or as a block.  For example,
+    # Callbacks must be defined as either the only argument, in the :do option,
+    # or as a block.  For example,
     # 
     #   class Vehicle
     #     state_machine do
-    #       before_transition :to =&gt; :parked, :do =&gt; :set_alarm
-    #       before_transition :to =&gt; :parked do |vehicle, transition|
+    #       before_transition :set_alarm
+    #       before_transition all =&gt; :parked :do =&gt; :set_alarm
+    #       before_transition all =&gt; :parked do |vehicle, transition|
     #         vehicle.set_alarm
     #       end
     #       ...
     #     end
     #   end
     # 
-    # === Accessing the transition
+    # == State requirements
     # 
-    # In addition to passing the object being transitioned, the actual
-    # transition describing the context (e.g. event, from, to) can be accessed
-    # as well.  This additional argument is only passed if the callback allows
-    # for it.
+    # Callbacks can require that the machine be transitioning from and to
+    # specific states.  These requirements use a Hash syntax to map beginning
+    # states to ending states.  For example,
     # 
-    # For example,
+    #   before_transition :parked =&gt; :idling, :idling =&gt; :first_gear, :do =&gt; :set_alarm
     # 
-    #   class Vehicle
-    #     # Only specifies one parameter (the object being transitioned)
-    #     before_transition :to =&gt; :parked, :do =&gt; lambda {|vehicle| vehicle.set_alarm}
-    #     
-    #     # Specifies 2 parameters (object being transitioned and actual transition)
-    #     before_transition :to =&gt; :parked, :do =&gt; lambda {|vehicle, transition| vehicle.set_alarm(transition)}
-    #   end
+    # In this case, the +set_alarm+ callback will only be called if the machine
+    # is transitioning from +parked+ to +idling+ or from +idling+ to +parked+.
     # 
-    # *Note* that the object in the callback will only be passed in as an
-    # argument if callbacks are configured to *not* be bound to the object
-    # involved.  This is the default and may change on a per-integration basis.
+    # To help define state requirements, a set of helpers are available for
+    # slightly more complex matching:
+    # * &lt;tt&gt;all&lt;/tt&gt; - Matches every state/event in the machine
+    # * &lt;tt&gt;all - [:parked, :idling, ...]&lt;/tt&gt; - Matches every state/event except those specified
+    # * &lt;tt&gt;any&lt;/tt&gt; - An alias for +all+ (matches every state/event in the machine)
+    # * &lt;tt&gt;same&lt;/tt&gt; - Matches the same state being transitioned from
     # 
-    # See StateMachine::Transition for more information about the
-    # attributes available on the transition.
+    # Examples:
     # 
-    # == Examples
+    #   before_transition :parked =&gt; [:idling, :first_gear], :do =&gt; ...     # Matches from parked to idling or first_gear
+    #   before_transition all - [:parked, :idling] =&gt; :idling, :do =&gt; ...   # Matches from every state except parked and idling to idling
+    #   before_transition all =&gt; :parked, :do =&gt; ...                        # Matches all states to parked
+    #   before_transition any =&gt; same, :do =&gt; ...                           # Matches every loopback
     # 
-    # Below is an example of a class with one state machine and various types
-    # of +before+ transitions defined for it:
+    # == Event requirements
     # 
-    #   class Vehicle
-    #     state_machine do
-    #       # Before all transitions
-    #       before_transition :update_dashboard
-    #       
-    #       # Before specific transition:
-    #       before_transition :to =&gt; :parked, :from =&gt; [:first_gear, :idling], :on =&gt; :park, :do =&gt; :take_off_seatbelt
-    #       
-    #       # With conditional callback:
-    #       before_transition :to =&gt; :parked, :do =&gt; :take_off_seatbelt, :if =&gt; :seatbelt_on?
-    #       
-    #       # Using :except counterparts:
-    #       before_transition :except_to =&gt; :stalled, :except_from =&gt; :stalled, :except_on =&gt; :crash, :do =&gt; :update_dashboard
-    #       ...
-    #     end
-    #   end
+    # In addition to state requirements, an event requirement can be defined so
+    # that the callback is only invoked on specific events using the +on+
+    # option.  This can also use the same matcher helpers as the state
+    # requirements.
     # 
-    # As can be seen, any number of transitions can be created using various
-    # combinations of configuration options.
-    def before_transition(options = {}, &amp;block)
-      add_callback(:before, options.is_a?(Hash) ? options : {:do =&gt; options}, &amp;block)
-    end
-    
-    # Creates a callback that will be invoked *after* a transition is
-    # performed, so long as the given configuration options match the transition.
-    # Each part of the transition (event, to state, from state) must match
-    # in order for the callback to get invoked.
+    # Examples:
+    # 
+    #   before_transition :on =&gt; :ignite, :do =&gt; ...                        # Matches only on ignite
+    #   before_transition :on =&gt; all - :ignite, :do =&gt; ...                  # Matches on every event except ignite
+    #   before_transition :parked =&gt; :idling, :on =&gt; :ignite, :do =&gt; ...    # Matches from parked to idling on ignite
+    # 
+    # == Verbose Requirements
+    # 
+    # Requirements can also be defined using verbose options rather than the
+    # implicit Hash syntax and helper methods described above.
     # 
     # Configuration options:
     # * &lt;tt&gt;:from&lt;/tt&gt; - One or more states being transitioned from.  If none
@@ -816,8 +778,18 @@ module StateMachine
     # * &lt;tt&gt;:except_from&lt;/tt&gt; - One or more states *not* being transitioned from
     # * &lt;tt&gt;:except_to&lt;/tt&gt; - One more states *not* being transitioned to
     # * &lt;tt&gt;:except_on&lt;/tt&gt; - One or more events that *did not* fire the transition
-    # * &lt;tt&gt;:do&lt;/tt&gt; - The callback to invoke when a transition matches. This
-    #   can be a method, proc or string.
+    # 
+    # Examples:
+    # 
+    #   before_transition :from =&gt; :ignite, :to =&gt; :idling, :on =&gt; :park, :do =&gt; ...
+    #   before_transition :except_from =&gt; :ignite, :except_to =&gt; :idling, :except_on =&gt; :park, :do =&gt; ...
+    # 
+    # == Conditions
+    # 
+    # In addition to the state/event requirements, a condition can also be
+    # defined to help determine whether the callback should be invoked.
+    # 
+    # Configuration options:
     # * &lt;tt&gt;:if&lt;/tt&gt; - A method, proc or string to call to determine if the
     #   callback should occur (e.g. :if =&gt; :allow_callbacks, or
     #   :if =&gt; lambda {|user| user.signup_step &gt; 2}). The method, proc or string
@@ -827,40 +799,26 @@ module StateMachine
     #   :unless =&gt; lambda {|user| user.signup_step &lt;= 2}). The method, proc or
     #   string should return or evaluate to a true or false value. 
     # 
-    # The +except+ group of options (+except_to+, +exception_from+, and
-    # +except_on+) acts as the +unless+ equivalent of their counterparts (+to+,
-    # +from+, and +on+, respectively)
-    # 
-    # == The callback
+    # Examples:
     # 
-    # When defining additional configuration options, callbacks must be defined
-    # in either the :do option or as a block.  For example,
+    #   before_transition :parked =&gt; :idling, :if =&gt; :moving?
+    #   before_transition :on =&gt; :ignite, :unless =&gt; :seatbelt_on?
     # 
-    #   class Vehicle
-    #     state_machine do
-    #       after_transition :to =&gt; :parked, :do =&gt; :set_alarm
-    #       after_transition :to =&gt; :parked do |vehicle, transition, result|
-    #         vehicle.set_alarm
-    #       end
-    #       ...
-    #     end
-    #   end
-    # 
-    # === Accessing the transition / result
+    # === Accessing the transition
     # 
     # In addition to passing the object being transitioned, the actual
-    # transition describing the context (e.g. event, from, to) and the result
-    # from calling the object's action can be optionally passed as well.  These
-    # additional arguments are only passed if the callback allows for it.
+    # transition describing the context (e.g. event, from, to) can be accessed
+    # as well.  This additional argument is only passed if the callback allows
+    # for it.
     # 
     # For example,
     # 
     #   class Vehicle
     #     # Only specifies one parameter (the object being transitioned)
-    #     after_transition :to =&gt; :parked, :do =&gt; lambda {|vehicle| vehicle.set_alarm}
+    #     before_transition :to =&gt; :parked, :do =&gt; lambda {|vehicle| vehicle.set_alarm}
     #     
-    #     # Specifies 3 parameters (object being transitioned, transition, and action result)
-    #     after_transition :to =&gt; :parked, :do =&gt; lambda {|vehicle, transition, result| vehicle.set_alarm(transition) if result}
+    #     # Specifies 2 parameters (object being transitioned and actual transition)
+    #     before_transition :to =&gt; :parked, :do =&gt; lambda {|vehicle, transition| vehicle.set_alarm(transition)}
     #   end
     # 
     # *Note* that the object in the callback will only be passed in as an
@@ -872,28 +830,37 @@ module StateMachine
     # 
     # == Examples
     # 
-    # Below is an example of a model with one state machine and various types
-    # of +after+ transitions defined for it:
+    # Below is an example of a class with one state machine and various types
+    # of +before+ transitions defined for it:
     # 
     #   class Vehicle
     #     state_machine do
-    #       # After all transitions
-    #       after_transition :update_dashboard
+    #       # Before all transitions
+    #       before_transition :update_dashboard
     #       
-    #       # After specific transition:
-    #       after_transition :to =&gt; :parked, :from =&gt; [:first_gear, :idling], :on =&gt; :park, :do =&gt; :take_off_seatbelt
+    #       # Before specific transition:
+    #       before_transition [:first_gear, :idling] =&gt; :parked, :on =&gt; :park, :do =&gt; :take_off_seatbelt
     #       
     #       # With conditional callback:
-    #       after_transition :to =&gt; :parked, :do =&gt; :take_off_seatbelt, :if =&gt; :seatbelt_on?
+    #       before_transition :to =&gt; :parked, :do =&gt; :take_off_seatbelt, :if =&gt; :seatbelt_on?
     #       
-    #       # Using :except counterparts:
-    #       after_transition :except_to =&gt; :stalled, :except_from =&gt; :stalled, :except_on =&gt; :crash, :do =&gt; :update_dashboard
+    #       # Using helpers:
+    #       before_transition all - :stalled =&gt; same, :on =&gt; any - :crash, :do =&gt; :update_dashboard
     #       ...
     #     end
     #   end
     # 
     # As can be seen, any number of transitions can be created using various
     # combinations of configuration options.
+    def before_transition(options = {}, &amp;block)
+      add_callback(:before, options.is_a?(Hash) ? options : {:do =&gt; options}, &amp;block)
+    end
+    
+    # Creates a callback that will be invoked *after* a transition is
+    # performed so long as the given requirements match the transition.
+    # 
+    # See +before_transition+ for a description of the possible configurations
+    # for defining callbacks.
     def after_transition(options = {}, &amp;block)
       add_callback(:after, options.is_a?(Hash) ? options : {:do =&gt; options}, &amp;block)
     end</diff>
      <filename>lib/state_machine/machine.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,11 +1,11 @@
 class Switch
   state_machine do
     event :turn_on do
-      transition :to =&gt; 'on', :from =&gt; 'off'
+      transition all =&gt; :on
     end
     
     event :turn_off do
-      transition :to =&gt; 'off', :from =&gt; 'on'
+      transition all =&gt; :off
     end
   end
 end</diff>
      <filename>test/classes/switch.rb</filename>
    </modified>
    <modified>
      <diff>@@ -9,15 +9,15 @@ class AutoShop
   end
   
   state_machine :initial =&gt; :available do
-    after_transition :from =&gt; :available, :do =&gt; :increment_customers
-    after_transition :from =&gt; :busy, :do =&gt; :decrement_customers
+    after_transition :available =&gt; any, :do =&gt; :increment_customers
+    after_transition :busy =&gt; any, :do =&gt; :decrement_customers
     
     event :tow_vehicle do
-      transition :to =&gt; :busy, :from =&gt; :available
+      transition :available =&gt; :busy
     end
     
     event :fix_vehicle do
-      transition :to =&gt; :available, :from =&gt; :busy
+      transition :busy =&gt; :available
     end
   end
   
@@ -51,56 +51,54 @@ class Vehicle
   
   # Defines the state machine for the state of the vehicled
   state_machine :initial =&gt; lambda {|vehicle| vehicle.force_idle ? :idling : :parked}, :action =&gt; :save do
-    before_transition :from =&gt; :parked, :do =&gt; :put_on_seatbelt
-    before_transition :to =&gt; :stalled, :do =&gt; :increase_insurance_premium
-    after_transition :to =&gt; :parked, :do =&gt; lambda {|vehicle| vehicle.seatbelt_on = false}
+    before_transition :parked =&gt; any, :do =&gt; :put_on_seatbelt
+    before_transition any =&gt; :stalled, :do =&gt; :increase_insurance_premium
+    after_transition any =&gt; :parked, :do =&gt; lambda {|vehicle| vehicle.seatbelt_on = false}
     after_transition :on =&gt; :crash, :do =&gt; :tow
     after_transition :on =&gt; :repair, :do =&gt; :fix
     
     # Callback tracking for initial state callbacks
-    after_transition :to =&gt; :parked, :do =&gt; lambda {|vehicle| vehicle.callbacks &lt;&lt; 'before_enter_parked'}
-    before_transition :to =&gt; :idling, :do =&gt; lambda {|vehicle| vehicle.callbacks &lt;&lt; 'before_enter_idling'}
+    after_transition any =&gt; :parked, :do =&gt; lambda {|vehicle| vehicle.callbacks &lt;&lt; 'before_enter_parked'}
+    before_transition any =&gt; :idling, :do =&gt; lambda {|vehicle| vehicle.callbacks &lt;&lt; 'before_enter_idling'}
     
     event :park do
-      transition :to =&gt; :parked, :from =&gt; [:idling, :first_gear]
+      transition [:idling, :first_gear] =&gt; :parked
     end
     
     event :ignite do
-      transition :to =&gt; :stalled, :from =&gt; :stalled
-      transition :to =&gt; :idling, :from =&gt; :parked
+      transition :stalled =&gt; :stalled
+      transition :parked =&gt; :idling
     end
     
     event :idle do
-      transition :to =&gt; :idling, :from =&gt; :first_gear
+      transition :first_gear =&gt; :idling
     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
+      transition :idling =&gt; :first_gear, :first_gear =&gt; :second_gear, :second_gear =&gt; :third_gear
     end
     
     event :shift_down do
-      transition :to =&gt; :second_gear, :from =&gt; :third_gear
-      transition :to =&gt; :first_gear, :from =&gt; :second_gear
+      transition :third_gear =&gt; :second_gear
+      transition :second_gear =&gt; :first_gear
     end
     
     event :crash do
-      transition :to =&gt; :stalled, :from =&gt; [:first_gear, :second_gear, :third_gear], :if =&gt; lambda {|vehicle| vehicle.auto_shop.available?}
+      transition [:first_gear, :second_gear, :third_gear] =&gt; :stalled, :if =&gt; lambda {|vehicle| vehicle.auto_shop.available?}
     end
     
     event :repair do
-      transition :to =&gt; :parked, :from =&gt; :stalled, :if =&gt; :auto_shop_busy?
+      transition :stalled =&gt; :parked, :if =&gt; :auto_shop_busy?
     end
   end
   
   state_machine :insurance_state, :initial =&gt; :inactive, :namespace =&gt; 'insurance' do
     event :buy do
-      transition :to =&gt; :active, :from =&gt; :inactive
+      transition :inactive =&gt; :active
     end
     
     event :cancel do
-      transition :to =&gt; :inactive, :from =&gt; :active
+      transition :active =&gt; :inactive
     end
   end
   
@@ -142,19 +140,19 @@ end
 class Car &lt; Vehicle
   state_machine do
     event :reverse do
-      transition :to =&gt; :backing_up, :from =&gt; [:parked, :idling, :first_gear]
+      transition [:parked, :idling, :first_gear] =&gt; :backing_up
     end
     
     event :park do
-      transition :to =&gt; :parked, :from =&gt; :backing_up
+      transition :backing_up =&gt; :parked
     end
     
     event :idle do
-      transition :to =&gt; :idling, :from =&gt; :backing_up
+      transition :backing_up =&gt; :idling
     end
     
     event :shift_up do
-      transition :to =&gt; :first_gear, :from =&gt; :backing_up
+      transition :backing_up =&gt; :first_gear
     end
   end
 end
@@ -166,9 +164,7 @@ end
 class TrafficLight
   state_machine :initial =&gt; :stop do
     event :cycle do
-      transition :to =&gt; :proceed, :from =&gt; :stop
-      transition :to =&gt; :caution, :from =&gt; :proceed
-      transition :to =&gt; :stop, :from =&gt; :caution
+      transition :stop =&gt; :proceed, :proceed=&gt; :caution, :caution =&gt; :stop
     end
     
     state :stop do</diff>
      <filename>test/functional/state_machine_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -10,9 +10,8 @@ class CallbackTest &lt; Test::Unit::TestCase
     assert_nothing_raised { StateMachine::Callback.new(:do =&gt; :run) }
   end
   
-  def test_should_raise_exception_if_invalid_option_specified
-    exception = assert_raise(ArgumentError) { StateMachine::Callback.new(:do =&gt; :run, :invalid =&gt; true) }
-    assert_match 'Invalid key(s): invalid', exception.message
+  def test_should_not_raise_exception_if_implicit_option_specified
+    assert_nothing_raised { StateMachine::Callback.new(:do =&gt; :run, :invalid =&gt; true) }
   end
   
   def test_should_not_bind_to_objects
@@ -33,8 +32,8 @@ class CallbackByDefaultTest &lt; Test::Unit::TestCase
   
   def test_should_have_a_guard_with_all_matcher_requirements
     assert_equal StateMachine::AllMatcher.instance, @callback.guard.event_requirement
-    assert_equal StateMachine::AllMatcher.instance, @callback.guard.state_requirement[:from]
-    assert_equal StateMachine::AllMatcher.instance, @callback.guard.state_requirement[:to]
+    assert_equal StateMachine::AllMatcher.instance, @callback.guard.state_requirements.first[:from]
+    assert_equal StateMachine::AllMatcher.instance, @callback.guard.state_requirements.first[:to]
   end
   
   def test_should_not_bind_to_the_object
@@ -57,7 +56,7 @@ class CallbackWithOnlyMethodTest &lt; Test::Unit::TestCase
   end
 end
 
-class CallbackWithRequirementsTest &lt; Test::Unit::TestCase
+class CallbackWithExplicitRequirementsTest &lt; Test::Unit::TestCase
   def setup
     @object = Object.new
     @callback = StateMachine::Callback.new(:from =&gt; :parked, :to =&gt; :idling, :on =&gt; :ignite, :do =&gt; lambda {true})
@@ -88,6 +87,37 @@ class CallbackWithRequirementsTest &lt; Test::Unit::TestCase
   end
 end
 
+class CallbackWithImplicitRequirementsTest &lt; Test::Unit::TestCase
+  def setup
+    @object = Object.new
+    @callback = StateMachine::Callback.new(:parked =&gt; :idling, :on =&gt; :ignite, :do =&gt; lambda {true})
+  end
+  
+  def test_should_call_with_empty_context
+    assert @callback.call(@object, {})
+  end
+  
+  def test_should_not_call_if_from_not_included
+    assert !@callback.call(@object, :from =&gt; :idling)
+  end
+  
+  def test_should_not_call_if_to_not_included
+    assert !@callback.call(@object, :to =&gt; :parked)
+  end
+  
+  def test_should_not_call_if_on_not_included
+    assert !@callback.call(@object, :on =&gt; :park)
+  end
+  
+  def test_should_call_if_all_requirements_met
+    assert @callback.call(@object, :from =&gt; :parked, :to =&gt; :idling, :on =&gt; :ignite)
+  end
+  
+  def test_should_include_in_known_states
+    assert_equal [:parked, :idling], @callback.known_states
+  end
+end
+
 class CallbackWithIfConditionTest &lt; Test::Unit::TestCase
   def setup
     @object = Object.new</diff>
      <filename>test/unit/callback_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -54,7 +54,7 @@ class EventTest &lt; Test::Unit::TestCase
   def setup
     @machine = StateMachine::Machine.new(Class.new)
     @event = StateMachine::Event.new(@machine, :ignite)
-    @event.transition :to =&gt; :idling, :from =&gt; :parked
+    @event.transition :parked =&gt; :idling
   end
   
   def test_should_allow_changing_machine
@@ -63,6 +63,16 @@ class EventTest &lt; Test::Unit::TestCase
     assert_equal new_machine, @event.machine
   end
   
+  def test_should_provide_matcher_helpers_during_initialization
+    matchers = []
+    
+    @event.instance_eval do
+      matchers = [all, any, same]
+    end
+    
+    assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
+  end
+  
   def test_should_use_pretty_inspect
     assert_match &quot;#&lt;StateMachine::Event name=:ignite transitions=[:parked =&gt; :idling]&gt;&quot;, @event.inspect
   end
@@ -99,8 +109,8 @@ class EventTransitionsTest &lt; Test::Unit::TestCase
     @event = StateMachine::Event.new(@machine, :ignite)
   end
   
-  def test_should_raise_exception_if_invalid_option_specified
-    assert_raise(ArgumentError) {@event.transition(:invalid =&gt; true)}
+  def test_should_not_raise_exception_if_implicit_option_specified
+    assert_nothing_raised {@event.transition(:invalid =&gt; true)}
   end
   
   def test_should_not_allow_on_option
@@ -131,11 +141,11 @@ class EventTransitionsTest &lt; Test::Unit::TestCase
   end
   
   def test_should_allow_transitioning_from_a_single_state
-    assert @event.transition(:to =&gt; :idling, :from =&gt; :parked)
+    assert @event.transition(:parked =&gt; :idling)
   end
   
   def test_should_allow_transitioning_from_multiple_states
-    assert @event.transition(:to =&gt; :idling, :from =&gt; [:parked, :idling])
+    assert @event.transition([:parked, :idling] =&gt; :idling)
   end
   
   def test_should_have_transitions
@@ -196,8 +206,8 @@ class EventWithTransitionsTest &lt; Test::Unit::TestCase
     @klass = Class.new
     @machine = StateMachine::Machine.new(@klass)
     @event = StateMachine::Event.new(@machine, :ignite)
-    @event.transition(:to =&gt; :idling, :from =&gt; :parked)
-    @event.transition(:to =&gt; :idling, :except_from =&gt; :first_gear)
+    @event.transition(:parked =&gt; :idling)
+    @event.transition(:first_gear =&gt; :idling)
   end
   
   def test_should_include_all_transition_states_in_known_states
@@ -206,10 +216,14 @@ class EventWithTransitionsTest &lt; Test::Unit::TestCase
   
   def test_should_include_new_transition_states_after_calling_known_states
     @event.known_states
-    @event.transition(:to =&gt; :idling, :from =&gt; :stalled)
+    @event.transition(:stalled =&gt; :idling)
     
     assert_equal [:parked, :idling, :first_gear, :stalled], @event.known_states
   end
+  
+  def test_should_use_pretty_inspect
+    assert_match &quot;#&lt;StateMachine::Event name=:ignite transitions=[:parked =&gt; :idling, :first_gear =&gt; :idling]&gt;&quot;, @event.inspect
+  end
 end
 
 class EventWithoutMatchingTransitionsTest &lt; Test::Unit::TestCase
@@ -219,7 +233,7 @@ class EventWithoutMatchingTransitionsTest &lt; Test::Unit::TestCase
     @machine.state :parked, :idling
     
     @event = StateMachine::Event.new(@machine, :ignite)
-    @event.transition(:to =&gt; :idling, :from =&gt; :parked)
+    @event.transition(:parked =&gt; :idling)
     
     @object = @klass.new
     @object.state = 'idling'
@@ -255,7 +269,7 @@ class EventWithMatchingDisabledTransitionsTest &lt; Test::Unit::TestCase
     @machine.state :parked, :idling
     
     @event = StateMachine::Event.new(@machine, :ignite)
-    @event.transition(:to =&gt; :idling, :from =&gt; :parked, :if =&gt; lambda {false})
+    @event.transition(:parked =&gt; :idling, :if =&gt; lambda {false})
     
     @object = @klass.new
     @object.state = 'parked'
@@ -286,7 +300,7 @@ class EventWithMatchingEnabledTransitionsTest &lt; Test::Unit::TestCase
     @machine.state :parked, :idling
     
     @event = StateMachine::Event.new(@machine, :ignite)
-    @event.transition(:to =&gt; :idling, :from =&gt; :parked)
+    @event.transition(:parked =&gt; :idling)
     
     @object = @klass.new
     @object.state = 'parked'
@@ -353,11 +367,11 @@ class EventWithTransitionWithNilToStateTest &lt; Test::Unit::TestCase
   def setup
     @klass = Class.new
     @machine = StateMachine::Machine.new(@klass)
-    @machine.state :parked, :value =&gt; nil
+    @machine.state nil
     @machine.state :idling
     
     @event = StateMachine::Event.new(@machine, :park)
-    @event.transition(:from =&gt; :idling, :to =&gt; :parked)
+    @event.transition(:idling =&gt; nil)
     
     @object = @klass.new
     @object.state = 'idling'
@@ -392,8 +406,8 @@ class EventWithMultipleTransitionsTest &lt; Test::Unit::TestCase
     @machine.state :parked, :idling
     
     @event = StateMachine::Event.new(@machine, :ignite)
-    @event.transition(:to =&gt; :idling, :from =&gt; :idling)
-    @event.transition(:to =&gt; :idling, :from =&gt; :parked) # This one should get used
+    @event.transition(:idling =&gt; :idling)
+    @event.transition(:parked =&gt; :idling) # This one should get used
     
     @object = @klass.new
     @object.state = 'parked'
@@ -437,8 +451,8 @@ begin
       states.each {|state| graph.add_node(state.to_s)}
       
       @event = StateMachine::Event.new(@machine , :park)
-      @event.transition :from =&gt; :idling, :to =&gt; :parked
-      @event.transition :from =&gt; :first_gear, :to =&gt; :parked
+      @event.transition :parked =&gt; :idling
+      @event.transition :first_gear =&gt; :parked
       @event.transition :except_from =&gt; :parked, :to =&gt; :parked
       
       @edges = @event.draw(graph)</diff>
      <filename>test/unit/event_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,12 +2,11 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
 
 class GuardTest &lt; Test::Unit::TestCase
   def setup
-    @guard = StateMachine::Guard.new(:to =&gt; :idling, :from =&gt; :parked)
+    @guard = StateMachine::Guard.new(:from =&gt; :parked, :to =&gt; :idling)
   end
   
-  def test_should_raise_exception_if_invalid_option_specified
-    exception = assert_raise(ArgumentError) { StateMachine::Guard.new(:invalid =&gt; true) }
-    assert_equal 'Invalid key(s): invalid', exception.message
+  def test_should_not_raise_exception_if_implicit_option_specified
+    assert_nothing_raised { StateMachine::Guard.new(:invalid =&gt; true) }
   end
   
   def test_should_not_have_an_if_condition
@@ -17,6 +16,10 @@ class GuardTest &lt; Test::Unit::TestCase
   def test_should_not_have_an_unless_condition
     assert_nil @guard.unless_condition
   end
+  
+  def test_should_have_a_state_requirement
+    assert_equal 1, @guard.state_requirements.length
+  end
 end
 
 class GuardWithNoRequirementsTest &lt; Test::Unit::TestCase
@@ -30,11 +33,11 @@ class GuardWithNoRequirementsTest &lt; Test::Unit::TestCase
   end
   
   def test_should_use_all_matcher_for_from_state_requirement
-    assert_equal StateMachine::AllMatcher.instance, @guard.state_requirement[:from]
+    assert_equal StateMachine::AllMatcher.instance, @guard.state_requirements.first[:from]
   end
   
   def test_should_use_all_matcher_for_to_state_requirement
-    assert_equal StateMachine::AllMatcher.instance, @guard.state_requirement[:to]
+    assert_equal StateMachine::AllMatcher.instance, @guard.state_requirements.first[:to]
   end
   
   def test_should_match_nil_query
@@ -48,6 +51,14 @@ class GuardWithNoRequirementsTest &lt; Test::Unit::TestCase
   def test_should_match_non_empty_query
     assert @guard.matches?(@object, :to =&gt; :idling, :from =&gt; :parked, :on =&gt; :ignite)
   end
+  
+  def test_should_include_all_requirements_in_match
+    match = @guard.match(@object, nil)
+    
+    assert_equal @guard.state_requirements.first[:from], match[:from]
+    assert_equal @guard.state_requirements.first[:to], match[:to]
+    assert_equal @guard.event_requirement, match[:on]
+  end
 end
 
 class GuardWithFromRequirementTest &lt; Test::Unit::TestCase
@@ -57,7 +68,7 @@ class GuardWithFromRequirementTest &lt; Test::Unit::TestCase
   end
   
   def test_should_use_a_whitelist_matcher
-    assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirement[:from]
+    assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirements.first[:from]
   end
   
   def test_should_match_if_not_specified
@@ -87,6 +98,11 @@ class GuardWithFromRequirementTest &lt; Test::Unit::TestCase
   def test_should_be_included_in_known_states
     assert_equal [:parked], @guard.known_states
   end
+  
+  def test_should_include_requirement_in_match
+    match = @guard.match(@object, :from =&gt; :parked)
+    assert_equal @guard.state_requirements.first[:from], match[:from]
+  end
 end
 
 class GuardWithMultipleFromRequirementsTest &lt; Test::Unit::TestCase
@@ -115,7 +131,7 @@ class GuardWithToRequirementTest &lt; Test::Unit::TestCase
   end
   
   def test_should_use_a_whitelist_matcher
-    assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirement[:to]
+    assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirements.first[:to]
   end
   
   def test_should_match_if_not_specified
@@ -145,6 +161,11 @@ class GuardWithToRequirementTest &lt; Test::Unit::TestCase
   def test_should_be_included_in_known_states
     assert_equal [:idling], @guard.known_states
   end
+  
+  def test_should_include_requirement_in_match
+    match = @guard.match(@object, :to =&gt; :idling)
+    assert_equal @guard.state_requirements.first[:to], match[:to]
+  end
 end
 
 class GuardWithMultipleToRequirementsTest &lt; Test::Unit::TestCase
@@ -203,6 +224,11 @@ class GuardWithOnRequirementTest &lt; Test::Unit::TestCase
   def test_should_not_be_included_in_known_states
     assert_equal [], @guard.known_states
   end
+  
+  def test_should_include_requirement_in_match
+    match = @guard.match(@object, :on =&gt; :ignite)
+    assert_equal @guard.event_requirement, match[:on]
+  end
 end
 
 class GuardWithMultipleOnRequirementsTest &lt; Test::Unit::TestCase
@@ -227,7 +253,7 @@ class GuardWithExceptFromRequirementTest &lt; Test::Unit::TestCase
   end
   
   def test_should_use_a_blacklist_matcher
-    assert_instance_of StateMachine::BlacklistMatcher, @guard.state_requirement[:from]
+    assert_instance_of StateMachine::BlacklistMatcher, @guard.state_requirements.first[:from]
   end
   
   def test_should_match_if_not_included
@@ -281,7 +307,7 @@ class GuardWithExceptToRequirementTest &lt; Test::Unit::TestCase
   end
   
   def test_should_use_a_blacklist_matcher
-    assert_instance_of StateMachine::BlacklistMatcher, @guard.state_requirement[:to]
+    assert_instance_of StateMachine::BlacklistMatcher, @guard.state_requirements.first[:to]
   end
   
   def test_should_match_if_not_included
@@ -425,6 +451,10 @@ class GuardWithDifferentRequirementsTest &lt; Test::Unit::TestCase
     assert !@guard.matches?(@object, :on =&gt; :park)
   end
   
+  def test_should_be_nil_if_unmatched
+    assert_nil @guard.match(@object, :from =&gt; :parked, :to =&gt; :idling, :on =&gt; :park)
+  end
+  
   def test_should_include_all_known_states
     assert_equal [:parked, :idling], @guard.known_states
   end
@@ -462,6 +492,129 @@ class GuardWithNilRequirementsTest &lt; Test::Unit::TestCase
   end
 end
 
+class GuardWithImplicitRequirementTest &lt; Test::Unit::TestCase
+  def setup
+    @guard = StateMachine::Guard.new(:parked =&gt; :idling, :on =&gt; :ignite)
+  end
+  
+  def test_should_create_an_event_requirement
+    assert_instance_of StateMachine::WhitelistMatcher, @guard.event_requirement
+    assert_equal [:ignite], @guard.event_requirement.values
+  end
+  
+  def test_should_use_a_whitelist_from_matcher
+    assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirements.first[:from]
+  end
+  
+  def test_should_use_a_whitelist_to_matcher
+    assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirements.first[:to]
+  end
+end
+
+class GuardWithMultipleImplicitRequirementsTest &lt; Test::Unit::TestCase
+  def setup
+    @object = Object.new
+    @guard = StateMachine::Guard.new(:parked =&gt; :idling, :idling =&gt; :first_gear, :on =&gt; :ignite)
+  end
+  
+  def test_should_create_multiple_state_requirements
+    assert_equal 2, @guard.state_requirements.length
+  end
+  
+  def test_should_not_match_event_as_state_requirement
+    assert !@guard.matches?(@object, :from =&gt; :on, :to =&gt; :ignite)
+  end
+  
+  def test_should_match_if_from_included_in_any
+    assert @guard.matches?(@object, :from =&gt; :parked)
+    assert @guard.matches?(@object, :from =&gt; :idling)
+  end
+  
+  def test_should_not_match_if_from_not_included_in_any
+    assert !@guard.matches?(@object, :from =&gt; :first_gear)
+  end
+  
+  def test_should_match_if_to_included_in_any
+    assert @guard.matches?(@object, :to =&gt; :idling)
+    assert @guard.matches?(@object, :to =&gt; :first_gear)
+  end
+  
+  def test_should_not_match_if_to_not_included_in_any
+    assert !@guard.matches?(@object, :to =&gt; :parked)
+  end
+  
+  def test_should_match_if_all_options_match
+    assert @guard.matches?(@object, :from =&gt; :parked, :to =&gt; :idling, :on =&gt; :ignite)
+    assert @guard.matches?(@object, :from =&gt; :idling, :to =&gt; :first_gear, :on =&gt; :ignite)
+  end
+  
+  def test_should_not_match_if_any_options_do_not_match
+    assert !@guard.matches?(@object, :from =&gt; :parked, :to =&gt; :idling, :on =&gt; :park)
+    assert !@guard.matches?(@object, :from =&gt; :parked, :to =&gt; :first_gear, :on =&gt; :park)
+  end
+  
+  def test_should_include_all_known_states
+    assert_equal [:first_gear, :idling, :parked], @guard.known_states.sort_by {|state| state.to_s}
+  end
+  
+  def test_should_not_duplicate_known_statse
+    guard = StateMachine::Guard.new(:parked =&gt; :idling, :first_gear =&gt; :idling)
+    assert_equal [:first_gear, :idling, :parked], guard.known_states.sort_by {|state| state.to_s}
+  end
+end
+
+class GuardWithImplicitFromRequirementMatcherTest &lt; Test::Unit::TestCase
+  def setup
+    @matcher = StateMachine::BlacklistMatcher.new(:parked)
+    @guard = StateMachine::Guard.new(@matcher =&gt; :idling)
+  end
+  
+  def test_should_not_convert_from_to_whitelist_matcher
+    assert_equal @matcher, @guard.state_requirements.first[:from]
+  end
+  
+  def test_should_convert_to_to_whitelist_matcher
+    assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirements.first[:to]
+  end
+end
+
+class GuardWithImplicitToRequirementMatcherTest &lt; Test::Unit::TestCase
+  def setup
+    @matcher = StateMachine::BlacklistMatcher.new(:idling)
+    @guard = StateMachine::Guard.new(:parked =&gt; @matcher)
+  end
+  
+  def test_should_convert_from_to_whitelist_matcher
+    assert_instance_of StateMachine::WhitelistMatcher, @guard.state_requirements.first[:from]
+  end
+  
+  def test_should_not_convert_to_to_whitelist_matcher
+    assert_equal @matcher, @guard.state_requirements.first[:to]
+  end
+end
+
+class GuardWithImplicitAndExplicitRequirementsTest &lt; Test::Unit::TestCase
+  def setup
+    @guard = StateMachine::Guard.new(:parked =&gt; :idling, :from =&gt; :parked)
+  end
+  
+  def test_should_create_multiple_requirements
+    assert_equal 2, @guard.state_requirements.length
+  end
+  
+  def test_should_create_implicit_requirements_for_implicit_options
+    assert(@guard.state_requirements.any? do |state_requirement|
+      state_requirement[:from].values == [:parked] &amp;&amp; state_requirement[:to].values == [:idling]
+    end)
+  end
+  
+  def test_should_create_implicit_requirements_for_explicit_options
+    assert(@guard.state_requirements.any? do |state_requirement|
+      state_requirement[:from].values == [:from] &amp;&amp; state_requirement[:to].values == [:parked]
+    end)
+  end
+end
+
 class GuardWithIfConditionalTest &lt; Test::Unit::TestCase
   def setup
     @object = Object.new
@@ -481,6 +634,11 @@ class GuardWithIfConditionalTest &lt; Test::Unit::TestCase
     guard = StateMachine::Guard.new(:if =&gt; lambda {false})
     assert !guard.matches?(@object)
   end
+  
+  def test_should_be_nil_if_unmatched
+    guard = StateMachine::Guard.new(:if =&gt; lambda {false})
+    assert_nil guard.match(@object)
+  end
 end
 
 class GuardWithUnlessConditionalTest &lt; Test::Unit::TestCase
@@ -502,6 +660,11 @@ class GuardWithUnlessConditionalTest &lt; Test::Unit::TestCase
     guard = StateMachine::Guard.new(:unless =&gt; lambda {true})
     assert !guard.matches?(@object)
   end
+  
+  def test_should_be_nil_if_unmatched
+    guard = StateMachine::Guard.new(:unless =&gt; lambda {true})
+    assert_nil guard.match(@object)
+  end
 end
 
 class GuardWithConflictingConditionalsTest &lt; Test::Unit::TestCase
@@ -624,6 +787,23 @@ begin
       assert_equal 'parked', @edges.first.instance_variable_get('@xNodeTwo')
     end
   end
+  
+  class GuardDrawingWithNilStateTest &lt; Test::Unit::TestCase
+    def setup
+      @machine = StateMachine::Machine.new(Class.new)
+      
+      graph = GraphViz.new('G')
+      graph.add_node('parked')
+      
+      @guard = StateMachine::Guard.new(:from =&gt; :idling, :to =&gt; nil)
+      @edges = @guard.draw(graph, :park, [nil, :idling])
+    end
+    
+    def test_should_generate_edges_for_each_valid_from_state
+      assert_equal 'idling', @edges.first.instance_variable_get('@xNodeOne')
+      assert_equal 'nil', @edges.first.instance_variable_get('@xNodeTwo')
+    end
+  end
 rescue LoadError
   $stderr.puts 'Skipping GraphViz StateMachine::Guard tests. `gem install ruby-graphviz` and try again.'
 end</diff>
      <filename>test/unit/guard_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -334,6 +334,16 @@ begin
           @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
         end
         
+        def test_should_provide_matcher_helpers
+          matchers = []
+          
+          new_observer(@resource) do
+            matchers = [all, any, same]
+          end
+          
+          assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
+        end
+        
         def test_should_call_before_transition_callback_if_requirements_match
           called = false
           </diff>
      <filename>test/unit/integrations/data_mapper_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -373,6 +373,16 @@ class MachineTest &lt; Test::Unit::TestCase
     
     assert called
   end
+  
+  def test_should_provide_matcher_helpers_during_initialization
+    matchers = []
+    
+    StateMachine::Machine.new(Class.new) do
+      matchers = [all, any, same]
+    end
+    
+    assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
+  end
 end
 
 class MachineAfterBeingCopiedTest &lt; Test::Unit::TestCase
@@ -1029,9 +1039,8 @@ class MachineWithTransitionCallbacksTest &lt; Test::Unit::TestCase
     @object.callbacks = []
   end
   
-  def test_should_raise_exception_if_invalid_option_specified
-    exception = assert_raise(ArgumentError) {@machine.before_transition :invalid =&gt; true, :do =&gt; lambda {}}
-    assert_equal 'Invalid key(s): invalid', exception.message
+  def test_should_not_raise_exception_if_implicit_option_specified
+    assert_nothing_raised {@machine.before_transition :invalid =&gt; true, :do =&gt; lambda {}}
   end
   
   def test_should_raise_exception_if_do_option_not_specified
@@ -1095,6 +1104,14 @@ class MachineWithTransitionCallbacksTest &lt; Test::Unit::TestCase
     assert_equal [:park], @object.callbacks
   end
   
+  def test_should_support_implicit_requirement
+    @machine.before_transition :parked =&gt; :idling, :do =&gt; lambda {|object| object.callbacks &lt;&lt; :parked}
+    @machine.before_transition :idling =&gt; :parked, :do =&gt; lambda {|object| object.callbacks &lt;&lt; :idling}
+    
+    @event.fire(@object)
+    assert_equal [:parked], @object.callbacks
+  end
+  
   def test_should_track_states_defined_in_transition_callbacks
     @machine.before_transition :from =&gt; :parked, :to =&gt; :idling, :do =&gt; lambda {}
     @machine.after_transition :from =&gt; :first_gear, :to =&gt; :second_gear, :do =&gt; lambda {}</diff>
      <filename>test/unit/machine_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,10 +6,6 @@ class NodeCollectionByDefaultTest &lt; Test::Unit::TestCase
   end
   
   def test_should_not_have_any_nodes
-    assert !@collection.any?
-  end
-  
-  def test_should_have_a_zero_length
     assert_equal 0, @collection.length
   end
   </diff>
      <filename>test/unit/node_collection_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,10 +6,6 @@ class StateCollectionByDefaultTest &lt; Test::Unit::TestCase
   end
   
   def test_should_not_have_any_nodes
-    assert !@states.any?
-  end
-  
-  def test_should_have_a_zero_length
     assert_equal 0, @states.length
   end
   </diff>
      <filename>test/unit/state_collection_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>5bdc42294ee11f0c086ecfbf229235896bbbbe4c</id>
    </parent>
  </parents>
  <author>
    <name>Aaron Pfeifer</name>
    <email>aaron.pfeifer@gmail.com</email>
  </author>
  <url>http://github.com/pluginaweek/state_machine/commit/cdec7f2db639f27d714da1dc9191d45710f475f9</url>
  <id>cdec7f2db639f27d714da1dc9191d45710f475f9</id>
  <committed-date>2009-03-02T18:45:08-08:00</committed-date>
  <authored-date>2009-03-02T18:45:08-08:00</authored-date>
  <message>Add simplified transition/callback requirement syntax (and recommend its usage)
Simplify hooking callbacks into loopbacks
Fix nil from/to states not being handled properly</message>
  <tree>16054d4ce06cb0e77884c2696355a15bb9839b21</tree>
  <committer>
    <name>Aaron Pfeifer</name>
    <email>aaron.pfeifer@gmail.com</email>
  </committer>
</commit>
