Class: Tenderloin::Actions::Runner

Inherits:
Object
  • Object
show all
Includes:
Util
Defined in:
lib/tenderloin/actions/runner.rb

Overview

Base class for any class which will act as a runner for actions. A runner handles queueing up and executing actions, and executing the methods of an action in the proper order. The action runner also handles invoking callbacks that actions may request.

# Executing Actions

Actions can be executed by adding them and executing them all at once:

runner = Tenderloin::Actions::Runner.new
runner.add_action(FooAction)
runner.add_action(BarAction)
runner.add_action(BazAction)
runner.execute!

Single actions have a shorthand to be executed:

Tenderloin::Actions::Runner.execute!(FooAction)

Arguments may be passed into added actions by adding them after the action class:

runner.add_action(FooAction, "many", "arguments", "may", "follow")

Direct Known Subclasses

Box, VM

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util

#error_and_exit, included, #logger, #wrap_output

Class Method Details

.execute!(action_klass, *args) ⇒ Object

Executes a specific action, optionally passing in any arguments to that action. This method is shorthand to initializing a runner, adding a single action, and executing it.



36
37
38
39
40
# File 'lib/tenderloin/actions/runner.rb', line 36

def execute!(action_klass, *args)
  runner = new
  runner.add_action(action_klass, *args)
  runner.execute!
end

Instance Method Details

#action_klassesObject



131
132
133
# File 'lib/tenderloin/actions/runner.rb', line 131

def action_klasses
  actions.map { |a| a.class }
end

#actionsArray

Returns an array of all the actions in queue. Because this will persist accross calls (calling #actions twice will yield exactly the same object), to clear or modify it, use the ruby array methods which act on ‘self`, such as `Array#clear`.

Returns:

  • (Array)


49
50
51
# File 'lib/tenderloin/actions/runner.rb', line 49

def actions
  @actions ||= []
end

#add_action(action_klass, *args) ⇒ Object

Add an action to the list of queued actions to execute. This method appends the given action class to the end of the queue. Any arguments given after the class are passed into the class constructor.



64
65
66
# File 'lib/tenderloin/actions/runner.rb', line 64

def add_action(action_klass, *args)
  actions << action_klass.new(self, *args)
end

#execute!(single_action = nil, *args) ⇒ Object

Execute the actions in queue. This method can also optionally be used to execute a single action on an instance. The syntax for executing a single method on an instance is the same as the execute! class method.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/tenderloin/actions/runner.rb', line 71

def execute!(single_action=nil, *args)

  if single_action
    actions.clear
    add_action(single_action, *args)
  end

  # Raising it here might be too late and hard debug where the actions are comming from (meta actions)
  raise DuplicateActionException.new if action_klasses.uniq.size < action_klasses.size
    
  # Call the prepare method on each once its
  # initialized, then call the execute! method
  begin
    [:prepare, :execute!, :cleanup].each do |method|
      actions.each do |action|
        action.send(method)
      end
    end
  rescue Exception => e
    # Run the rescue code to do any emergency cleanup
    actions.each do |action|
      action.rescue(e)
    end

    # If its an ActionException, error and exit the message
    if e.is_a?(ActionException)
      error_and_exit(e.message)
      return
    end

    # Finally, reraise the exception
    raise
  end

  # Clear the actions
  actions.clear
end

#find_action(action_klass) ⇒ Object

Returns the first action instance which matches the given class.

Parameters:

  • action_klass (Class)

    The action to search for in the queue

Returns:

  • (Object)


57
58
59
# File 'lib/tenderloin/actions/runner.rb', line 57

def find_action(action_klass)
  actions.find { |a| a.is_a?(action_klass) }
end

#invoke_around_callback(name, *args) ⇒ Object

Invokes an “around callback” which invokes before_name and after_name for the given callback name, yielding a block between callback invokations.



112
113
114
115
116
# File 'lib/tenderloin/actions/runner.rb', line 112

def invoke_around_callback(name, *args)
  invoke_callback("before_#{name}".to_sym, *args)
  yield
  invoke_callback("after_#{name}".to_sym, *args)
end

#invoke_callback(name, *args) ⇒ Object

Invokes a single callback. This method will go through each action and call the method given in the parameter ‘name` if the action responds to it.



121
122
123
124
125
126
127
128
129
# File 'lib/tenderloin/actions/runner.rb', line 121

def invoke_callback(name, *args)
  # Attempt to call the method for the callback on each of the
  # actions
  results = []
  actions.each do |action|
    results << action.send(name, *args) if action.respond_to?(name)
  end
  results
end