Class: Middlegem::ArrayDefinition
- Inherits:
-
Definition
- Object
- Definition
- Middlegem::ArrayDefinition
- Defined in:
- lib/middlegem/array_definition.rb
Overview
ArrayDefinition is an implementation of Definition that allows middlewares to be explicitly defined and ordered by class in an array. A basic example of usage is:
definition = Middlegem::ArrayDefinition.new([
MiddlewareOne, # appends '1'
MiddlewareTwo, # appends '2'
MiddlewareThree, # appends '3'
MiddlewareFinal # appends '.'
])
stack = Middlegem::Stack.new(definition, middlewares: [
MiddlewareThree.new,
MiddlewareFinal.new,
MiddlewareOne.new,
MiddlewareTwo.new
])
stack.call('hello') # => ['hello123.']
Notice that the middlewares are called in the order they are specified in the definition array.
If two or more middlewares are encountered that have the same class, they will be left in the order they were added. This behavior can be overriden by setting a tie resolver. The following code, for example, raises an error when multiple MiddlewareFinal
middlewares are encountered:
middlewares = [
MiddlewareOne,
MiddlewareTwo,
MiddlewareThree,
MiddlewareFinal
]
tie_resolver = proc do |ties|
raise "Can't run multiple MiddlewareFinals!" if ties.first.is_a? MiddlewareFinal
ties
end
definition = Middlegem::ArrayDefinition.new(middlewares, resolver: tie_resolver)
stack = Middlegem::Stack.new(definition, middlewares: [
MiddlewareTwo.new,
MiddlewareOne.new,
MiddlewareFinal.new,
MiddlewareThree.new,
MiddlewareFinal.new
])
stack.call('hello') # => RuntimeError (Can't run multiple MiddlewareFinals!)
When the two MiddlewareFinal
instances are encountered, the tie resolver is run, which raises the error.
Of course, this is only scratching the surface of what is possible with a custom tie resolver. You might, for example, simply skip other instances of MiddlewareFinal
, rather than raising an error. A word of caution is in order, however! It is not recommended to try anything too complicated with the tie resolver because it is run for all ties whatsoever. That means that, while you could technically try to sort middlewares with the same class based on some other factor—there is even an example in spec/middlegem/array_definition_spec.rb
—it potentially results in long if/else
or case/when
constructions because each type must be dealt with separately. Use at your own risk!
In general, if you need to use a tie resolver for anything but the most basic of tasks, you should probably just create your own Definition implementation with the required functionality. ArrayDefinition is intended primarily for defining middlewares according to their classes and nothing more.
Instance Attribute Summary collapse
-
#defined_classes ⇒ Array<Class>
An array of the middleware classes defined by this ArrayDefinition.
-
#resolver ⇒ #call
readonly
The callable object to use to break ties when sorting middlewares.
Instance Method Summary collapse
-
#defined?(middleware) ⇒ bool
Determines whether the given middleware is defined according to this ArrayDefinition by checking whether its class is contained in the list of defined classes (i.e. #defined_classes).
-
#initialize(defined_classes, resolver: nil) ⇒ ArrayDefinition
constructor
Creates a new instance of ArrayDefinition with the given array of defined classes and, optionally, a custom tie resolver.
-
#matches(middlewares, klass) ⇒ Array<Object>
private
Gets all the middlewares in the given array whose class is the given class.
-
#matches_class?(middleware, klass) ⇒ Boolean
protected
Should determine whether the given middleware’s evaluated class is equal to the given one.
-
#sort(middlewares) ⇒ Array<Object>
Sorts the given array of middlewares according to this ArrayDefinition.
Methods inherited from Definition
Constructor Details
#initialize(defined_classes, resolver: nil) ⇒ ArrayDefinition
Creates a new instance of Middlegem::ArrayDefinition with the given array of defined classes and, optionally, a custom tie resolver.
96 97 98 99 100 101 102 103 |
# File 'lib/middlegem/array_definition.rb', line 96 def initialize(defined_classes, resolver: nil) resolver = ->(*ties) { ties } if resolver.nil? @defined_classes = defined_classes @resolver = resolver super() end |
Instance Attribute Details
#defined_classes ⇒ Array<Class>
An array of the middleware classes defined by this Middlegem::ArrayDefinition. Middlewares will only be permitted if their class is in this array will be run in the order specified here.
79 80 81 |
# File 'lib/middlegem/array_definition.rb', line 79 def defined_classes @defined_classes end |
#resolver ⇒ #call (readonly)
The callable object to use to break ties when sorting middlewares. When multiple middlewares of the same type are encountered, this object will be called with an array of all tied middlewares. The resolver should sort and return the array as appropriate.
86 87 88 |
# File 'lib/middlegem/array_definition.rb', line 86 def resolver @resolver end |
Instance Method Details
#defined?(middleware) ⇒ bool
Determines whether the given middleware is defined according to this Middlegem::ArrayDefinition by checking whether its class is contained in the list of defined classes (i.e. #defined_classes).
110 111 112 |
# File 'lib/middlegem/array_definition.rb', line 110 def defined?(middleware) defined_classes.any? { |c| matches_class?(middleware, c) } end |
#matches(middlewares, klass) ⇒ Array<Object> (private)
Gets all the middlewares in the given array whose class is the given class.
144 145 146 |
# File 'lib/middlegem/array_definition.rb', line 144 def matches(middlewares, klass) middlewares.select { |m| matches_class?(m, klass) } end |
#matches_class?(middleware, klass) ⇒ Boolean (protected)
Should determine whether the given middleware’s evaluated class is equal to the given one. The default implementation naturally just uses instance_of?
, but you are free to override this method for other situations. You may want is use is_a?
instead, for example, or perhaps a middleware’s “class” is based on some other criterion.
134 135 136 |
# File 'lib/middlegem/array_definition.rb', line 134 def matches_class?(middleware, klass) middleware.instance_of? klass end |
#sort(middlewares) ⇒ Array<Object>
Sorts the given array of middlewares according to this Middlegem::ArrayDefinition. Middlewares are sorted according to the order in which their classes are specified in #defined_classes. If multiple middlewares of the same type are encountered, they will be resolved with the #resolver.
120 121 122 |
# File 'lib/middlegem/array_definition.rb', line 120 def sort(middlewares) defined_classes.map { |c| resolver.call(matches(middlewares, c)) }.flatten end |