Class: StateMachines::Transition
- Inherits:
- 
      Object
      
        - Object
- StateMachines::Transition
 
- Defined in:
- lib/state_machines/transition.rb
Overview
A transition represents a state change for a specific attribute.
Transitions consist of:
- 
An event 
- 
A starting state 
- 
An ending state 
Instance Attribute Summary collapse
- 
  
    
      #args  ⇒ Object 
    
    
  
  
  
  
    
    
  
  
  
  
  
  
    The arguments passed in to the event that triggered the transition (does not include the run_actionboolean argument if specified).
- 
  
    
      #from  ⇒ Object 
    
    
  
  
  
  
    
      readonly
    
    
  
  
  
  
  
  
    The original state value before the transition. 
- 
  
    
      #machine  ⇒ Object 
    
    
  
  
  
  
    
      readonly
    
    
  
  
  
  
  
  
    The state machine for which this transition is defined. 
- 
  
    
      #object  ⇒ Object 
    
    
  
  
  
  
    
      readonly
    
    
  
  
  
  
  
  
    The object being transitioned. 
- 
  
    
      #result  ⇒ Object 
    
    
  
  
  
  
    
      readonly
    
    
  
  
  
  
  
  
    The result of invoking the action associated with the machine. 
- 
  
    
      #to  ⇒ Object 
    
    
  
  
  
  
    
      readonly
    
    
  
  
  
  
  
  
    The new state value after the transition. 
- 
  
    
      #transient  ⇒ Object 
    
    
  
  
  
  
    
    
      writeonly
    
  
  
  
  
  
  
    Whether the transition is only existing temporarily for the object. 
Instance Method Summary collapse
- 
  
    
      #==(other)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Determines equality of transitions by testing whether the object, states, and event involved in the transition are equal. 
- 
  
    
      #action  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    The action that will be run when this transition is performed. 
- 
  
    
      #attribute  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    The attribute which this transition’s machine is defined for. 
- 
  
    
      #attributes  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    A hash of all the core attributes defined for this transition with their names as keys and values of the attributes as values. 
- 
  
    
      #event  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    The event that triggered the transition. 
- 
  
    
      #from_name  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    The state name before the transition. 
- 
  
    
      #human_event  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    The human-readable name of the event that triggered the transition. 
- 
  
    
      #human_from_name  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    The human-readable state name before the transition. 
- 
  
    
      #human_to_name  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    The new human-readable state name after the transition. 
- 
  
    
      #initialize(object, machine, event, from_name, to_name, read_state = true)  ⇒ Transition 
    
    
  
  
  
    constructor
  
  
  
  
  
  
  
    Creates a new, specific transition. 
- 
  
    
      #inspect  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Generates a nicely formatted description of this transitions’s contents. 
- 
  
    
      #loopback?  ⇒ Boolean 
    
    
  
  
  
  
  
  
  
  
  
    Does this transition represent a loopback (i.e. the from and to state are the same). 
- 
  
    
      #paused?  ⇒ Boolean 
    
    
  
  
  
  
  
  
  
  
  
    Checks whether this transition is currently paused. 
- 
  
    
      #perform(*args)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Runs the actual transition and any before/after callbacks associated with the transition. 
- 
  
    
      #persist  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Transitions the current value of the state to that specified by the transition. 
- 
  
    
      #qualified_event  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    The fully-qualified name of the event that triggered the transition. 
- 
  
    
      #qualified_from_name  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    The fully-qualified state name before the transition. 
- 
  
    
      #qualified_to_name  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    The new fully-qualified state name after the transition. 
- 
  
    
      #reset  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Resets any tracking of which callbacks have already been run and whether the state has already been persisted. 
- 
  
    
      #resumable?  ⇒ Boolean 
    
    
  
  
  
  
  
  
  
  
  
    Checks whether this transition has a paused fiber that can be resumed. 
- 
  
    
      #resume!(&block)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Manually resumes the execution of a previously paused callback. 
- 
  
    
      #rollback  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Rolls back changes made to the object’s state via this transition. 
- 
  
    
      #run_callbacks(options = {}, &block)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Runs the before / after callbacks for this transition. 
- 
  
    
      #to_name  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    The new state name after the transition. 
- 
  
    
      #transient?  ⇒ Boolean 
    
    
  
  
  
  
  
  
  
  
  
    Is this transition existing for a short period only? If this is set, it indicates that the transition (or the event backing it) should not be written to the object if it fails. 
- 
  
    
      #within_transaction  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    Runs a block within a transaction for the object being transitioned. 
Constructor Details
#initialize(object, machine, event, from_name, to_name, read_state = true) ⇒ Transition
Creates a new, specific transition
| 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | # File 'lib/state_machines/transition.rb', line 34 def initialize(object, machine, event, from_name, to_name, read_state = true) # :nodoc: @object = object @machine = machine @args = [] @transient = false @paused_fiber = nil @resuming = false @continuation_block = nil @event = machine.events.fetch(event) @from_state = machine.states.fetch(from_name) @from = read_state ? machine.read(object, :state) : @from_state.value @to_state = machine.states.fetch(to_name) @to = @to_state.value reset end | 
Instance Attribute Details
#args ⇒ Object
The arguments passed in to the event that triggered the transition (does not include the run_action boolean argument if specified)
| 25 26 27 | # File 'lib/state_machines/transition.rb', line 25 def args @args end | 
#from ⇒ Object (readonly)
The original state value before the transition
| 18 19 20 | # File 'lib/state_machines/transition.rb', line 18 def from @from end | 
#machine ⇒ Object (readonly)
The state machine for which this transition is defined
| 15 16 17 | # File 'lib/state_machines/transition.rb', line 15 def machine @machine end | 
#object ⇒ Object (readonly)
The object being transitioned
| 12 13 14 | # File 'lib/state_machines/transition.rb', line 12 def object @object end | 
#result ⇒ Object (readonly)
The result of invoking the action associated with the machine
| 28 29 30 | # File 'lib/state_machines/transition.rb', line 28 def result @result end | 
#to ⇒ Object (readonly)
The new state value after the transition
| 21 22 23 | # File 'lib/state_machines/transition.rb', line 21 def to @to end | 
#transient=(value) ⇒ Object (writeonly)
Whether the transition is only existing temporarily for the object
| 31 32 33 | # File 'lib/state_machines/transition.rb', line 31 def transient=(value) @transient = value end | 
Instance Method Details
#==(other) ⇒ Object
Determines equality of transitions by testing whether the object, states, and event involved in the transition are equal
| 290 291 292 293 294 295 296 297 | # File 'lib/state_machines/transition.rb', line 290 def ==(other) other.instance_of?(self.class) && other.object == object && other.machine == machine && other.from_name == from_name && other.to_name == to_name && other.event == event end | 
#action ⇒ Object
The action that will be run when this transition is performed
| 58 59 60 | # File 'lib/state_machines/transition.rb', line 58 def action machine.action end | 
#attribute ⇒ Object
The attribute which this transition’s machine is defined for
| 53 54 55 | # File 'lib/state_machines/transition.rb', line 53 def attribute machine.attribute end | 
#attributes ⇒ Object
A hash of all the core attributes defined for this transition with their names as keys and values of the attributes as values.
Example
machine = StateMachine.new(Vehicle)
transition = StateMachines::Transition.new(Vehicle.new, machine, :ignite, :parked, :idling)
transition.attributes   # => {:object => #<Vehicle:0xb7d60ea4>, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}
| 134 135 136 | # File 'lib/state_machines/transition.rb', line 134 def attributes @attributes ||= { object: object, attribute: attribute, event: event, from: from, to: to } end | 
#event ⇒ Object
The event that triggered the transition
| 63 64 65 | # File 'lib/state_machines/transition.rb', line 63 def event @event.name end | 
#from_name ⇒ Object
The state name before the transition
| 78 79 80 | # File 'lib/state_machines/transition.rb', line 78 def from_name @from_state.name end | 
#human_event ⇒ Object
The human-readable name of the event that triggered the transition
| 73 74 75 | # File 'lib/state_machines/transition.rb', line 73 def human_event @event.human_name(@object.class) end | 
#human_from_name ⇒ Object
The human-readable state name before the transition
| 88 89 90 | # File 'lib/state_machines/transition.rb', line 88 def human_from_name @from_state.human_name(@object.class) end | 
#human_to_name ⇒ Object
The new human-readable state name after the transition
| 103 104 105 | # File 'lib/state_machines/transition.rb', line 103 def human_to_name @to_state.human_name(@object.class) end | 
#inspect ⇒ Object
Generates a nicely formatted description of this transitions’s contents.
For example,
transition = StateMachines::Transition.new(object, machine, :ignite, :parked, :idling)
transition   # => #<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>
| 305 306 307 | # File 'lib/state_machines/transition.rb', line 305 def inspect "#<#{self.class} #{%w[attribute event from from_name to to_name].map { |attr| "#{attr}=#{send(attr).inspect}" } * ' '}>" end | 
#loopback? ⇒ Boolean
Does this transition represent a loopback (i.e. the from and to state are the same)
Example
machine = StateMachine.new(Vehicle)
StateMachines::Transition.new(Vehicle.new, machine, :park, :parked, :parked).loopback?   # => true
StateMachines::Transition.new(Vehicle.new, machine, :park, :idling, :parked).loopback?   # => false
| 115 116 117 | # File 'lib/state_machines/transition.rb', line 115 def loopback? from_name == to_name end | 
#paused? ⇒ Boolean
Checks whether this transition is currently paused. Returns true if there is a paused fiber, false otherwise.
| 311 312 313 | # File 'lib/state_machines/transition.rb', line 311 def paused? @paused_fiber&.alive? || false end | 
#perform(*args) ⇒ Object
Runs the actual transition and any before/after callbacks associated with the transition.  The action associated with the transition/machine can be skipped by passing in false.
Examples
class Vehicle
  state_machine :action => :save do
    ...
  end
end
vehicle = Vehicle.new
transition = StateMachines::Transition.new(vehicle, machine, :ignite, :parked, :idling)
transition.perform                              # => Runs the +save+ action after setting the state attribute
transition.perform(false)                       # => Only sets the state attribute
transition.perform(run_action: false)           # => Only sets the state attribute
transition.perform(Time.now)                    # => Passes in additional arguments and runs the +save+ action
transition.perform(Time.now, false)             # => Passes in additional arguments and only sets the state attribute
transition.perform(Time.now, run_action: false) # => Passes in additional arguments and only sets the state attribute
| 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | # File 'lib/state_machines/transition.rb', line 158 def perform(*args) run_action = case args.last in true | false args.pop in { run_action: } args.last.delete(:run_action) else true end self.args = args # Run the transition !!TransitionCollection.new([self], { use_transactions: machine.use_transactions, actions: run_action }).perform end | 
#persist ⇒ Object
Transitions the current value of the state to that specified by the transition. Once the state is persisted, it cannot be persisted again until this transition is reset.
Example
class Vehicle
  state_machine do
    event :ignite do
      transition :parked => :idling
    end
  end
end
vehicle = Vehicle.new
transition = StateMachines::Transition.new(vehicle, Vehicle.state_machine, :ignite, :parked, :idling)
transition.persist
vehicle.state   # => 'idling'
| 243 244 245 246 247 248 | # File 'lib/state_machines/transition.rb', line 243 def persist return if @persisted machine.write(object, :state, to) @persisted = true end | 
#qualified_event ⇒ Object
The fully-qualified name of the event that triggered the transition
| 68 69 70 | # File 'lib/state_machines/transition.rb', line 68 def qualified_event @event.qualified_name end | 
#qualified_from_name ⇒ Object
The fully-qualified state name before the transition
| 83 84 85 | # File 'lib/state_machines/transition.rb', line 83 def qualified_from_name @from_state.qualified_name end | 
#qualified_to_name ⇒ Object
The new fully-qualified state name after the transition
| 98 99 100 | # File 'lib/state_machines/transition.rb', line 98 def qualified_to_name @to_state.qualified_name end | 
#reset ⇒ Object
Resets any tracking of which callbacks have already been run and whether the state has already been persisted
| 281 282 283 284 285 286 | # File 'lib/state_machines/transition.rb', line 281 def reset @before_run = @persisted = @after_run = false @paused_fiber = nil @resuming = false @continuation_block = nil end | 
#resumable? ⇒ Boolean
Checks whether this transition has a paused fiber that can be resumed. Returns true if there is a paused fiber, false otherwise.
Note: The actual resuming happens automatically when run_callbacks is called again on a transition with a paused fiber.
| 320 321 322 | # File 'lib/state_machines/transition.rb', line 320 def resumable? paused? end | 
#resume!(&block) ⇒ Object
Manually resumes the execution of a previously paused callback. Returns true if the transition was successfully resumed and completed, false if there was no paused fiber, and raises an exception if the transition was halted.
| 328 329 330 331 332 333 334 335 336 337 338 339 | # File 'lib/state_machines/transition.rb', line 328 def resume!(&block) return false unless paused? # Store continuation block if provided @continuation_block = block if block_given? # Run the pausable block which will resume the fiber halted = pausable { true } # Return whether the transition completed successfully !halted end | 
#rollback ⇒ Object
Rolls back changes made to the object’s state via this transition.  This will revert the state back to the from value.
Example
class Vehicle
  state_machine :initial => :parked do
    event :ignite do
      transition :parked => :idling
    end
  end
end
vehicle = Vehicle.new     # => #<Vehicle:0xb7b7f568 @state="parked">
transition = StateMachines::Transition.new(vehicle, Vehicle.state_machine, :ignite, :parked, :idling)
# Persist the new state
vehicle.state             # => "parked"
transition.persist
vehicle.state             # => "idling"
# Roll back to the original state
transition.rollback
vehicle.state             # => "parked"
| 274 275 276 277 | # File 'lib/state_machines/transition.rb', line 274 def rollback reset machine.write(object, :state, from) end | 
#run_callbacks(options = {}, &block) ⇒ Object
Runs the before / after callbacks for this transition. If a block is provided, then it will be executed between the before and after callbacks.
Configuration options:
- 
before- Whether to run before callbacks.
- 
after- Whether to run after callbacks. If false, then any around callbacks will be paused until called again withafterenabled. Default is true.
This will return true if all before callbacks gets executed. After callbacks will not have an effect on the result.
| 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | # File 'lib/state_machines/transition.rb', line 192 def run_callbacks( = {}, &block) = { before: true, after: true }.merge() # If we have a paused fiber and we're not trying to resume (after: false), # this is an idempotent call on an already-paused transition. Just return true. return true if @paused_fiber&.alive? && ![:after] # Extract pausable options = .key?(:fiber) ? { fiber: [:fiber] } : {} # Check if we're resuming from a pause if @paused_fiber&.alive? && [:after] # Resume the paused fiber # Don't reset @success when resuming - preserve the state from the pause # Store the block for later execution @continuation_block = block if block_given? halted = pausable() { true } else @success = false # For normal execution (not pause/resume), default to success # The action block will override this if needed halted = pausable() { before([:after], &block) } if [:before] end # After callbacks are only run if: # * An around callback didn't halt after yielding OR the run failed # * They're enabled or the run didn't succeed after if (!(@before_run && halted) || !@success) && ([:after] || !@success) @before_run end | 
#to_name ⇒ Object
The new state name after the transition
| 93 94 95 | # File 'lib/state_machines/transition.rb', line 93 def to_name @to_state.name end | 
#transient? ⇒ Boolean
Is this transition existing for a short period only? If this is set, it indicates that the transition (or the event backing it) should not be written to the object if it fails.
| 122 123 124 | # File 'lib/state_machines/transition.rb', line 122 def transient? @transient end | 
#within_transaction ⇒ Object
Runs a block within a transaction for the object being transitioned. By default, transactions are a no-op unless otherwise defined by the machine’s integration.
| 177 178 179 | # File 'lib/state_machines/transition.rb', line 177 def within_transaction(&) machine.within_transaction(object, &) end |