module StateMachine::Integrations::DataMapper::Observer
Adds support for creating before/after/around/failure transition callbacks within a DataMapper
observer. These callbacks behave very similar to hooks during save/update/destroy/etc., but with the following modifications:
-
Each callback can define a set of transition requirements that must be met in order for the callback to get invoked.
-
An additional transition parameter is available that provides contextual information about the event (see
StateMachine::Transition
for more information)
To define a single observer for multiple state machines:
class StateMachineObserver include DataMapper::Observer observe Vehicle, Switch, Project after_transition do |transition| Audit.log(self, transition) end end
Requirements¶ ↑
To use this feature of the DataMapper
integration, the dm-observer library must be available. This can be installed either directly or indirectly through dm-more. When loading DataMapper
, be sure to load the dm-observer library as well like so:
require 'rubygems' require 'dm-core' require 'dm-observer'
If dm-observer is not available, then this feature will be skipped.
Public Instance Methods
Creates a callback that will be invoked after a transition is performed so long as the given configuration options match the transition.
See before_transition
for a description of the possible configurations for defining callbacks.
# File lib/state_machine/integrations/data_mapper/observer.rb 103 def after_transition(*args, &block) 104 add_transition_callback(:after_transition, *args, &block) 105 end
Creates a callback that will be invoked after a transition failures to be performed so long as the given requirements match the transition.
Example¶ ↑
class Vehicle include DataMapper::Resource property :id, Serial property :state, :String state_machine :initial => :parked do event :ignite do transition :parked => :idling end end end class VehicleObserver after_transition_failure do |transition| # log failure end after_transition_failure :on => :ignite do # log failure end end
See before_transition
for a description of the possible configurations for defining callbacks. Note however that you cannot define the state requirements in these callbacks. You may only define event requirements.
# File lib/state_machine/integrations/data_mapper/observer.rb 174 def after_transition_failure(*args, &block) 175 add_transition_callback(:after_failure, *args, &block) 176 end
Creates a callback that will be invoked around a transition so long as the given requirements match the transition.
Examples¶ ↑
class Vehicle include DataMapper::Resource property :id, Serial property :state, :String state_machine :initial => :parked do event :ignite do transition :parked => :idling end end end class VehicleObserver include DataMapper::Observer observe Vehicle around_transition do |transition, block| # track start time block.call # track end time end end
See before_transition
for a description of the possible configurations for defining callbacks.
# File lib/state_machine/integrations/data_mapper/observer.rb 139 def around_transition(*args, &block) 140 add_transition_callback(:around_transition, *args, &block) 141 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.
See StateMachine::Machine#before_transition
for more information about the various configuration options available.
Examples¶ ↑
class Vehicle include DataMapper::Resource property :id, Serial property :state, :String state_machine :initial => :parked do event :ignite do transition :parked => :idling end end end class VehicleObserver include DataMapper::Observer observe Vehicle before :save do # log message end # Target all state machines before_transition :parked => :idling, :on => :ignite do # put on seatbelt end # Target a specific state machine before_transition :state, any => :idling do # put on seatbelt end # Target all state machines without requirements before_transition do |transition| # log message end end
Note that in each of the above before_transition
callbacks, the callback is executed within the context of the object (i.e. the Vehicle instance being transition). This means that self
refers to the vehicle record within each callback block.
# File lib/state_machine/integrations/data_mapper/observer.rb 93 def before_transition(*args, &block) 94 add_transition_callback(:before_transition, *args, &block) 95 end
Private Instance Methods
Adds the transition callback to a specific machine or all of the state machines for each observed class.
# File lib/state_machine/integrations/data_mapper/observer.rb 181 def add_transition_callback(type, *args, &block) 182 if args.any? && !args.first.is_a?(Hash) 183 # Specific machine(s) being targeted 184 names = args 185 args = args.last.is_a?(Hash) ? [args.pop] : [] 186 else 187 # Target all state machines 188 names = nil 189 end 190 191 # Add the transition callback to each class being observed 192 observing.each do |klass| 193 state_machines = 194 if names 195 names.map {|name| klass.state_machines.fetch(name)} 196 else 197 klass.state_machines.values 198 end 199 200 state_machines.each {|machine| machine.send(type, *args, &block)} 201 end if observing 202 end