ibsciss-middleware 0.3.1 → 0.3.2
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 +6 -0
- data/LICENSE +1 -0
- data/README.md +134 -11
- data/lib/middleware/builder.rb +28 -0
- data/lib/middleware/runner.rb +1 -1
- data/middleware.gemspec +3 -2
- data/spec/middleware/builder_spec.rb +20 -3
- data/spec/middleware/runner_spec.rb +11 -2
- data/spec/spec_helper.rb +2 -0
- metadata +18 -5
- data/.travis.yml +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab6d4d8a9225726d9aa68a41d4be42bcac71bc23
|
4
|
+
data.tar.gz: 4df6dce76dca18f51c8af01a3be56e5861d8fe4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e33e2f98cc16cf4dcf6ee076cf1734b1cf8bac3ef17daf7d8aa97636510d739e4af7f851d0adacb75444844e3c9eba401e5f22c787406adac6badab48ffc7ab4
|
7
|
+
data.tar.gz: c9f1537de72e76797a690c23646640655ca9ed4adfbefae661bef899cac998efb073d199ab9ec3854de9a4cbfa9d4e36322b24d2c201be2530528fcafd9cb734
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 0.3.2
|
2
|
+
- Add CI & Code Climate & Improve documentation
|
3
|
+
|
4
|
+
## 0.3.1
|
5
|
+
- Enable lambda to change the given object
|
6
|
+
|
1
7
|
## 0.3.0
|
2
8
|
- Apply https://github.com/Ibsciss/ruby-middleware/commit/01f75d8e4137b39ea907f13756f21cba4edffaa7
|
3
9
|
- Apply https://github.com/Ibsciss/ruby-middleware/commit/00aa09353f7ee2b801bdb446418a936640ae56d7
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,21 @@
|
|
1
|
+
[](https://codeclimate.com/github/Ibsciss/ruby-middleware)
|
2
|
+
[](https://codeclimate.com/github/Ibsciss/ruby-middleware)
|
3
|
+
[](https://semaphoreci.com/lilobase/ruby-middleware)
|
4
|
+
|
1
5
|
# Middleware
|
2
6
|
|
3
|
-
|
4
|
-
|
7
|
+
[](https://gitter.im/Ibsciss/ruby-middleware?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
8
|
+
|
9
|
+
`Middleware` is a library which provides a generalized implementation
|
10
|
+
of the [chain of responsibility pattern](http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern) for Ruby.
|
11
|
+
|
12
|
+
This pattern is used in `Rack::Builder` or `ActionDispatch::MiddlewareStack` to manage a stack of middlewares. This gem is a generic implementation for any Ruby project.
|
13
|
+
|
14
|
+
The middleware pattern is a useful
|
5
15
|
abstraction tool in various cases, but is specifically useful for splitting
|
6
16
|
large sequential chunks of logic into small pieces.
|
7
17
|
|
8
|
-
This
|
18
|
+
This is an updated version of the original Mitchell Hashimoto's library: https://github.com/mitchellh/middleware
|
9
19
|
|
10
20
|
## Installing
|
11
21
|
|
@@ -15,6 +25,18 @@ Middleware is distributed as a RubyGem, so simply gem install:
|
|
15
25
|
$ gem install ibsciss-middleware
|
16
26
|
```
|
17
27
|
|
28
|
+
Or, in your Gemfile:
|
29
|
+
|
30
|
+
```
|
31
|
+
gem 'ibsciss-middleware', '~> 0.3'
|
32
|
+
```
|
33
|
+
|
34
|
+
Then, you can add it to your project:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
require 'middleware'
|
38
|
+
```
|
39
|
+
|
18
40
|
## A Basic Example
|
19
41
|
|
20
42
|
Below is a basic example of the library in use. If you don't understand
|
@@ -61,7 +83,6 @@ And the output:
|
|
61
83
|
```
|
62
84
|
|
63
85
|
|
64
|
-
|
65
86
|
## Middleware
|
66
87
|
|
67
88
|
### What is it?
|
@@ -103,9 +124,9 @@ class Trace
|
|
103
124
|
end
|
104
125
|
|
105
126
|
def call(env)
|
106
|
-
puts "
|
127
|
+
puts "Before next middleware execution"
|
107
128
|
@app.call(env)
|
108
|
-
puts "
|
129
|
+
puts "After next middleware execution"
|
109
130
|
end
|
110
131
|
end
|
111
132
|
```
|
@@ -119,14 +140,39 @@ A basic description of the two methods that a middleware must implement:
|
|
119
140
|
state sent in (defined by the caller, but usually a Hash). This call should also
|
120
141
|
call `app.call(env)` at some point to move on.
|
121
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:
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
class Greeting
|
148
|
+
def initialize(app, append = nil)
|
149
|
+
@app = app
|
150
|
+
@datas = datas
|
151
|
+
end
|
152
|
+
|
153
|
+
def call(env)
|
154
|
+
env = "#{append} #{env}"
|
155
|
+
result = @app(env)
|
156
|
+
"#{result} !"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
Middleware::Builder.new { |b|
|
161
|
+
b.use Greeting, 'Hello'
|
162
|
+
}.call('John') #return "Hello John !"
|
163
|
+
```
|
164
|
+
|
122
165
|
### Middleware Lambdas
|
123
166
|
|
124
167
|
A middleware can also be a simple lambda. The downside of using a lambda is that
|
125
168
|
it only has access to the state on the initial call, there is no "post" step for
|
126
|
-
lambdas
|
169
|
+
lambdas:
|
127
170
|
|
128
171
|
```ruby
|
129
|
-
|
172
|
+
Middleware::Builder.new { |b|
|
173
|
+
b.use lambda { |env| env + 3 }
|
174
|
+
b.use lambda { |env| env * 2 }
|
175
|
+
}.call(1) #return 8
|
130
176
|
```
|
131
177
|
|
132
178
|
## Middleware Stacks
|
@@ -148,10 +194,12 @@ end
|
|
148
194
|
```
|
149
195
|
|
150
196
|
This `stack` variable itself is now a valid middleware and has the same interface,
|
151
|
-
so to execute the stack, just call `call` on it:
|
197
|
+
so to execute the stack, just call `call` on it, so can compose middleware stack between them:
|
152
198
|
|
153
199
|
```ruby
|
154
|
-
|
200
|
+
Middleware::Builder.new do |d|
|
201
|
+
d.use stack
|
202
|
+
end.call()
|
155
203
|
```
|
156
204
|
|
157
205
|
The call method takes an optional parameter which is the state to pass into the
|
@@ -165,15 +213,62 @@ created. Given the `stack` variable created above, we can manipulate it as
|
|
165
213
|
follows. Please imagine that each example runs with the original `stack` variable,
|
166
214
|
so that the order of the examples doesn't actually matter:
|
167
215
|
|
216
|
+
#### Insert before
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
# Insert a new item before the Trace middleware
|
220
|
+
stack.insert_before Trace, SomeOtherMiddleware
|
221
|
+
|
222
|
+
# Insert a new item at the top of the middleware stack
|
223
|
+
stack.insert_before 0, SomeOtherMiddleware
|
224
|
+
```
|
225
|
+
|
226
|
+
#### Insert after
|
227
|
+
|
168
228
|
```ruby
|
169
229
|
# Insert a new item after the Trace middleware
|
170
230
|
stack.insert_after(Trace, SomeOtherMiddleware)
|
171
231
|
|
172
|
-
#
|
232
|
+
# Insert a new item after the first middleware
|
233
|
+
stack.insert_after(0, SomeOtherMiddleware)
|
234
|
+
```
|
235
|
+
|
236
|
+
#### Insert after each
|
237
|
+
|
238
|
+
```ruby
|
239
|
+
logger = lambda { |env| p env }
|
240
|
+
|
241
|
+
# Insert the middleware (can be also a middleware object) after each existing middleware
|
242
|
+
stack.insert_after_each logger
|
243
|
+
```
|
244
|
+
|
245
|
+
#### Insert before each
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
logger = lambda { |env| p env }
|
249
|
+
|
250
|
+
# Insert the middleware (can be also a middleware object) before each existing middleware
|
251
|
+
stack.insert_before_each logger
|
252
|
+
```
|
253
|
+
|
254
|
+
#### Replace
|
255
|
+
|
256
|
+
```ruby
|
257
|
+
# Replace the first middleware
|
173
258
|
stack.replace(1, SomeOtherMiddleware)
|
174
259
|
|
260
|
+
# Replace the Trace middleware
|
261
|
+
stack.replace(Trace, SomeOtherMiddleware)
|
262
|
+
```
|
263
|
+
|
264
|
+
#### Delete
|
265
|
+
|
266
|
+
```ruby
|
175
267
|
# Delete the lambda
|
176
268
|
stack.delete(1)
|
269
|
+
|
270
|
+
# Delete the Trace middleware
|
271
|
+
stack.delete(Trace)
|
177
272
|
```
|
178
273
|
|
179
274
|
### Passing Additional Constructor Arguments
|
@@ -206,3 +301,31 @@ end
|
|
206
301
|
Then when the stack is called, it will output "Hello, World!"
|
207
302
|
|
208
303
|
Note that you can also pass blocks in using the `use` method.
|
304
|
+
|
305
|
+
#### Lambda
|
306
|
+
|
307
|
+
Lambda work the same with additional arguments:
|
308
|
+
|
309
|
+
```ruby
|
310
|
+
Middleware::Builder.new { |b|
|
311
|
+
# arrow syntax for lambda construction
|
312
|
+
b.use ->(env, msg) { puts msg }, 'some message'
|
313
|
+
}.call(1) #will print "some message"
|
314
|
+
```
|
315
|
+
|
316
|
+
### Debug
|
317
|
+
|
318
|
+
You can see the content of a given stack using the `inspect` method
|
319
|
+
|
320
|
+
```ruby
|
321
|
+
Middleware::Builder.new { |b|
|
322
|
+
b.use Trace
|
323
|
+
b.use Echo, "Hello, World!"
|
324
|
+
}.inspect
|
325
|
+
```
|
326
|
+
|
327
|
+
the output will be
|
328
|
+
|
329
|
+
```ruby
|
330
|
+
[Trace(), Echo("Hello, World!")]
|
331
|
+
```
|
data/lib/middleware/builder.rb
CHANGED
@@ -92,6 +92,20 @@ module Middleware
|
|
92
92
|
insert(index + 1, middleware, *args, &block)
|
93
93
|
end
|
94
94
|
|
95
|
+
# Inserts a middleware before each middleware object
|
96
|
+
def insert_before_each(middleware, *args, &block)
|
97
|
+
self.stack = stack.reduce([]) do |carry, item|
|
98
|
+
carry.push([middleware, args, block], item)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Inserts a middleware after each middleware object
|
103
|
+
def insert_after_each(middleware, *args, &block)
|
104
|
+
self.stack = stack.reduce([]) do |carry, item|
|
105
|
+
carry.push(item, [middleware, args, block])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
95
109
|
# Replaces the given middleware object or index with the new
|
96
110
|
# middleware.
|
97
111
|
def replace(index, middleware, *args, &block)
|
@@ -115,6 +129,12 @@ module Middleware
|
|
115
129
|
to_app.call(env)
|
116
130
|
end
|
117
131
|
|
132
|
+
def inspect
|
133
|
+
"[" + stack.reduce([]) { |carry, middleware|
|
134
|
+
carry << "#{middleware[0].class.name}(#{middleware[1].join(', ')})"
|
135
|
+
}.join(', ') + "]"
|
136
|
+
end
|
137
|
+
|
118
138
|
protected
|
119
139
|
|
120
140
|
# Returns the numeric index for the given middleware object.
|
@@ -137,11 +157,19 @@ module Middleware
|
|
137
157
|
@stack ||= []
|
138
158
|
end
|
139
159
|
|
160
|
+
# you shouldn't use this method
|
161
|
+
#
|
162
|
+
# @return [Array]
|
163
|
+
def stack= stack
|
164
|
+
@stack = stack
|
165
|
+
end
|
166
|
+
|
140
167
|
# Converts the builder stack to a runnable action sequence.
|
141
168
|
#
|
142
169
|
# @return [Object] A callable object
|
143
170
|
def to_app
|
144
171
|
@runner_class.new(stack.dup)
|
145
172
|
end
|
173
|
+
|
146
174
|
end
|
147
175
|
end
|
data/lib/middleware/runner.rb
CHANGED
@@ -57,7 +57,7 @@ module Middleware
|
|
57
57
|
# Make it a lambda which calls the item then forwards up
|
58
58
|
# the chain.
|
59
59
|
lambda do |env|
|
60
|
-
next_middleware.call(klass.call(env))
|
60
|
+
next_middleware.call(klass.call(env, *args))
|
61
61
|
end
|
62
62
|
else
|
63
63
|
raise "Invalid middleware, doesn't respond to `call`: #{klass.inspect}"
|
data/middleware.gemspec
CHANGED
@@ -8,15 +8,16 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.homepage = "https://github.com/ibsciss/ruby-middleware"
|
9
9
|
gem.license = "MIT"
|
10
10
|
|
11
|
-
gem.add_development_dependency "rake", "~>
|
11
|
+
gem.add_development_dependency "rake", "~> 10.4.2"
|
12
12
|
gem.add_development_dependency "rspec-core", "~> 3.2"
|
13
13
|
gem.add_development_dependency "rspec-expectations", "~> 3.2"
|
14
14
|
gem.add_development_dependency "rspec-mocks", "~> 3.2"
|
15
|
+
gem.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.7'
|
15
16
|
|
16
17
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
18
|
gem.files = `git ls-files`.split("\n")
|
18
19
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
20
|
gem.name = "ibsciss-middleware"
|
20
21
|
gem.require_paths = ["lib"]
|
21
|
-
gem.version = '0.3.
|
22
|
+
gem.version = '0.3.2'
|
22
23
|
end
|
@@ -126,13 +126,22 @@ describe Middleware::Builder do
|
|
126
126
|
to raise_error(RuntimeError)
|
127
127
|
end
|
128
128
|
|
129
|
-
it "can insert after" do
|
129
|
+
it "can insert after each" do
|
130
130
|
instance.use appender_proc(1)
|
131
|
+
instance.use appender_proc(2)
|
131
132
|
instance.use appender_proc(3)
|
132
|
-
instance.
|
133
|
+
instance.insert_after_each appender_proc(9)
|
133
134
|
instance.call(data)
|
135
|
+
expect(data[:data]).to eq [1, 9, 2, 9, 3, 9]
|
136
|
+
end
|
134
137
|
|
135
|
-
|
138
|
+
it "can insert before each" do
|
139
|
+
instance.use appender_proc(1)
|
140
|
+
instance.use appender_proc(2)
|
141
|
+
instance.use appender_proc(3)
|
142
|
+
instance.insert_before_each appender_proc(9)
|
143
|
+
instance.call(data)
|
144
|
+
expect(data[:data]).to eq [9, 1, 9, 2, 9, 3]
|
136
145
|
end
|
137
146
|
|
138
147
|
it "raises an exception if attempting to insert after an invalid object" do
|
@@ -188,4 +197,12 @@ describe Middleware::Builder do
|
|
188
197
|
expect(data[:data]).to eq [2]
|
189
198
|
end
|
190
199
|
end
|
200
|
+
|
201
|
+
context "debugging" do
|
202
|
+
it "has an inspect method" do
|
203
|
+
instance.use appender_proc(1)
|
204
|
+
instance.use appender_proc(1), 2
|
205
|
+
expect(instance.inspect).to eq '[Proc(), Proc(2)]'
|
206
|
+
end
|
207
|
+
end
|
191
208
|
end
|
@@ -49,7 +49,6 @@ describe Middleware::Runner do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
it "should let lambdas to change the given argument" do
|
52
|
-
data = []
|
53
52
|
a = lambda { |env| env + 1 }
|
54
53
|
b = lambda { |env| env + 2 }
|
55
54
|
|
@@ -57,6 +56,16 @@ describe Middleware::Runner do
|
|
57
56
|
expect(instance.call(1)).to eq 4
|
58
57
|
end
|
59
58
|
|
59
|
+
it "passes in arguments to lambda if given" do
|
60
|
+
data = []
|
61
|
+
a = lambda { |env, arg| data << arg }
|
62
|
+
|
63
|
+
instance = described_class.new([[a, 1]])
|
64
|
+
instance.call(nil)
|
65
|
+
|
66
|
+
expect(data).to eq [1]
|
67
|
+
end
|
68
|
+
|
60
69
|
it "passes in arguments if given" do
|
61
70
|
a = Class.new do
|
62
71
|
def initialize(app, value)
|
@@ -156,7 +165,7 @@ describe Middleware::Runner do
|
|
156
165
|
|
157
166
|
env = {}
|
158
167
|
instance = described_class.new([a, b, c])
|
159
|
-
expect { instance.call(env) }.to raise_error
|
168
|
+
expect { instance.call(env) }.to raise_error 'ERROR'
|
160
169
|
|
161
170
|
expect(data).to eq ["a", "b", "e"]
|
162
171
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "codeclimate-test-reporter"
|
2
|
+
CodeClimate::TestReporter.start
|
1
3
|
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
4
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
5
|
# The generated `.rspec` file contains `--require spec_helper` which will cause this
|
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.3.
|
4
|
+
version: 0.3.2
|
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-08-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version:
|
20
|
+
version: 10.4.2
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version:
|
27
|
+
version: 10.4.2
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rspec-core
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,6 +67,20 @@ dependencies:
|
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '3.2'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: codeclimate-test-reporter
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 0.4.7
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 0.4.7
|
70
84
|
description: Generalized implementation of the rack middleware abstraction for Ruby.
|
71
85
|
email:
|
72
86
|
- mitchell.hashimoto@gmail.com
|
@@ -77,7 +91,6 @@ extra_rdoc_files: []
|
|
77
91
|
files:
|
78
92
|
- ".gitignore"
|
79
93
|
- ".rspec"
|
80
|
-
- ".travis.yml"
|
81
94
|
- CHANGELOG.md
|
82
95
|
- Gemfile
|
83
96
|
- LICENSE
|