module Workflow::WorkflowInstanceMethods

Attributes

in_entry[RW]
in_exit[RW]
in_transition[RW]

Public Instance Methods

clear_transition_flags() click to toggle source
# File lib/workflow.rb, line 236
def clear_transition_flags
  set_transition_flags nil, nil, nil
end
current_state() click to toggle source
# File lib/workflow.rb, line 188
def current_state
  loaded_state = load_workflow_state
  res = spec.states[loaded_state.to_sym] if loaded_state
  res || spec.initial_state
end
halt(reason = nil) click to toggle source
# File lib/workflow.rb, line 240
def halt(reason = nil)
  @halted_because = reason
  @halted = true
end
halt!(reason = nil) click to toggle source
# File lib/workflow.rb, line 245
def halt!(reason = nil)
  halt reason
  raise TransitionHalted.new(reason)
end
halted?() click to toggle source

See the 'Guards' section in the README @return true if the last transition was halted by one of the transition callbacks.

# File lib/workflow.rb, line 196
def halted?
  @halted
end
halted_because() click to toggle source

@return the reason of the last transition abort as set by the previous call of `halt` or `halt!` method.

# File lib/workflow.rb, line 202
def halted_because
  @halted_because
end
process_event!(name, *args) click to toggle source
# File lib/workflow.rb, line 206
def process_event!(name, *args)
  assure_transition_allowed! name
  event = current_state.events[name.to_sym]
  assure_target_state_exists!(event)
  set_transition_flags(current_state, spec.states[event.transitions_to], event)
  @halted_because = nil
  @halted         = false
  return_value    = run_action(event.action, *args) || run_action_callback(event.name, *args)
  if @halted
    run_on_failed_transition(*args)
    return_value = false
  else
    if event.perform_validation? and not valid?
      halt :validation_failed
      run_on_failed_transition(*args)
      @halted = true # make sure this one is not reset in the on_failed_transition callback
      return_value = false
    else
      transition(*args)
    end
  end
  return_value.nil? ? true : return_value
end
set_transition_flags(current_state, target_state, event) click to toggle source
# File lib/workflow.rb, line 230
def set_transition_flags(current_state, target_state, event)
  @in_exit       = current_state
  @in_entry      = target_state
  @in_transition = event
end
spec() click to toggle source
# File lib/workflow.rb, line 250
def spec
  # check the singleton class first
  class << self
    return workflow_spec if workflow_spec
  end

  c = self.class
  # using a simple loop instead of class_inheritable_accessor to avoid
  # dependency on Rails' ActiveSupport
  until c.workflow_spec || !(c.include? Workflow)
    c = c.superclass
  end
  c.workflow_spec
end

Protected Instance Methods

assure_target_state_exists!(event) click to toggle source
# File lib/workflow.rb, line 278
def assure_target_state_exists!(event)
  # Create a meaningful error message instead of
  # "undefined method `on_entry' for nil:NilClass"
  # Reported by Kyle Burton
  if !spec.states[event.transitions_to]
    raise WorkflowError.new \
        "Event[#{event.name}]'s transitions_to[#{event.transitions_to}] is not a declared state."
  end
end
assure_transition_allowed!(name) click to toggle source
# File lib/workflow.rb, line 267
def assure_transition_allowed!(name)
  unless self.send "can_#{name}?"
    prohibit_transition! name
  end
end
load_workflow_state() click to toggle source

load_workflow_state and persist_workflow_state can be overriden to handle the persistence of the workflow state.

Default (non ActiveRecord) implementation stores the current state in a variable.

Default ActiveRecord implementation uses a 'workflow_state' database column.

# File lib/workflow.rb, line 362
def load_workflow_state
  @workflow_state if instance_variable_defined? :@workflow_state
end
persist_workflow_state(new_value) click to toggle source
# File lib/workflow.rb, line 366
def persist_workflow_state(new_value)
  @workflow_state = new_value
end
prohibit_transition!(name) click to toggle source
# File lib/workflow.rb, line 273
def prohibit_transition!(name)
  raise NoTransitionAllowed.new \
      "There is no event #{name} defined for the #{current_state} state."
end
run_action(action, *args) click to toggle source
# File lib/workflow.rb, line 311
def run_action(action, *args)
  instance_exec(*args, &action) if action
end
run_action_callback(action_name, *args) click to toggle source
# File lib/workflow.rb, line 315
def run_action_callback(action_name, *args)
  self.send action_name.to_sym, *args if self.respond_to?(action_name.to_sym)
end
run_on_entry(*args) click to toggle source
# File lib/workflow.rb, line 319
def run_on_entry(*args)
  if self.wf_target_state.on_entry
    instance_exec(self.wf_prior_state.name, self.wf_event_name, *args, &self.wf_target_state.on_entry)
  else
    hook_name = "on_#{self.wf_target_state.name}_entry"
    self.send hook_name, self.wf_prior_state, self.wf_event_name, *args if self.respond_to? hook_name
  end
end
run_on_exit(*args) click to toggle source
# File lib/workflow.rb, line 328
def run_on_exit(*args)
  if self.wf_prior_state # no on_exit for entry into initial state
    if self.wf_prior_state.on_exit
      instance_exec(self.wf_target_state.name, self.wf_event_name, *args, &self.wf_prior_state.on_exit)
    else
      hook_name = "on_#{self.wf_prior_state.name}_exit"
      self.send hook_name, self.wf_target_state, self.wf_event_name, *args if self.respond_to? hook_name
    end
  end
end
run_on_failed_transition(*args) click to toggle source
# File lib/workflow.rb, line 301
def run_on_failed_transition(*args)
  if spec.on_failed_transition_proc
    return_value = instance_exec(self.wf_prior_state.name, self.wf_target_state.name, self.wf_event_name, *args, &spec.on_failed_transition_proc)
  else
    return_value = nil
  end
  clear_transition_flags
  return return_value
end
run_on_transition(*args) click to toggle source
# File lib/workflow.rb, line 297
def run_on_transition(*args)
  instance_exec(self.wf_prior_state.name, self.wf_target_state.name, self.wf_event_name, *args, &spec.on_transition_proc) if spec.on_transition_proc
end
transition(*args) click to toggle source
# File lib/workflow.rb, line 288
def transition(*args)
  run_on_exit(*args)
  run_on_transition(*args)
  val = persist_workflow_state wf_target_state.name
  run_on_entry(*args)
  clear_transition_flags
  val
end
wf_event() click to toggle source
# File lib/workflow.rb, line 351
def wf_event
  @in_transition
end
wf_event_name() click to toggle source
# File lib/workflow.rb, line 347
def wf_event_name
  @in_transition.name
end
wf_prior_state() click to toggle source
# File lib/workflow.rb, line 339
def wf_prior_state
  @in_exit
end
wf_target_state() click to toggle source
# File lib/workflow.rb, line 343
def wf_target_state
  @in_entry
end