class Vagrant::Action::Builder

Action builder which provides a nice DSL for building up a middleware sequence for Vagrant actions. This code is based heavily off of `Rack::Builder` and `ActionDispatch::MiddlewareStack` in Rack and Rails, respectively.

Usage

Building an action sequence is very easy:

app = Vagrant::Action::Builder.new.tap do |b|
  b.use MiddlewareA
  b.use MiddlewareB
end

Vagrant::Action.run(app)

Attributes

stack[R]

This is the stack of middlewares added. This should NOT be used directly.

@return [Array]

Public Class Methods

build(middleware, *args, &block) click to toggle source

This is a shortcut for a middleware sequence with only one item in it. For a description of the arguments and the documentation, please see {#use} instead.

@return [Builder]

# File lib/vagrant/action/builder.rb, line 31
def self.build(middleware, *args, &block)
  new.use(middleware, *args, &block)
end
new() click to toggle source
# File lib/vagrant/action/builder.rb, line 35
def initialize
  @stack = []
end

Public Instance Methods

call(env) click to toggle source

Runs the builder stack with the given environment.

# File lib/vagrant/action/builder.rb, line 115
def call(env)
  to_app(env).call(env)
end
delete(index) click to toggle source

Deletes the given middleware object or index

# File lib/vagrant/action/builder.rb, line 109
def delete(index)
  index = self.index(index) unless index.is_a?(Integer)
  stack.delete_at(index)
end
flatten() click to toggle source

Returns a mergeable version of the builder. If `use` is called with the return value of this method, then the stack will merge, instead of being treated as a separate single middleware.

# File lib/vagrant/action/builder.rb, line 50
def flatten
  lambda do |env|
    self.call(env)
  end
end
index(object) click to toggle source

Returns the numeric index for the given middleware object.

@param [Object] object The item to find the index for @return [Integer]

# File lib/vagrant/action/builder.rb, line 123
def index(object)
  stack.each_with_index do |item, i|
    return i if item[0] == object
    return i if item[0].respond_to?(:name) && item[0].name == object
  end

  nil
end
initialize_copy(original) click to toggle source

Implement a custom copy that copies the stack variable over so that we don't clobber that.

Calls superclass method
# File lib/vagrant/action/builder.rb, line 41
def initialize_copy(original)
  super

  @stack = original.stack.dup
end
insert(index, middleware, *args, &block) click to toggle source

Inserts a middleware at the given index or directly before the given middleware object.

# File lib/vagrant/action/builder.rb, line 74
def insert(index, middleware, *args, &block)
  index = self.index(index) unless index.is_a?(Integer)
  raise "no such middleware to insert before: #{index.inspect}" unless index

  if middleware.kind_of?(Builder)
    middleware.stack.reverse.each do |stack_item|
      stack.insert(index, stack_item)
    end
  else
    stack.insert(index, [middleware, args, block])
  end
end
Also aliased as: insert_before
insert_after(index, middleware, *args, &block) click to toggle source

Inserts a middleware after the given index or middleware object.

# File lib/vagrant/action/builder.rb, line 90
def insert_after(index, middleware, *args, &block)
  index = self.index(index) unless index.is_a?(Integer)
  raise "no such middleware to insert after: #{index.inspect}" unless index
  insert(index + 1, middleware, *args, &block)
end
insert_before(index, middleware, *args, &block)
Alias for: insert
replace(index, middleware, *args, &block) click to toggle source

Replaces the given middlware object or index with the new middleware.

# File lib/vagrant/action/builder.rb, line 98
def replace(index, middleware, *args, &block)
  if index.is_a?(Integer)
    delete(index)
    insert(index, middleware, *args, &block)
  else
    insert_before(index, middleware, *args, &block)
    delete(index)
  end
end
to_app(env) click to toggle source

Converts the builder stack to a runnable action sequence.

@param [Hash] env The action environment hash @return [Object] A callable object

# File lib/vagrant/action/builder.rb, line 136
def to_app(env)
  app_stack = nil

  # If we have action hooks, then we apply them
  if env[:action_hooks]
    builder = self.dup

    # These are the options to pass into hook application.
    options = {}

    # If we already ran through once and did append/prepends,
    # then don't do it again.
    if env[:action_hooks_already_ran]
      options[:no_prepend_or_append] = true
    end

    # Specify that we already ran, so in the future we don't repeat
    # the prepend/append hooks.
    env[:action_hooks_already_ran] = true

    # Apply all the hooks to the new builder instance
    env[:action_hooks].each do |hook|
      hook.apply(builder, options)
    end

    # The stack is now the result of the new builder
    app_stack = builder.stack.dup
  end

  # If we don't have a stack then default to using our own
  app_stack ||= stack.dup

  # Wrap the middleware stack with the Warden to provide a consistent
  # and predictable behavior upon exceptions.
  Warden.new(app_stack, env)
end
use(middleware, *args, &block) click to toggle source

Adds a middleware class to the middleware stack. Any additional args and a block, if given, are saved and passed to the initializer of the middleware.

@param [Class] middleware The middleware class

# File lib/vagrant/action/builder.rb, line 61
def use(middleware, *args, &block)
  if middleware.kind_of?(Builder)
    # Merge in the other builder's stack into our own
    self.stack.concat(middleware.stack)
  else
    self.stack << [middleware, args, block]
  end

  self
end