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:

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

after_transition(*args, &block) click to toggle source

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
after_transition_failure(*args, &block) click to toggle source

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
around_transition(*args, &block) click to toggle source

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
before_transition(*args, &block) click to toggle source

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

add_transition_callback(type, *args, &block) click to toggle source

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