ibsciss-middleware 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Code Climate](https://codeclimate.com/github/Ibsciss/ruby-middleware/badges/gpa.svg)](https://codeclimate.com/github/Ibsciss/ruby-middleware)
|
2
|
+
[![Test Coverage](https://codeclimate.com/github/Ibsciss/ruby-middleware/badges/coverage.svg)](https://codeclimate.com/github/Ibsciss/ruby-middleware)
|
3
|
+
[![Build Status](https://semaphoreci.com/api/v1/projects/c5797935-6c93-4596-a8a8-bd45c8c584e9/393201/shields_badge.svg)](https://semaphoreci.com/lilobase/ruby-middleware)
|
4
|
+
|
1
5
|
# Middleware
|
2
6
|
|
3
|
-
|
4
|
-
|
7
|
+
[![Join the chat at https://gitter.im/Ibsciss/ruby-middleware](https://badges.gitter.im/Join%20Chat.svg)](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
|