ibsciss-middleware 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -1
- data/README.md +57 -10
- data/Rakefile +3 -3
- data/lib/middleware.rb +2 -2
- data/lib/middleware/builder.rb +27 -15
- data/lib/middleware/logger.rb +49 -0
- data/lib/middleware/runner.rb +2 -2
- data/middleware.gemspec +14 -14
- data/spec/middleware/builder_spec.rb +78 -44
- data/spec/middleware/logger_spec.rb +58 -0
- data/spec/middleware/runner_spec.rb +56 -48
- data/spec/spec_helper.rb +45 -47
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45a7f568a5dd19fa3ed4060972af8eab369d6cc7
|
4
|
+
data.tar.gz: 9324a50e02d47da8f6a4232db2d0f373dda717f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc1c0601887f79ce0580705cf7031124315cc25109703765f1b92e66147c8c2ef79b2ee9ffca951ff7bb4ef739bebdf8d21f3ec226fab2630852fa073be45204
|
7
|
+
data.tar.gz: ad2c8c9a03d3da09664e879322906b405423e0fdb8cd801da3fab30c0cfba90ea0529aeeea330a5c1bb4ff28d4922b20f0b61249ab1c7ab57d6d5c161a9dcd94
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
|
+
## 0.4.0
|
2
|
+
- Add a name displayed in the logger & inspect methods
|
3
|
+
- Add a logger middleware
|
4
|
+
- Fixed rubocop offenses
|
5
|
+
- Fix builder#inspect to display class name
|
6
|
+
|
1
7
|
## 0.3.2
|
2
|
-
- Add CI
|
8
|
+
- Add CI, Code Climate, Gitter & Improve documentation
|
9
|
+
- Add `insert_after_each` and `insert_before_each` methods
|
10
|
+
- Improve the `inspect` method to a more readable version
|
11
|
+
- Enable lambda to receive additional arguments
|
3
12
|
|
4
13
|
## 0.3.1
|
5
14
|
- Enable lambda to change the given object
|
data/README.md
CHANGED
@@ -140,18 +140,17 @@ A basic description of the two methods that a middleware must implement:
|
|
140
140
|
state sent in (defined by the caller, but usually a Hash). This call should also
|
141
141
|
call `app.call(env)` at some point to move on.
|
142
142
|
|
143
|
-
This architecture offers the biggest advantage of letting you enhance the env variable before passing it to the next middleware,
|
144
|
-
and giving you the abilities to change the returned datas, as follow:
|
143
|
+
This architecture offers the biggest advantage of letting you enhance the `env` variable before passing it to the next middleware, and giving you the ability to change the returned data, as follows:
|
145
144
|
|
146
145
|
```ruby
|
147
146
|
class Greeting
|
148
|
-
def initialize(app,
|
147
|
+
def initialize(app, datas = nil)
|
149
148
|
@app = app
|
150
149
|
@datas = datas
|
151
150
|
end
|
152
151
|
|
153
152
|
def call(env)
|
154
|
-
env = "#{
|
153
|
+
env = "#{@datas} #{env}"
|
155
154
|
result = @app(env)
|
156
155
|
"#{result} !"
|
157
156
|
end
|
@@ -205,6 +204,12 @@ end.call()
|
|
205
204
|
The call method takes an optional parameter which is the state to pass into the
|
206
205
|
initial middleware.
|
207
206
|
|
207
|
+
You can optionally set a name, that will be displayed in inspect and for logging purpose, for the current middleware:
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
Middleware::Builder.new(name: 'MyPersonalMiddleware')
|
211
|
+
```
|
212
|
+
|
208
213
|
### Manipulating a Stack
|
209
214
|
|
210
215
|
Stacks also provide a set of methods for manipulating the middleware stack. This
|
@@ -254,7 +259,7 @@ stack.insert_before_each logger
|
|
254
259
|
#### Replace
|
255
260
|
|
256
261
|
```ruby
|
257
|
-
# Replace the
|
262
|
+
# Replace the second middleware
|
258
263
|
stack.replace(1, SomeOtherMiddleware)
|
259
264
|
|
260
265
|
# Replace the Trace middleware
|
@@ -264,7 +269,7 @@ stack.replace(Trace, SomeOtherMiddleware)
|
|
264
269
|
#### Delete
|
265
270
|
|
266
271
|
```ruby
|
267
|
-
# Delete the
|
272
|
+
# Delete the second middleware
|
268
273
|
stack.delete(1)
|
269
274
|
|
270
275
|
# Delete the Trace middleware
|
@@ -304,7 +309,7 @@ Note that you can also pass blocks in using the `use` method.
|
|
304
309
|
|
305
310
|
#### Lambda
|
306
311
|
|
307
|
-
Lambda work the same with additional arguments:
|
312
|
+
Lambda work the same, with additional arguments:
|
308
313
|
|
309
314
|
```ruby
|
310
315
|
Middleware::Builder.new { |b|
|
@@ -324,8 +329,50 @@ Middleware::Builder.new { |b|
|
|
324
329
|
}.inspect
|
325
330
|
```
|
326
331
|
|
327
|
-
|
332
|
+
It will output:
|
333
|
+
|
334
|
+
```ruby
|
335
|
+
Middleware[Trace(), Echo("Hello, World!")]
|
336
|
+
```
|
337
|
+
|
338
|
+
_If you have set a name, it will be displayed instead of `Middleware`_.
|
339
|
+
|
340
|
+
#### Logging
|
341
|
+
|
342
|
+
A built-in logging mechanism is provided, it will output for each provider of the stack:
|
343
|
+
|
344
|
+
- The provided arguments
|
345
|
+
- The returned values (the first 255 chars) and the time (in milliseconds) elapsed in the call method
|
346
|
+
|
347
|
+
To initialize the logging you must provide a valid logger instance to `#inject_logger`.
|
348
|
+
|
349
|
+
It is also recommended to give a name to your middleware stack.
|
328
350
|
|
329
351
|
```ruby
|
330
|
-
|
331
|
-
|
352
|
+
require 'logger'
|
353
|
+
|
354
|
+
class UpperCaseMiddleware
|
355
|
+
def initialize app
|
356
|
+
@app = app
|
357
|
+
end
|
358
|
+
|
359
|
+
def call env
|
360
|
+
sleep(1)
|
361
|
+
env.upcase
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
# Build the middleware:
|
366
|
+
Middleware::Builder.new(name: 'MyMiddleware') { |b|
|
367
|
+
b.use UpperCaseMiddleware
|
368
|
+
}.inject_logger(Logger.new(STDOUT)).call('a message')
|
369
|
+
```
|
370
|
+
|
371
|
+
It will output something like:
|
372
|
+
|
373
|
+
```
|
374
|
+
INFO -- MyMiddleware: UpperCaseMiddleware has been called with: "a message"
|
375
|
+
INFO -- MyMiddleware: UpperCaseMiddleware finished in 1001 ms and returned: "A MESSAGE"
|
376
|
+
```
|
377
|
+
|
378
|
+
_Note: the provided logger instance must respond to `#call(level severity, message, app name)`_
|
data/Rakefile
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
-
require
|
3
|
-
require
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rspec/core/rake_task'
|
4
4
|
|
5
5
|
# RSpec test task
|
6
6
|
RSpec::Core::RakeTask.new
|
7
7
|
|
8
8
|
# Make sure the default is to run RSpec
|
9
|
-
task :
|
9
|
+
task default: 'spec'
|
data/lib/middleware.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'middleware/builder'
|
2
|
+
require 'middleware/runner'
|
data/lib/middleware/builder.rb
CHANGED
@@ -17,6 +17,7 @@ module Middleware
|
|
17
17
|
# app.call(7)
|
18
18
|
#
|
19
19
|
class Builder
|
20
|
+
|
20
21
|
# Initializes the builder. An optional block can be passed which
|
21
22
|
# will either yield the builder or be evaluated in the context of the instance.
|
22
23
|
#
|
@@ -37,9 +38,10 @@ module Middleware
|
|
37
38
|
# in which knows how to run them.
|
38
39
|
# @yield [] Evaluated in this instance which allows you to use methods
|
39
40
|
# like {#use} and such.
|
40
|
-
def initialize(opts=nil, &block)
|
41
|
+
def initialize(opts = nil, &block)
|
41
42
|
opts ||= {}
|
42
43
|
@runner_class = opts[:runner_class] || Runner
|
44
|
+
@middleware_name = opts[:name] || 'Middleware'
|
43
45
|
|
44
46
|
if block_given?
|
45
47
|
if block.arity == 1
|
@@ -50,12 +52,17 @@ module Middleware
|
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
55
|
+
# Returns the name of the current middleware
|
56
|
+
def name
|
57
|
+
@middleware_name
|
58
|
+
end
|
59
|
+
|
53
60
|
# Returns a mergeable version of the builder. If `use` is called with
|
54
61
|
# the return value of this method, then the stack will merge, instead
|
55
62
|
# of being treated as a separate single middleware.
|
56
63
|
def flatten
|
57
64
|
lambda do |env|
|
58
|
-
|
65
|
+
call(env)
|
59
66
|
end
|
60
67
|
end
|
61
68
|
|
@@ -65,11 +72,11 @@ module Middleware
|
|
65
72
|
#
|
66
73
|
# @param [Class] middleware The middleware class
|
67
74
|
def use(middleware, *args, &block)
|
68
|
-
if middleware.
|
75
|
+
if middleware.is_a?(Builder)
|
69
76
|
# Merge in the other builder's stack into our own
|
70
|
-
|
77
|
+
stack.concat(middleware.stack)
|
71
78
|
else
|
72
|
-
|
79
|
+
stack << [middleware, args, block]
|
73
80
|
end
|
74
81
|
|
75
82
|
self
|
@@ -79,7 +86,7 @@ module Middleware
|
|
79
86
|
# given middleware object.
|
80
87
|
def insert(index, middleware, *args, &block)
|
81
88
|
index = self.index(index) unless index.is_a?(Integer)
|
82
|
-
|
89
|
+
fail "no such middleware to insert before: #{index.inspect}" unless index
|
83
90
|
stack.insert(index, [middleware, args, block])
|
84
91
|
end
|
85
92
|
|
@@ -88,7 +95,7 @@ module Middleware
|
|
88
95
|
# Inserts a middleware after the given index or middleware object.
|
89
96
|
def insert_after(index, middleware, *args, &block)
|
90
97
|
index = self.index(index) unless index.is_a?(Integer)
|
91
|
-
|
98
|
+
fail "no such middleware to insert after: #{index.inspect}" unless index
|
92
99
|
insert(index + 1, middleware, *args, &block)
|
93
100
|
end
|
94
101
|
|
@@ -125,14 +132,22 @@ module Middleware
|
|
125
132
|
end
|
126
133
|
|
127
134
|
# Runs the builder stack with the given environment.
|
128
|
-
def call(env=nil)
|
135
|
+
def call(env = nil)
|
129
136
|
to_app.call(env)
|
130
137
|
end
|
131
138
|
|
132
139
|
def inspect
|
133
|
-
|
134
|
-
|
135
|
-
|
140
|
+
name+'[' + stack.reduce([]) do |carry, middleware|
|
141
|
+
name = middleware[0].is_a?(Proc) ? 'Proc' : middleware[0].name
|
142
|
+
|
143
|
+
carry << "#{name}(#{middleware[1].join(', ')})"
|
144
|
+
end.join(', ') + ']'
|
145
|
+
end
|
146
|
+
|
147
|
+
def inject_logger logger
|
148
|
+
insert_before_each Middleware::Logger, logger, name
|
149
|
+
|
150
|
+
self
|
136
151
|
end
|
137
152
|
|
138
153
|
protected
|
@@ -160,9 +175,7 @@ module Middleware
|
|
160
175
|
# you shouldn't use this method
|
161
176
|
#
|
162
177
|
# @return [Array]
|
163
|
-
|
164
|
-
@stack = stack
|
165
|
-
end
|
178
|
+
attr_writer :stack
|
166
179
|
|
167
180
|
# Converts the builder stack to a runnable action sequence.
|
168
181
|
#
|
@@ -170,6 +183,5 @@ module Middleware
|
|
170
183
|
def to_app
|
171
184
|
@runner_class.new(stack.dup)
|
172
185
|
end
|
173
|
-
|
174
186
|
end
|
175
187
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
module Middleware
|
5
|
+
|
6
|
+
class Logger
|
7
|
+
def initialize app, logger, name = nil
|
8
|
+
@app = app
|
9
|
+
@write_to = logger
|
10
|
+
@middleware_name = name
|
11
|
+
end
|
12
|
+
|
13
|
+
def call env
|
14
|
+
write(
|
15
|
+
way_in_message(
|
16
|
+
next_middleware_name, env
|
17
|
+
))
|
18
|
+
|
19
|
+
time = Time.now
|
20
|
+
|
21
|
+
@app.call(env).tap { |env|
|
22
|
+
write(
|
23
|
+
way_out_message(
|
24
|
+
next_middleware_name, (Time.now - time) * 1000.0, env
|
25
|
+
))
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def next_middleware_name
|
30
|
+
@app.class.name
|
31
|
+
end
|
32
|
+
|
33
|
+
def pretty_print item
|
34
|
+
->(out){ PP.pp(item, out) }.('')
|
35
|
+
end
|
36
|
+
|
37
|
+
def way_in_message name, env
|
38
|
+
' %s has been called with: %s' % [name, pretty_print(env)]
|
39
|
+
end
|
40
|
+
|
41
|
+
def way_out_message name, time, value
|
42
|
+
' %s finished in %.0f ms and returned: %s' % [name, time, pretty_print(value)]
|
43
|
+
end
|
44
|
+
|
45
|
+
def write msg
|
46
|
+
@write_to.add(::Logger::INFO, msg.slice(0, 255).strip!, @middleware_name)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/middleware/runner.rb
CHANGED
@@ -4,7 +4,7 @@ module Middleware
|
|
4
4
|
# in order, then reversing the order.
|
5
5
|
class Runner
|
6
6
|
# A middleware which does nothing
|
7
|
-
EMPTY_MIDDLEWARE =
|
7
|
+
EMPTY_MIDDLEWARE = ->(env) { env }
|
8
8
|
|
9
9
|
# Build a new middleware runner with the given middleware
|
10
10
|
# stack.
|
@@ -60,7 +60,7 @@ module Middleware
|
|
60
60
|
next_middleware.call(klass.call(env, *args))
|
61
61
|
end
|
62
62
|
else
|
63
|
-
|
63
|
+
fail "Invalid middleware, doesn't respond to `call`: #{klass.inspect}"
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
data/middleware.gemspec
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
|
-
gem.authors = [
|
5
|
-
gem.email = [
|
6
|
-
gem.description =
|
7
|
-
gem.summary =
|
8
|
-
gem.homepage =
|
9
|
-
gem.license =
|
4
|
+
gem.authors = ['Mitchell Hashimoto', 'Arnaud Lemaire']
|
5
|
+
gem.email = ['mitchell.hashimoto@gmail.com', 'alemaire@ibsciss.com']
|
6
|
+
gem.description = 'Generalized implementation of the rack middleware abstraction for Ruby.'
|
7
|
+
gem.summary = 'Generalized implementation of the rack middleware abstraction for Ruby (chain of responsibility design pattern).'
|
8
|
+
gem.homepage = 'https://github.com/ibsciss/ruby-middleware'
|
9
|
+
gem.license = 'MIT'
|
10
10
|
|
11
|
-
gem.add_development_dependency
|
12
|
-
gem.add_development_dependency
|
13
|
-
gem.add_development_dependency
|
14
|
-
gem.add_development_dependency
|
11
|
+
gem.add_development_dependency 'rake', '~> 10.4.2'
|
12
|
+
gem.add_development_dependency 'rspec-core', '~> 3.2'
|
13
|
+
gem.add_development_dependency 'rspec-expectations', '~> 3.2'
|
14
|
+
gem.add_development_dependency 'rspec-mocks', '~> 3.2'
|
15
15
|
gem.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.7'
|
16
16
|
|
17
|
-
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
18
18
|
gem.files = `git ls-files`.split("\n")
|
19
19
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
-
gem.name =
|
21
|
-
gem.require_paths = [
|
22
|
-
gem.version = '0.
|
20
|
+
gem.name = 'ibsciss-middleware'
|
21
|
+
gem.require_paths = ['lib']
|
22
|
+
gem.version = '0.4.0'
|
23
23
|
end
|
@@ -1,20 +1,20 @@
|
|
1
|
-
require
|
1
|
+
require 'middleware'
|
2
2
|
|
3
3
|
describe Middleware::Builder do
|
4
|
-
let(:data) { { :
|
4
|
+
let(:data) { { data: [] } }
|
5
5
|
let(:instance) { described_class.new }
|
6
6
|
|
7
7
|
# This returns a proc that can be used with the builder
|
8
8
|
# that simply appends data to an array in the env.
|
9
9
|
def appender_proc(data)
|
10
|
-
|
10
|
+
proc { |obj| obj.tap { |env| env[:data] << data } }
|
11
11
|
end
|
12
12
|
|
13
|
-
context
|
14
|
-
context
|
15
|
-
it
|
13
|
+
context 'initialized with a block' do
|
14
|
+
context 'without explicit receiver' do
|
15
|
+
it 'instance evals the block' do
|
16
16
|
data = {}
|
17
|
-
proc =
|
17
|
+
proc = proc { |env| env[:data] = true }
|
18
18
|
|
19
19
|
app = described_class.new do
|
20
20
|
use proc
|
@@ -26,10 +26,10 @@ describe Middleware::Builder do
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
context
|
30
|
-
it
|
29
|
+
context 'with explicit receiver' do
|
30
|
+
it 'yields self to the block' do
|
31
31
|
data = {}
|
32
|
-
proc =
|
32
|
+
proc = proc { |env| env[:data] = true }
|
33
33
|
|
34
34
|
app = described_class.new do |b|
|
35
35
|
b.use proc
|
@@ -42,10 +42,10 @@ describe Middleware::Builder do
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
context
|
46
|
-
it
|
45
|
+
context 'basic `use`' do
|
46
|
+
it 'should add items to the stack and make them callable' do
|
47
47
|
data = {}
|
48
|
-
proc =
|
48
|
+
proc = proc { |env| env[:data] = true }
|
49
49
|
|
50
50
|
instance.use proc
|
51
51
|
instance.call(data)
|
@@ -53,10 +53,10 @@ describe Middleware::Builder do
|
|
53
53
|
expect(data[:data]).to be_truthy
|
54
54
|
end
|
55
55
|
|
56
|
-
it
|
56
|
+
it 'should be able to add multiple items' do
|
57
57
|
data = {}
|
58
|
-
proc1 =
|
59
|
-
proc2 =
|
58
|
+
proc1 = proc { |env| env.tap { |obj| obj[:one] = true } }
|
59
|
+
proc2 = proc { |env| env.tap { |obj| obj[:two] = true } }
|
60
60
|
|
61
61
|
instance.use proc1
|
62
62
|
instance.use proc2
|
@@ -66,16 +66,16 @@ describe Middleware::Builder do
|
|
66
66
|
expect(data[:two]).to be_truthy
|
67
67
|
end
|
68
68
|
|
69
|
-
it
|
69
|
+
it 'should be able to add another builder' do
|
70
70
|
data = {}
|
71
|
-
proc1 =
|
71
|
+
proc1 = proc { |env| env[:one] = true }
|
72
72
|
|
73
73
|
# Build the first builder
|
74
74
|
one = described_class.new
|
75
75
|
one.use proc1
|
76
76
|
|
77
77
|
# Add it to this builder
|
78
|
-
two
|
78
|
+
two = described_class.new
|
79
79
|
two.use one
|
80
80
|
|
81
81
|
# Call the 2nd and verify results
|
@@ -83,19 +83,19 @@ describe Middleware::Builder do
|
|
83
83
|
expect(data[:one]).to be_truthy
|
84
84
|
end
|
85
85
|
|
86
|
-
it
|
86
|
+
it 'should default the env to `nil` if not given' do
|
87
87
|
result = false
|
88
|
-
proc =
|
88
|
+
proc = proc { |env| result = env.nil? }
|
89
89
|
|
90
90
|
instance.use proc
|
91
91
|
instance.call
|
92
92
|
|
93
93
|
expect(result).to be_truthy
|
94
|
-
|
94
|
+
end
|
95
95
|
end
|
96
96
|
|
97
|
-
context
|
98
|
-
it
|
97
|
+
context 'inserting' do
|
98
|
+
it 'can insert at an index' do
|
99
99
|
instance.use appender_proc(1)
|
100
100
|
instance.insert(0, appender_proc(2))
|
101
101
|
instance.call(data)
|
@@ -103,7 +103,7 @@ describe Middleware::Builder do
|
|
103
103
|
expect(data[:data]).to eq [2, 1]
|
104
104
|
end
|
105
105
|
|
106
|
-
it
|
106
|
+
it 'can insert next to a previous object' do
|
107
107
|
proc2 = appender_proc(2)
|
108
108
|
instance.use appender_proc(1)
|
109
109
|
instance.use proc2
|
@@ -113,7 +113,7 @@ describe Middleware::Builder do
|
|
113
113
|
expect(data[:data]).to eq [1, 3, 2]
|
114
114
|
end
|
115
115
|
|
116
|
-
it
|
116
|
+
it 'can insert before' do
|
117
117
|
instance.use appender_proc(1)
|
118
118
|
instance.insert_before 0, appender_proc(2)
|
119
119
|
instance.call(data)
|
@@ -121,12 +121,12 @@ describe Middleware::Builder do
|
|
121
121
|
expect(data[:data]).to eq [2, 1]
|
122
122
|
end
|
123
123
|
|
124
|
-
it
|
125
|
-
expect { instance.insert
|
126
|
-
to raise_error(RuntimeError)
|
124
|
+
it 'raises an exception if attempting to insert before an invalid object' do
|
125
|
+
expect { instance.insert 'object', appender_proc(1) }
|
126
|
+
.to raise_error(RuntimeError)
|
127
127
|
end
|
128
128
|
|
129
|
-
it
|
129
|
+
it 'can insert after each' do
|
130
130
|
instance.use appender_proc(1)
|
131
131
|
instance.use appender_proc(2)
|
132
132
|
instance.use appender_proc(3)
|
@@ -135,7 +135,7 @@ describe Middleware::Builder do
|
|
135
135
|
expect(data[:data]).to eq [1, 9, 2, 9, 3, 9]
|
136
136
|
end
|
137
137
|
|
138
|
-
it
|
138
|
+
it 'can insert before each' do
|
139
139
|
instance.use appender_proc(1)
|
140
140
|
instance.use appender_proc(2)
|
141
141
|
instance.use appender_proc(3)
|
@@ -144,14 +144,14 @@ describe Middleware::Builder do
|
|
144
144
|
expect(data[:data]).to eq [9, 1, 9, 2, 9, 3]
|
145
145
|
end
|
146
146
|
|
147
|
-
it
|
148
|
-
expect { instance.insert_after
|
149
|
-
to raise_error(RuntimeError)
|
147
|
+
it 'raises an exception if attempting to insert after an invalid object' do
|
148
|
+
expect { instance.insert_after 'object', appender_proc(1) }
|
149
|
+
.to raise_error(RuntimeError)
|
150
150
|
end
|
151
151
|
end
|
152
152
|
|
153
|
-
context
|
154
|
-
it
|
153
|
+
context 'replace' do
|
154
|
+
it 'can replace an object' do
|
155
155
|
proc1 = appender_proc(1)
|
156
156
|
proc2 = appender_proc(2)
|
157
157
|
|
@@ -162,7 +162,7 @@ describe Middleware::Builder do
|
|
162
162
|
expect(data[:data]).to eq [2]
|
163
163
|
end
|
164
164
|
|
165
|
-
it
|
165
|
+
it 'can replace by index' do
|
166
166
|
proc1 = appender_proc(1)
|
167
167
|
proc2 = appender_proc(2)
|
168
168
|
|
@@ -174,8 +174,8 @@ describe Middleware::Builder do
|
|
174
174
|
end
|
175
175
|
end
|
176
176
|
|
177
|
-
context
|
178
|
-
it
|
177
|
+
context 'deleting' do
|
178
|
+
it 'can delete by object' do
|
179
179
|
proc1 = appender_proc(1)
|
180
180
|
|
181
181
|
instance.use proc1
|
@@ -186,7 +186,7 @@ describe Middleware::Builder do
|
|
186
186
|
expect(data[:data]).to eq [2]
|
187
187
|
end
|
188
188
|
|
189
|
-
it
|
189
|
+
it 'can delete by index' do
|
190
190
|
proc1 = appender_proc(1)
|
191
191
|
|
192
192
|
instance.use proc1
|
@@ -198,11 +198,45 @@ describe Middleware::Builder do
|
|
198
198
|
end
|
199
199
|
end
|
200
200
|
|
201
|
-
context
|
202
|
-
|
201
|
+
context 'debugging' do
|
202
|
+
class Echo
|
203
|
+
def initialize app
|
204
|
+
@app = app
|
205
|
+
end
|
206
|
+
|
207
|
+
def call env
|
208
|
+
@app.call(env)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'has an inspect method' do
|
203
213
|
instance.use appender_proc(1)
|
204
214
|
instance.use appender_proc(1), 2
|
205
|
-
|
215
|
+
instance.use Echo, 'Hi, how are you?'
|
216
|
+
expect(instance.inspect).to eq 'Middleware[Proc(), Proc(2), Echo(Hi, how are you?)]'
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'displays his name in the inspect' do
|
220
|
+
middleware = described_class.new(name: 'Dumb') { |b|
|
221
|
+
b.use appender_proc(1)
|
222
|
+
}
|
223
|
+
expect(middleware.inspect).to eq 'Dumb[Proc()]'
|
224
|
+
end
|
225
|
+
|
226
|
+
it "can have a name" do
|
227
|
+
expect(described_class.new(name: 'Name').name).to eq 'Name'
|
228
|
+
end
|
229
|
+
|
230
|
+
it "can have a Logger" do
|
231
|
+
mocked_logger = instance_double(Logger)
|
232
|
+
expect(mocked_logger).to receive(:add).exactly(4).times
|
233
|
+
|
234
|
+
described_class.new(name: 'Dumb') { |b|
|
235
|
+
b.use Echo
|
236
|
+
b.use Echo
|
237
|
+
}.inject_logger(mocked_logger)
|
238
|
+
.call()
|
206
239
|
end
|
207
240
|
end
|
208
|
-
|
241
|
+
|
242
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative '../../lib/middleware/logger'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
class NEXT_Middleware
|
5
|
+
def initialize app
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call env
|
10
|
+
env
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
#Middleware.new('tchoutchou_orchestrator') {
|
15
|
+
#}.inject_logger(Logger.new IO::String(''))
|
16
|
+
|
17
|
+
describe Middleware::Logger do
|
18
|
+
|
19
|
+
it 'wrote the names of the next middleware in the logger' do
|
20
|
+
mocked_logger = instance_double('Logger');
|
21
|
+
expect(mocked_logger).to receive(:add).twice
|
22
|
+
|
23
|
+
described_class.new(NEXT_Middleware.new(nil), mocked_logger, 'dump_middleware').call(1)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#next_middleware_name' do
|
27
|
+
context 'when the next middleware is a Class' do
|
28
|
+
it 'extracts the next middleware name from the class name' do
|
29
|
+
expect(described_class.new(NEXT_Middleware.new(nil), nil).next_middleware_name).to eq 'NEXT_Middleware'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when the next middleware is a Lambda' do
|
34
|
+
it 'gives "Proc" for the next middleware' do
|
35
|
+
expect(described_class.new(->(env){env}, nil).next_middleware_name).to eq 'Proc'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#way_out_message' do
|
41
|
+
it 'returns a formatted message' do
|
42
|
+
expect(described_class.new(nil, nil).way_out_message('Dumb', 2400, [1, 2])).to eq " Dumb finished in 2400 ms and returned: [1, 2]\n"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#way_in_message' do
|
47
|
+
it 'returns a formatted message' do
|
48
|
+
expect(described_class.new(nil, nil).way_in_message('Dumb', [1, 2])).to eq " Dumb has been called with: [1, 2]\n"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#pretty_print' do
|
53
|
+
it 'pretty prints given var' do
|
54
|
+
expect(described_class.new(nil, nil).pretty_print([1, 2, 3, 4, 5])).to eq "[1, 2, 3, 4, 5]\n"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -1,21 +1,21 @@
|
|
1
|
-
require
|
1
|
+
require 'middleware'
|
2
2
|
|
3
3
|
describe Middleware::Runner do
|
4
|
-
it
|
4
|
+
it 'should work with an empty stack' do
|
5
5
|
instance = described_class.new([])
|
6
6
|
expect { instance.call({}) }.to_not raise_error
|
7
7
|
end
|
8
8
|
|
9
|
-
it
|
9
|
+
it 'should call classes in the proper order' do
|
10
10
|
a = Class.new do
|
11
11
|
def initialize(app)
|
12
12
|
@app = app
|
13
13
|
end
|
14
14
|
|
15
15
|
def call(env)
|
16
|
-
env[:result] <<
|
16
|
+
env[:result] << 'A'
|
17
17
|
@app.call(env)
|
18
|
-
env[:result] <<
|
18
|
+
env[:result] << 'A'
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -25,40 +25,40 @@ describe Middleware::Runner do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def call(env)
|
28
|
-
env[:result] <<
|
28
|
+
env[:result] << 'B'
|
29
29
|
@app.call(env)
|
30
|
-
env[:result] <<
|
30
|
+
env[:result] << 'B'
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
env = { :
|
34
|
+
env = { result: [] }
|
35
35
|
instance = described_class.new([a, b])
|
36
36
|
instance.call(env)
|
37
|
-
expect(env[:result]).to eq
|
37
|
+
expect(env[:result]).to eq %w(A B B A)
|
38
38
|
end
|
39
39
|
|
40
|
-
it
|
40
|
+
it 'should call lambdas in the proper order' do
|
41
41
|
data = []
|
42
|
-
a =
|
43
|
-
b =
|
42
|
+
a = ->(_env) { data << 'A' }
|
43
|
+
b = ->(_env) { data << 'B' }
|
44
44
|
|
45
45
|
instance = described_class.new([a, b])
|
46
46
|
instance.call({})
|
47
47
|
|
48
|
-
expect(data).to eq
|
48
|
+
expect(data).to eq %w(A B)
|
49
49
|
end
|
50
50
|
|
51
|
-
it
|
52
|
-
a =
|
53
|
-
b =
|
51
|
+
it 'should let lambdas to change the given argument' do
|
52
|
+
a = ->(env) { env + 1 }
|
53
|
+
b = ->(env) { env + 2 }
|
54
54
|
|
55
55
|
instance = described_class.new([a, b])
|
56
56
|
expect(instance.call(1)).to eq 4
|
57
57
|
end
|
58
58
|
|
59
|
-
it
|
59
|
+
it 'passes in arguments to lambda if given' do
|
60
60
|
data = []
|
61
|
-
a =
|
61
|
+
a = ->(_env, arg) { data << arg }
|
62
62
|
|
63
63
|
instance = described_class.new([[a, 1]])
|
64
64
|
instance.call(nil)
|
@@ -66,7 +66,7 @@ describe Middleware::Runner do
|
|
66
66
|
expect(data).to eq [1]
|
67
67
|
end
|
68
68
|
|
69
|
-
it
|
69
|
+
it 'passes in arguments if given' do
|
70
70
|
a = Class.new do
|
71
71
|
def initialize(app, value)
|
72
72
|
@app = app
|
@@ -85,9 +85,9 @@ describe Middleware::Runner do
|
|
85
85
|
expect(env[:result]).to eq 42
|
86
86
|
end
|
87
87
|
|
88
|
-
it
|
88
|
+
it 'passes in a block if given' do
|
89
89
|
a = Class.new do
|
90
|
-
def initialize(
|
90
|
+
def initialize(_app, &block)
|
91
91
|
@block = block
|
92
92
|
end
|
93
93
|
|
@@ -96,7 +96,7 @@ describe Middleware::Runner do
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
-
block =
|
99
|
+
block = proc { 42 }
|
100
100
|
env = {}
|
101
101
|
instance = described_class.new([[a, nil, block]])
|
102
102
|
instance.call(env)
|
@@ -104,7 +104,7 @@ describe Middleware::Runner do
|
|
104
104
|
expect(env[:result]).to eq 42
|
105
105
|
end
|
106
106
|
|
107
|
-
it
|
107
|
+
it 'should raise an error if an invalid middleware is given' do
|
108
108
|
expect { described_class.new([27]) }.to raise_error(/Invalid middleware/)
|
109
109
|
end
|
110
110
|
|
@@ -112,24 +112,26 @@ describe Middleware::Runner do
|
|
112
112
|
# A does not call B, so B should never execute
|
113
113
|
data = []
|
114
114
|
a = Class.new do
|
115
|
-
def initialize(app)
|
115
|
+
def initialize(app)
|
116
|
+
@app = app
|
117
|
+
end
|
116
118
|
|
117
|
-
define_method :call do |
|
118
|
-
data <<
|
119
|
+
define_method :call do |_env|
|
120
|
+
data << 'a'
|
119
121
|
end
|
120
122
|
end
|
121
123
|
|
122
|
-
b =
|
124
|
+
b = ->(_env) { data << 'b' }
|
123
125
|
|
124
126
|
env = {}
|
125
127
|
instance = described_class.new([a, b])
|
126
128
|
instance.call(env)
|
127
129
|
|
128
|
-
expect(data).to eq [
|
130
|
+
expect(data).to eq ['a']
|
129
131
|
end
|
130
132
|
|
131
|
-
describe
|
132
|
-
it
|
133
|
+
describe 'exceptions' do
|
134
|
+
it 'should propagate the exception up the middleware chain' do
|
133
135
|
# This tests a few important properties:
|
134
136
|
# * Exceptions propagate multiple middlewares
|
135
137
|
# - C raises an exception, which raises through B to A.
|
@@ -141,70 +143,76 @@ describe Middleware::Runner do
|
|
141
143
|
end
|
142
144
|
|
143
145
|
define_method :call do |env|
|
144
|
-
data <<
|
146
|
+
data << 'a'
|
145
147
|
begin
|
146
148
|
@app.call(env)
|
147
|
-
data <<
|
149
|
+
data << 'never'
|
148
150
|
rescue Exception => e
|
149
|
-
data <<
|
151
|
+
data << 'e'
|
150
152
|
raise
|
151
153
|
end
|
152
154
|
end
|
153
155
|
end
|
154
156
|
|
155
157
|
b = Class.new do
|
156
|
-
def initialize(app)
|
158
|
+
def initialize(app)
|
159
|
+
@app = app
|
160
|
+
end
|
157
161
|
|
158
162
|
define_method :call do |env|
|
159
|
-
data <<
|
163
|
+
data << 'b'
|
160
164
|
@app.call(env)
|
161
165
|
end
|
162
166
|
end
|
163
167
|
|
164
|
-
c =
|
168
|
+
c = ->(_env) { fail 'ERROR' }
|
165
169
|
|
166
170
|
env = {}
|
167
171
|
instance = described_class.new([a, b, c])
|
168
172
|
expect { instance.call(env) }.to raise_error 'ERROR'
|
169
173
|
|
170
|
-
expect(data).to eq
|
174
|
+
expect(data).to eq %w(a b e)
|
171
175
|
end
|
172
176
|
|
173
|
-
it
|
177
|
+
it 'should stop propagation if rescued' do
|
174
178
|
# This test mainly tests that if there is a sequence A, B, C, and
|
175
179
|
# an exception is raised in C, that if B rescues this, then the chain
|
176
180
|
# continues fine backwards.
|
177
181
|
data = []
|
178
182
|
a = Class.new do
|
179
|
-
def initialize(app)
|
183
|
+
def initialize(app)
|
184
|
+
@app = app
|
185
|
+
end
|
180
186
|
|
181
187
|
define_method :call do |env|
|
182
|
-
data <<
|
188
|
+
data << 'in_a'
|
183
189
|
@app.call(env)
|
184
|
-
data <<
|
190
|
+
data << 'out_a'
|
185
191
|
end
|
186
192
|
end
|
187
193
|
|
188
194
|
b = Class.new do
|
189
|
-
def initialize(app)
|
195
|
+
def initialize(app)
|
196
|
+
@app = app
|
197
|
+
end
|
190
198
|
|
191
199
|
define_method :call do |env|
|
192
|
-
data <<
|
200
|
+
data << 'in_b'
|
193
201
|
@app.call(env) rescue nil
|
194
|
-
data <<
|
202
|
+
data << 'out_b'
|
195
203
|
end
|
196
204
|
end
|
197
205
|
|
198
|
-
c = lambda do |
|
199
|
-
data <<
|
200
|
-
|
206
|
+
c = lambda do |_env|
|
207
|
+
data << 'in_c'
|
208
|
+
fail 'BAD'
|
201
209
|
end
|
202
210
|
|
203
211
|
env = {}
|
204
212
|
instance = described_class.new([a, b, c])
|
205
213
|
instance.call(env)
|
206
214
|
|
207
|
-
expect(data).to eq
|
215
|
+
expect(data).to eq %w(in_a in_b in_c out_b out_a)
|
208
216
|
end
|
209
217
|
end
|
210
218
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'codeclimate-test-reporter'
|
2
2
|
CodeClimate::TestReporter.start
|
3
3
|
# This file was generated by the `rspec --init` command. Conventionally, all
|
4
4
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
@@ -42,50 +42,48 @@ RSpec.configure do |config|
|
|
42
42
|
|
43
43
|
# The settings below are suggested to provide a good initial experience
|
44
44
|
# with RSpec, but feel free to customize to your heart's content.
|
45
|
-
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
config.
|
51
|
-
|
52
|
-
|
53
|
-
#
|
54
|
-
#
|
55
|
-
# - http://
|
56
|
-
# - http://
|
57
|
-
#
|
58
|
-
|
59
|
-
|
60
|
-
#
|
61
|
-
#
|
62
|
-
|
63
|
-
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
|
78
|
-
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
|
84
|
-
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
Kernel.srand config.seed
|
90
|
-
=end
|
45
|
+
# # These two settings work together to allow you to limit a spec run
|
46
|
+
# # to individual examples or groups you care about by tagging them with
|
47
|
+
# # `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
48
|
+
# # get run.
|
49
|
+
# config.filter_run :focus
|
50
|
+
# config.run_all_when_everything_filtered = true
|
51
|
+
#
|
52
|
+
# # Limits the available syntax to the non-monkey patched syntax that is recommended.
|
53
|
+
# # For more details, see:
|
54
|
+
# # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
55
|
+
# # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
56
|
+
# # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
|
57
|
+
# config.disable_monkey_patching!
|
58
|
+
#
|
59
|
+
# # This setting enables warnings. It's recommended, but in some cases may
|
60
|
+
# # be too noisy due to issues in dependencies.
|
61
|
+
# config.warnings = true
|
62
|
+
#
|
63
|
+
# # Many RSpec users commonly either run the entire suite or an individual
|
64
|
+
# # file, and it's useful to allow more verbose output when running an
|
65
|
+
# # individual spec file.
|
66
|
+
# if config.files_to_run.one?
|
67
|
+
# # Use the documentation formatter for detailed output,
|
68
|
+
# # unless a formatter has already been configured
|
69
|
+
# # (e.g. via a command-line flag).
|
70
|
+
# config.default_formatter = 'doc'
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# # Print the 10 slowest examples and example groups at the
|
74
|
+
# # end of the spec run, to help surface which specs are running
|
75
|
+
# # particularly slow.
|
76
|
+
# config.profile_examples = 10
|
77
|
+
#
|
78
|
+
# # Run specs in random order to surface order dependencies. If you find an
|
79
|
+
# # order dependency and want to debug it, you can fix the order by providing
|
80
|
+
# # the seed, which is printed after each run.
|
81
|
+
# # --seed 1234
|
82
|
+
# config.order = :random
|
83
|
+
#
|
84
|
+
# # Seed global randomization in this process using the `--seed` CLI option.
|
85
|
+
# # Setting this allows you to use `--seed` to deterministically reproduce
|
86
|
+
# # test failures related to randomization by passing the same `--seed` value
|
87
|
+
# # as the one that triggered the failure.
|
88
|
+
# Kernel.srand config.seed
|
91
89
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ibsciss-middleware
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mitchell Hashimoto
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-11-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -98,9 +98,11 @@ files:
|
|
98
98
|
- Rakefile
|
99
99
|
- lib/middleware.rb
|
100
100
|
- lib/middleware/builder.rb
|
101
|
+
- lib/middleware/logger.rb
|
101
102
|
- lib/middleware/runner.rb
|
102
103
|
- middleware.gemspec
|
103
104
|
- spec/middleware/builder_spec.rb
|
105
|
+
- spec/middleware/logger_spec.rb
|
104
106
|
- spec/middleware/runner_spec.rb
|
105
107
|
- spec/spec_helper.rb
|
106
108
|
homepage: https://github.com/ibsciss/ruby-middleware
|
@@ -130,5 +132,6 @@ summary: Generalized implementation of the rack middleware abstraction for Ruby
|
|
130
132
|
of responsibility design pattern).
|
131
133
|
test_files:
|
132
134
|
- spec/middleware/builder_spec.rb
|
135
|
+
- spec/middleware/logger_spec.rb
|
133
136
|
- spec/middleware/runner_spec.rb
|
134
137
|
- spec/spec_helper.rb
|