class Middleware::Builder

This provides a DSL for building up a stack of middlewares.

This code is based heavily off of `Rack::Builder` and `ActionDispatch::MiddlewareStack` in Rack and Rails, respectively.

# Usage

Building a middleware stack is very easy:

app = Middleware::Builder.new do |b|
  b.use A
  b.use B
end

# Call the middleware
app.call(7)

Attributes

stack[W]

you shouldn't use this method used for insert_before|after_each @return [Array]

Public Class Methods

new(opts = nil) { |self| ... } click to toggle source

Initializes the builder. An optional block can be passed which will either yield the builder or be evaluated in the context of the instance.

Example:

Builder.new do |b|
  b.use A
  b.use B
end

Builder.new do
  use A
  use B
end

@param [Hash] opts Options hash @option opts [Class] :runner_class The class to wrap the middleware stack

in which knows how to run them.

@yield [] Evaluated in this instance which allows you to use methods

like {#use} and such.
# File lib/middleware/builder.rb, line 43
def initialize(opts = nil, &block)
  opts ||= {}
  @runner_class = opts.fetch(:runner_class, Runner)
  @middleware_name = opts.fetch(:name, 'Middleware')

  if block_given?
    if block.arity == 1
      yield self
    else
      instance_eval(&block)
    end
  end
end

Public Instance Methods

call(env = nil) click to toggle source

Runs the builder stack with the given environment.

# File lib/middleware/builder.rb, line 132
def call(env = nil)
  to_app.call(env)
end
delete(index) click to toggle source

Deletes the given middleware object or index

# File lib/middleware/builder.rb, line 126
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/middleware/builder.rb, line 65
def flatten
  lambda do |env|
    call(env)
  end
end
inject_logger(logger) click to toggle source
# File lib/middleware/builder.rb, line 143
def inject_logger logger
  insert_before_each Middleware::Logger, logger, name

  self
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/middleware/builder.rb, line 88
def insert(index, middleware, *args, &block)
  index = self.index(index) unless index.is_a?(Integer)
  fail "no such middleware to insert before: #{index.inspect}" unless index
  stack.insert(index, [middleware, args, block])
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/middleware/builder.rb, line 97
def insert_after(index, middleware, *args, &block)
  index = self.index(index) unless index.is_a?(Integer)
  fail "no such middleware to insert after: #{index.inspect}" unless index
  insert(index + 1, middleware, *args, &block)
end
insert_after_each(middleware, *args, &block) click to toggle source

Inserts a middleware after each middleware object

# File lib/middleware/builder.rb, line 111
def insert_after_each(middleware, *args, &block)
  self.stack = stack.reduce([]) do |carry, item|
    carry.push(item, [middleware, args, block])
  end
end
insert_before(index, middleware, *args, &block)
Alias for: insert
insert_before_each(middleware, *args, &block) click to toggle source

Inserts a middleware before each middleware object

# File lib/middleware/builder.rb, line 104
def insert_before_each(middleware, *args, &block)
  self.stack = stack.reduce([]) do |carry, item|
    carry.push([middleware, args, block], item)
  end
end
inspect() click to toggle source
# File lib/middleware/builder.rb, line 136
def inspect
  name+'[' + stack.map do |middleware|
    name = middleware[0].is_a?(Proc) ? 'Proc' : middleware[0].name
    "#{name}(#{middleware[1].join(', ')})"
  end.join(', ') + ']'
end
name() click to toggle source

Returns the name of the current middleware

# File lib/middleware/builder.rb, line 58
def name
  @middleware_name
end
replace(index, middleware, *args, &block) click to toggle source

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

# File lib/middleware/builder.rb, line 118
def replace(index, middleware, *args, &block)
  index = self.index index unless index.is_a? Integer

  delete(index)
  insert(index, middleware, *args, &block)
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/middleware/builder.rb, line 76
def use(middleware, *args, &block)
  if middleware.is_a?(Builder)
    # Merge in the other builder's stack into our own
    stack.concat(middleware.stack)
  else
    stack << [middleware, args, block]
  end

  self
end

Protected Instance Methods

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/middleware/builder.rb, line 155
def index(object)
  stack.each_with_index do |item, i|
    return i if item[0] == object
  end

  nil
end
stack() click to toggle source

Returns the current stack of middlewares. You probably won't need to use this directly, and it's recommended that you don't.

@return [Array]

# File lib/middleware/builder.rb, line 167
def stack
  @stack ||= []
end
to_app() click to toggle source

Converts the builder stack to a runnable action sequence.

@return [Object] A callable object

# File lib/middleware/builder.rb, line 179
def to_app
  @runner_class.new(stack.dup)
end