Class: StateMachines::Callback

Inherits:
Object
  • Object
show all
Includes:
EvalHelpers
Defined in:
lib/state_machines/callback.rb

Overview

Callbacks represent hooks into objects that allow logic to be triggered before, after, or around a specific set of transitions.

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from EvalHelpers

#evaluate_method, #evaluate_method_with_event_args

Constructor Details

#initialize(type, *args, &block) ⇒ Callback

Creates a new callback that can get called based on the configured options.

In addition to the possible configuration options for branches, the following options can be configured:

  • :bind_to_object - Whether to bind the callback to the object involved. If set to false, the object will be passed as a parameter instead. Default is integration-specific or set to the application default.

  • :terminator - A block/proc that determines what callback results should cause the callback chain to halt (if not using the default throw :halt technique).

More information about how those options affect the behavior of the callback can be found in their attribute definitions.

Raises:

  • (ArgumentError)


125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/state_machines/callback.rb', line 125

def initialize(type, *args, &block)
  @type = type
  raise ArgumentError, 'Type must be :before, :after, :around, or :failure' unless %i[before after around failure].include?(type)

  options = args.last.is_a?(Hash) ? args.pop : {}
  @methods = args
  @methods.concat(Array(options.delete(:do)))
  @methods << block if block_given?
  raise ArgumentError, 'Method(s) for callback must be specified' unless @methods.any?

  options = { bind_to_object: self.class.bind_to_object, terminator: self.class.terminator }.merge(options)

  # Proxy lambda blocks so that they're bound to the object
  bind_to_object = options.delete(:bind_to_object)
  @methods.map! do |method|
    bind_to_object && method.is_a?(Proc) ? bound_method(method) : method
  end

  @terminator = options.delete(:terminator)
  @branch = Branch.new(options)
end

Class Attribute Details

.bind_to_objectObject

Determines whether to automatically bind the callback to the object being transitioned. This only applies to callbacks that are defined as lambda blocks (or Procs). Some integrations, such as DataMapper, handle callbacks by executing them bound to the object involved, while other integrations, such as ActiveRecord, pass the object as an argument to the callback. This can be configured on an application-wide basis by setting this configuration to true or false. The default value is false.

Note that the DataMapper and Sequel integrations automatically configure this value on a per-callback basis, so it does not have to be enabled application-wide.

Examples

When not bound to the object:

class Vehicle
  state_machine do
    before_transition do |vehicle|
      vehicle.set_alarm
    end
  end

  def set_alarm
    ...
  end
end

When bound to the object:

StateMachines::Callback.bind_to_object = true

class Vehicle
  state_machine do
    before_transition do
      self.set_alarm
    end
  end

  def set_alarm
    ...
  end
end


57
58
59
# File 'lib/state_machines/callback.rb', line 57

def bind_to_object
  @bind_to_object
end

.terminatorObject

The application-wide terminator to use for callbacks when not explicitly defined. Terminators determine whether to cancel a callback chain based on the return value of the callback.

See StateMachines::Callback#terminator for more information.



64
65
66
# File 'lib/state_machines/callback.rb', line 64

def terminator
  @terminator
end

Instance Attribute Details

#branchObject (readonly)

The branch that determines whether or not this callback can be invoked based on the context of the transition. The event, from state, and to state must all match in order for the branch to pass.

See StateMachines::Branch for more information.



109
110
111
# File 'lib/state_machines/callback.rb', line 109

def branch
  @branch
end

#terminatorObject (readonly)

An optional block for determining whether to cancel the callback chain based on the return value of the callback. By default, the callback chain never cancels based on the return value (i.e. there is no implicit terminator). Certain integrations, such as ActiveRecord and Sequel, change this default value.

Examples

Canceling the callback chain without a terminator:

class Vehicle
  state_machine do
    before_transition do |vehicle|
      throw :halt
    end
  end
end

Canceling the callback chain with a terminator value of false:

class Vehicle
  state_machine do
    before_transition do |vehicle|
      false
    end
  end
end


102
103
104
# File 'lib/state_machines/callback.rb', line 102

def terminator
  @terminator
end

#typeObject

The type of callback chain this callback is for. This can be one of the following:

  • before

  • after

  • around

  • failure



73
74
75
# File 'lib/state_machines/callback.rb', line 73

def type
  @type
end

Instance Method Details

#call(object, context = {}) ⇒ Object

Runs the callback as long as the transition context matches the branch requirements configured for this callback. If a block is provided, it will be called when the last method has run.

If a terminator has been configured and it matches the result from the evaluated method, then the callback chain should be halted.



159
160
161
162
163
164
165
166
# File 'lib/state_machines/callback.rb', line 159

def call(object, context = {}, *, &)
  if @branch.matches?(object, context)
    run_methods(object, context, 0, *, &)
    true
  else
    false
  end
end

#known_statesObject

Gets a list of the states known to this callback by looking at the branch’s known states



149
150
151
# File 'lib/state_machines/callback.rb', line 149

def known_states
  branch.known_states
end