Class: Riot::ContextMiddleware
Overview
Context middlewares are chainable, context preparers. This to say that a middleware knows about a single neighbor and that it can prepare context before the context is “run”. As a for instance, suppose you wanted the following to be possible.
context Person do
denies(:valid?)
end # Person
Without writing a middleware, the topic in this would actually be nil, but what the context is saying is that there should be something in the topic that responds to :valid?
; an instance of Person
in this case. We can do this with middleware like so:
class Modelware < Riot::ContextMiddleware
register
def call(context)
if context.description.kind_of?(Model)
context.setup { context.description.new }
end
middleware.call(context)
end
end # Modelware
That’s good stuff. If you’re familiar at all with the nature of Rack middleware - how to implement it, how it’s executed, etc. - you’ll be familiar with Context middleware as the principles are similar:
-
Define a class that extends ContextMiddleware
-
Call
register
-
Implement a
call
method that accepts the Context that is about to be executed -
Do stuff, but make sure to pass the call along with middleware.call(context)
Steps 1, 2, and 3 should be pretty straight-forward. Currently, context
is the only argument to call
. When your middleware is initialized it is given the next registered middleware in the chain (which is where the ‘middleware` method gets its value from).
So, “Do stuff” from step 4 is the where we start breaking things down. What can you actually do? Well, you can do anything to the context that you could do if you were writing a Riot test; and I do mean anything.
-
Add setup blocks (as many as you like)
-
Add teardown blocks (as many as you like)
-
Add hookup blocks (as many as you like)
-
Add helpers (as many as you like)
-
Add assertions
The context in question will not run before all middleware have been applied to the context; this is different behavior than that of Rack middleware. ContextMiddleware is only about preparing a context, not about executing it. Thus, where in your method you actually pass the call off to the next middleware in the chain has impact on how the context is set up. Basically, whatever you do before calling ‘middleware.call(context)` is done before any other middleware gets setup and before the innards of the context itself are applied. Whatever you do after that call is done after all that, but still before the actual setups, hookups, assertions, and teardowns are run.
Do not expect the same instance of middleware to exist from one Context instance to the next. It is highly likely that each Context will instantiate their own middleware instances.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#middleware ⇒ Object
readonly
Theoretically, the next middleware in the stack.
Class Method Summary collapse
-
.register ⇒ Object
Registers the current middleware class with Riot so that it may be included in the set of middlewares Riot will poke before executing a Context.
Instance Method Summary collapse
-
#call(context) ⇒ Object
The magic happens here.
-
#initialize(middleware) ⇒ ContextMiddleware
constructor
Create a new middleware instance and give it the next middleware in the chain.
Constructor Details
#initialize(middleware) ⇒ ContextMiddleware
Create a new middleware instance and give it the next middleware in the chain.
80 81 82 |
# File 'lib/riot/middleware.rb', line 80 def initialize(middleware) @middleware = middleware end |
Instance Attribute Details
#middleware ⇒ Object (readonly)
Theoretically, the next middleware in the stack
75 76 77 |
# File 'lib/riot/middleware.rb', line 75 def middleware @middleware end |
Class Method Details
.register ⇒ Object
Registers the current middleware class with Riot so that it may be included in the set of middlewares Riot will poke before executing a Context.
class MyContextMiddleware < Riot::ContextMiddleware
register
def call(context)
context.setup { ... }
middleware.call(context) # this can go anywhere
context.hookup { ... }
end
end
70 71 72 |
# File 'lib/riot/middleware.rb', line 70 def self.register Context.middlewares << self end |
Instance Method Details
#call(context) ⇒ Object
The magic happens here. Because you have access to the Context, you can add your own setups, hookups, etc. call
will be called before any tests are run, but after the Context is configured. Though something will likely be returned, do not put any faith in what that will be.
89 90 91 |
# File 'lib/riot/middleware.rb', line 89 def call(context) raise "You should implement call yourself" end |