Class: Middlegem::Stack
- Inherits:
-
Object
- Object
- Middlegem::Stack
- Defined in:
- lib/middlegem/stack.rb
Overview
Stack is a class that represents a chain of middlewares, which, when called, can arbitrarily transform a given input. Most of the functionality provided by middlegem
lies in this class. Using Stack is simple: create a new instance with the desired definition, add whatever middlewares you want to use, and #call it.
A very basic example of usage is:
class LastNameMiddleware < Middlegem::Middleware
def call(name)
"The Honorable #{name}"
end
end
class EmailStringMiddleware < Middlegem::Middleware
def initialize(email)
@email = email
end
def call(name)
"#{@email} <#{name}>"
end
end
definitions = [
LastNameMiddleware,
EmailStringMiddleware
]
stack = Middlegem::Stack.new(Middlegem::ArrayDefinition.new(definitions))
stack.middlewares += [EmailStringMiddleware.new('[email protected]'), LastNameMiddleware.new]
stack.call('Jacob') # => "[email protected] <The Honorable Jacob>"
Notice that, even though the EmailStringMiddleware
was added before the LastNameMiddleware
, the LastNameMiddleware
was still run first since it was defined first. That is a core principle of middlegem
—rather than providing extensive methods to insert middleware in a specific place along the chain, middlegem
allows you to define the order explicitly. Also note that there are a variety of ways that you could specify the middleware order by extending Definition.
Instance Attribute Summary collapse
-
#definition ⇒ Definition
readonly
The Definition used to determine what middlewares are permitted in this stack and in what order they should be run.
-
#middlewares ⇒ Array<Object>
An array containing the middlewares represented by this Stack.
Instance Method Summary collapse
-
#call(*args) ⇒ Array<Object>
Transforms the given input by calling all the middlewares in this stack, as defined by the middleware #definition.
-
#ensure_valid!(middleware) ⇒ void
private
Ensures that the given middleware is a valid middleware for this middleware stack, raising an appropriate error if not.
-
#ensure_valid_output!(middleware, output) ⇒ void
private
Ensures that the given output of the given middleware is valid for all the intents and purposes of this stack.
-
#initialize(definition, middlewares: []) ⇒ Stack
constructor
Creates a new instance of Stack with the given middleware definition and, optionally, an array of middlewares.
Constructor Details
#initialize(definition, middlewares: []) ⇒ Stack
Creates a new instance of Middlegem::Stack with the given middleware definition and, optionally, an array of middlewares. Note that middlewares will be validated, not immediately, but before being run.
72 73 74 75 76 77 78 79 |
# File 'lib/middlegem/stack.rb', line 72 def initialize(definition, middlewares: []) unless Definition.valid?(definition) raise InvalidDefinitionError, "The middleware definition #{definition} is invalid!" end @definition = definition @middlewares = middlewares end |
Instance Attribute Details
#definition ⇒ Definition (readonly)
The Definition used to determine what middlewares are permitted in this stack and in what order they should be run. Note that this attribute may be any object that is a valid definition according to Definition.valid?.
63 64 65 |
# File 'lib/middlegem/stack.rb', line 63 def definition @definition end |
#middlewares ⇒ Array<Object>
An array containing the middlewares represented by this Middlegem::Stack. You can insert middlewares in any way you like by accessing this attribute directly and using ruby’s built-in array methods. If desired, you can even assign a new array to it. All middlewares will be validated before being run. To be run, a middleware must be valid as defined by Middleware.valid? and it must be defined according to the Definition instance in #definition.
57 58 59 |
# File 'lib/middlegem/stack.rb', line 57 def middlewares @middlewares end |
Instance Method Details
#call(*args) ⇒ Array<Object>
Transforms the given input by calling all the middlewares in this stack, as defined by the middleware #definition. Note that, as mentioned in Middleware, middlewares in middlegem
transform argument lists. Thus, the arguments are already splatted—there is no need to pass a single array of arguments as the only parameter, unless you actually want to transform just a single array. Also, middleware must return an array of arguments, which will be splatted when passed to Middleware#call.
Midlewares are validated before being run or sorted. If a middleware is encountered that is either invalid or unpermitted, an appropriate error will be raised.
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/middlegem/stack.rb', line 98 def call(*args) # Validate the middlewares. middlewares.each { |m| ensure_valid!(m) } # Sort the middlewares. sorted = definition.sort(middlewares) # Run each middleware with the output of the previous one, ensuring that each output is # valid. For the first middleware, use `args` as the input. last_output = args sorted.each do |middleware| last_output = middleware.call(*last_output) ensure_valid_output!(middleware, last_output) end last_output end |
#ensure_valid!(middleware) ⇒ void (private)
This method returns an undefined value.
Ensures that the given middleware is a valid middleware for this middleware stack, raising an appropriate error if not. A middleware is valid if:
-
it is valid according to Middleware.valid?, and
-
it is defined according to #definition.
124 125 126 127 128 129 130 131 132 |
# File 'lib/middlegem/stack.rb', line 124 def ensure_valid!(middleware) unless Middleware.valid?(middleware) raise InvalidMiddlewareError, "The middleware #{middleware} is not a valid middleware!" end unless definition.defined?(middleware) raise UnpermittedMiddlewareError, "The middleware #{middleware} has not been defined!" end end |
#ensure_valid_output!(middleware, output) ⇒ void (private)
This method returns an undefined value.
Ensures that the given output of the given middleware is valid for all the intents and purposes of this stack. Essentially, the output is valid if it can be passed, splatted, to the next middleware, or returned at the end of the stack. Currently, this method only checks whether the output is an “array” (as defined by the splat operator). If the output is invalid, an appropriate error will be raised.
143 144 145 146 147 148 149 |
# File 'lib/middlegem/stack.rb', line 143 def ensure_valid_output!(middleware, output) unless output == [*output] raise InvalidMiddlewareOutputError, <<~ERR The middleware #{middleware} outputted #{output}, which is not an array! ERR end end |