Module: StateMachines::InstanceMethods
- Defined in:
- lib/state_machines/extensions.rb
Instance Method Summary collapse
-
#fire_events(*events) ⇒ Object
Runs one or more events in parallel.
-
#fire_events!(*events) ⇒ Object
Run one or more events in parallel.
Instance Method Details
#fire_events(*events) ⇒ Object
Runs one or more events in parallel. All events will run through the following steps:
-
Before callbacks
-
Persist state
-
Invoke action
-
After callbacks
For example, if two events (for state machines A and B) are run in parallel, the order in which steps are run is:
-
A - Before transition callbacks
-
B - Before transition callbacks
-
A - Persist new state
-
B - Persist new state
-
A - Invoke action
-
B - Invoke action (only if different than A’s action)
-
A - After transition callbacks
-
B - After transition callbacks
Note that multiple events on the same state machine / attribute cannot be run in parallel. If this is attempted, an ArgumentError will be raised.
Halting callbacks
When running multiple events in parallel, special consideration should be taken with regard to how halting within callbacks affects the flow.
For before callbacks, any :halt
error that’s thrown will immediately cancel the perform for all transitions. As a result, it’s possible for one event’s transition to affect the continuation of another.
On the other hand, any :halt
error that’s thrown within an after callback with only affect that event’s transition. Other transitions will continue to run their own callbacks.
Example
class Vehicle
state_machine :initial => :parked do
event :ignite do
transition :parked => :idling
end
event :park do
transition :idling => :parked
end
end
state_machine :alarm_state, :namespace => 'alarm', :initial => :on do
event :enable do
transition all => :active
end
event :disable do
transition all => :off
end
end
end
vehicle = Vehicle.new # => #<Vehicle:0xb7c02850 @state="parked", @alarm_state="active">
vehicle.state # => "parked"
vehicle.alarm_state # => "active"
vehicle.fire_events(:ignite, :disable_alarm) # => true
vehicle.state # => "idling"
vehicle.alarm_state # => "off"
# If any event fails, the entire event chain fails
vehicle.fire_events(:ignite, :enable_alarm) # => false
vehicle.state # => "idling"
vehicle.alarm_state # => "off"
# Exception raised on invalid event
vehicle.fire_events(:park, :invalid) # => StateMachines::InvalidEvent: :invalid is an unknown event
vehicle.state # => "idling"
vehicle.alarm_state # => "off"
100 101 102 |
# File 'lib/state_machines/extensions.rb', line 100 def fire_events(*events) self.class.state_machines.fire_events(self, *events) end |
#fire_events!(*events) ⇒ Object
Run one or more events in parallel. If any event fails to run, then a StateMachines::InvalidTransition exception will be raised.
See StateMachines::InstanceMethods#fire_events for more information.
Example
class Vehicle
state_machine :initial => :parked do
event :ignite do
transition :parked => :idling
end
event :park do
transition :idling => :parked
end
end
state_machine :alarm_state, :namespace => 'alarm', :initial => :active do
event :enable do
transition all => :active
end
event :disable do
transition all => :off
end
end
end
vehicle = Vehicle.new # => #<Vehicle:0xb7c02850 @state="parked", @alarm_state="active">
vehicle.fire_events(:ignite, :disable_alarm) # => true
vehicle.fire_events!(:ignite, :disable_alarm) # => StateMachines::InvalidParallelTransition: Cannot run events in parallel: ignite, disable_alarm
137 138 139 140 |
# File 'lib/state_machines/extensions.rb', line 137 def fire_events!(*events) run_action = [true, false].include?(events.last) ? events.pop : true fire_events(*(events + [run_action])) || fail(StateMachines::InvalidParallelTransition.new(self, events)) end |