Class: StateMachines::EventCollection

Inherits:
NodeCollection show all
Defined in:
lib/state_machines/event_collection.rb

Overview

Represents a collection of events in a state machine

Instance Attribute Summary

Attributes inherited from NodeCollection

#machine

Instance Method Summary collapse

Methods inherited from NodeCollection

#<<, #[], #at, #concat, #context, #each, #fetch, #initialize_copy, #keys, #length, #update

Constructor Details

#initialize(machine) ⇒ EventCollection

:nodoc:



4
5
6
# File 'lib/state_machines/event_collection.rb', line 4

def initialize(machine) #:nodoc:
  super(machine, index: [:name, :qualified_name])
end

Instance Method Details

#attribute_transition_for(object, invalidate = false) ⇒ Object

Gets the transition that should be performed for the event stored in the given object’s event attribute. This also takes an additional parameter for automatically invalidating the object if the event or transition are invalid. By default, this is turned off.

Note that if a transition has already been generated for the event, then that transition will be used.

Examples

class Vehicle < ActiveRecord::Base
  state_machine :initial => :parked do
    event :ignite do
      transition :parked => :idling
    end
  end
end

vehicle = Vehicle.new                       # => #<Vehicle id: nil, state: "parked">
events = Vehicle.state_machine.events

vehicle.state_event = nil
events.attribute_transition_for(vehicle)    # => nil # Event isn't defined

vehicle.state_event = 'invalid'
events.attribute_transition_for(vehicle)    # => false # Event is invalid

vehicle.state_event = 'ignite'
events.attribute_transition_for(vehicle)    # => #<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>


114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/state_machines/event_collection.rb', line 114

def attribute_transition_for(object, invalidate = false)
  return unless machine.action

  # TODO, simplify
  machine.read(object, :event_transition) || if event_name = machine.read(object, :event)
                                               if event = self[event_name.to_sym, :name]
                                                 event.transition_for(object) || begin
                                                   # No valid transition: invalidate
                                                   machine.invalidate(object, :event, :invalid_event, [[:state, machine.states.match!(object).human_name(object.class)]]) if invalidate
                                                   false
                                                 end
                                               else
                                                 # Event is unknown: invalidate
                                                 machine.invalidate(object, :event, :invalid) if invalidate
                                                 false
                                               end
                                             end

end

#transitions_for(object, requirements = {}) ⇒ Object

Gets the list of transitions that can be run on the given object.

Valid requirement options:

  • :from - One or more states being transitioned from. If none are specified, then this will be the object’s current state.

  • :to - One or more states being transitioned to. If none are specified, then this will match any to state.

  • :on - One or more events that fire the transition. If none are specified, then this will match any event.

  • :guard - Whether to guard transitions with the if/unless conditionals defined for each one. Default is true.

Examples

class Vehicle
  state_machine :initial => :parked do
    event :park do
      transition :idling => :parked
    end

    event :ignite do
      transition :parked => :idling
    end
  end
end

events = Vehicle.state_machine.events

vehicle = Vehicle.new                             # => #<Vehicle:0xb7c464b0 @state="parked">
events.transitions_for(vehicle)                   # => [#<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>]

vehicle.state = 'idling'
events.transitions_for(vehicle)                   # => [#<StateMachines::Transition attribute=:state event=:park from="idling" from_name=:idling to="parked" to_name=:parked>]

# Search for explicit transitions regardless of the current state
events.transitions_for(vehicle, :from => :parked) # => [#<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>]


81
82
83
# File 'lib/state_machines/event_collection.rb', line 81

def transitions_for(object, requirements = {})
  match(requirements).map { |event| event.transition_for(object, requirements) }.compact
end

#valid_for(object, requirements = {}) ⇒ Object

Gets the list of events that can be fired on the given object.

Valid requirement options:

  • :from - One or more states being transitioned from. If none are specified, then this will be the object’s current state.

  • :to - One or more states being transitioned to. If none are specified, then this will match any to state.

  • :on - One or more events that fire the transition. If none are specified, then this will match any event.

  • :guard - Whether to guard transitions with the if/unless conditionals defined for each one. Default is true.

Examples

class Vehicle
  state_machine :initial => :parked do
    event :park do
      transition :idling => :parked
    end

    event :ignite do
      transition :parked => :idling
    end
  end
end

events = Vehicle.state_machine(:state).events

vehicle = Vehicle.new               # => #<Vehicle:0xb7c464b0 @state="parked">
events.valid_for(vehicle)           # => [#<StateMachines::Event name=:ignite transitions=[:parked => :idling]>]

vehicle.state = 'idling'
events.valid_for(vehicle)           # => [#<StateMachines::Event name=:park transitions=[:idling => :parked]>]


41
42
43
# File 'lib/state_machines/event_collection.rb', line 41

def valid_for(object, requirements = {})
  match(requirements).select { |event| event.can_fire?(object, requirements) }
end