Class: Vagrant::Action::Builder

Inherits:
Object
  • Object
show all
Defined in:
lib/vagrant/action/builder.rb

Overview

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)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBuilder

Returns a new instance of Builder.



35
36
37
# File 'lib/vagrant/action/builder.rb', line 35

def initialize
  @stack = []
end

Instance Attribute Details

#stackArray (readonly)

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

Returns:

  • (Array)


24
25
26
# File 'lib/vagrant/action/builder.rb', line 24

def stack
  @stack
end

Class Method Details

.build(middleware, *args, &block) ⇒ Builder

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.

Returns:



31
32
33
# File 'lib/vagrant/action/builder.rb', line 31

def self.build(middleware, *args, &block)
  new.use(middleware, *args, &block)
end

Instance Method Details

#call(env) ⇒ Object

Runs the builder stack with the given environment.



108
109
110
# File 'lib/vagrant/action/builder.rb', line 108

def call(env)
  to_app(env).call(env)
end

#delete(index) ⇒ Object

Deletes the given middleware object or index



102
103
104
105
# File 'lib/vagrant/action/builder.rb', line 102

def delete(index)
  index = self.index(index) unless index.is_a?(Integer)
  stack.delete_at(index)
end

#flattenObject

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.



50
51
52
53
54
# File 'lib/vagrant/action/builder.rb', line 50

def flatten
  lambda do |env|
    self.call(env)
  end
end

#index(object) ⇒ Integer

Returns the numeric index for the given middleware object.

Parameters:

  • object (Object)

    The item to find the index for

Returns:

  • (Integer)


116
117
118
119
120
121
122
123
# File 'lib/vagrant/action/builder.rb', line 116

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) ⇒ Object

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



41
42
43
44
45
# File 'lib/vagrant/action/builder.rb', line 41

def initialize_copy(original)
  super

  @stack = original.stack.dup
end

#insert(index, middleware, *args, &block) ⇒ Object Also known as: insert_before

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



74
75
76
77
78
# 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
  stack.insert(index, [middleware, args, block])
end

#insert_after(index, middleware, *args, &block) ⇒ Object

Inserts a middleware after the given index or middleware object.



83
84
85
86
87
# File 'lib/vagrant/action/builder.rb', line 83

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

#replace(index, middleware, *args, &block) ⇒ Object

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



91
92
93
94
95
96
97
98
99
# File 'lib/vagrant/action/builder.rb', line 91

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) ⇒ Object

Converts the builder stack to a runnable action sequence.

Parameters:

  • env (Vagrant::Action::Environment)

    The action environment

Returns:

  • (Object)

    A callable object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/vagrant/action/builder.rb', line 129

def to_app(env)
  app_stack = nil

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

    # Apply all the hooks to the new builder instance
    env[:action_hooks].each do |hook|
      hook.apply(builder)
    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) ⇒ Object

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.

Parameters:

  • middleware (Class)

    The middleware class



61
62
63
64
65
66
67
68
69
70
# 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