meddleware 0.2.0 → 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 +36 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +42 -0
- data/LICENSE.txt +21 -0
- data/README.md +145 -0
- data/lib/meddleware/stack.rb +187 -0
- data/lib/meddleware/version.rb +2 -2
- data/lib/meddleware.rb +15 -178
- data/meddleware.gemspec +19 -0
- metadata +22 -54
- data/lib/meddleware/v2_5.rb +0 -143
- data/spec/build_meddleware_spec.rb +0 -479
- data/spec/call_meddleware_chain_spec.rb +0 -74
- data/spec/call_meddleware_spec.rb +0 -266
- data/spec/readme/full_example_spec.rb +0 -60
- data/spec/readme/usage_spec.rb +0 -47
@@ -1,479 +0,0 @@
|
|
1
|
-
A = Class.new(Meddler)
|
2
|
-
B = Class.new(Meddler)
|
3
|
-
C = Class.new(Meddler)
|
4
|
-
|
5
|
-
|
6
|
-
describe Meddleware do
|
7
|
-
subject { described_class.new }
|
8
|
-
|
9
|
-
def stack
|
10
|
-
subject.send(:build_chain).map &:class
|
11
|
-
end
|
12
|
-
|
13
|
-
shared_examples 'a middleware adder method' do |name|
|
14
|
-
let(:function) do
|
15
|
-
subject.method(name).yield_self do |fn|
|
16
|
-
if fn.arity < -1
|
17
|
-
# needs prefix arg, eg. :before/:after
|
18
|
-
proc {|*args, &block| fn.call(nil, *args, &block) }
|
19
|
-
else
|
20
|
-
fn
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'adds middleware to the stack' do
|
26
|
-
function.call(A)
|
27
|
-
expect(stack).to eq [ A ]
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'does not add duplicates' do
|
31
|
-
3.times { function.call(A) }
|
32
|
-
expect(stack).to eq [ A ]
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'returns self' do
|
36
|
-
expect(function.call(A)).to be subject
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'is idempotent' do
|
40
|
-
subject.use A
|
41
|
-
function.call(B)
|
42
|
-
res = stack
|
43
|
-
|
44
|
-
function.call(B)
|
45
|
-
expect(stack).to eq res
|
46
|
-
end
|
47
|
-
|
48
|
-
context 'with arguments' do
|
49
|
-
after { subject.send :build_chain }
|
50
|
-
|
51
|
-
it 'accepts an argument' do
|
52
|
-
expect(A).to receive(:new).with(:abc)
|
53
|
-
function.call(A, :abc)
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'accepts multiple arguments' do
|
57
|
-
expect(A).to receive(:new).with(:abc, :xyz)
|
58
|
-
function.call(A, :abc, :xyz)
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'accepts kwargs' do
|
62
|
-
expect(A).to receive(:new).with(a: 1, b: 2)
|
63
|
-
function.call(A, a: 1, b: 2)
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'works with all forms of kwargs' do
|
67
|
-
expect(A).to receive(:new).with(a: 1, b: 2)
|
68
|
-
function.call(A, { a: 1, b: 2 })
|
69
|
-
|
70
|
-
expect(B).to receive(:new).with({ a: 1, b: 2 })
|
71
|
-
function.call(B, { a: 1, b: 2 })
|
72
|
-
|
73
|
-
expect(C).to receive(:new).with({ a: 1, b: 2 })
|
74
|
-
function.call(C, a: 1, b: 2)
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'works with both args and kwargs' do
|
78
|
-
expect(A).to receive(:new).with(:abc, a: 1, b: 2)
|
79
|
-
function.call(A, :abc, a: 1, b: 2)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
context 'when middleware is an instance' do
|
84
|
-
it 'adds middleware to the stack' do
|
85
|
-
function.call(A.new)
|
86
|
-
expect(stack).to eq [ A ]
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'will add multiple instances of the same class' do
|
90
|
-
function.call(A.new)
|
91
|
-
function.call(A.new)
|
92
|
-
expect(stack).to eq [ A, A ]
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
context 'when middleware is a block' do
|
97
|
-
it 'accepts procs' do
|
98
|
-
function.call(Proc.new {})
|
99
|
-
expect(stack).to eq [ Proc ]
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'accepts lambdas' do
|
103
|
-
function.call(-> {})
|
104
|
-
expect(stack).to eq [ Proc ]
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'accepts inline blocks' do
|
108
|
-
function.call {}
|
109
|
-
expect(stack).to eq [ Proc ]
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
context 'when middleware is invalid' do
|
114
|
-
it 'rejects classes that do not implement `.call`' do
|
115
|
-
expect {
|
116
|
-
function.call(Class.new)
|
117
|
-
}.to raise_error(ArgumentError)
|
118
|
-
end
|
119
|
-
|
120
|
-
it 'rejects instances that do not respond to `.call`' do
|
121
|
-
expect {
|
122
|
-
function.call(123)
|
123
|
-
}.to raise_error(ArgumentError)
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'fails when both instance and block are passed' do
|
127
|
-
expect {
|
128
|
-
function.call(A.new) {}
|
129
|
-
}.to raise_error(ArgumentError)
|
130
|
-
end
|
131
|
-
|
132
|
-
it 'rejects nil' do
|
133
|
-
expect {
|
134
|
-
function.call(nil)
|
135
|
-
}.to raise_error(ArgumentError)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
describe '#use' do
|
141
|
-
it_behaves_like 'a middleware adder method', :use
|
142
|
-
|
143
|
-
it 'appends middleware in order' do
|
144
|
-
subject.use A
|
145
|
-
subject.use B
|
146
|
-
expect(stack).to eq [ A, B ]
|
147
|
-
end
|
148
|
-
|
149
|
-
it 'reorders duplicates' do
|
150
|
-
subject.use A
|
151
|
-
subject.use B
|
152
|
-
subject.use A
|
153
|
-
expect(stack).to eq [ B, A ]
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
describe '#prepend' do
|
158
|
-
it_behaves_like 'a middleware adder method', :prepend
|
159
|
-
|
160
|
-
it 'prepends middleware in order' do
|
161
|
-
subject.prepend A
|
162
|
-
subject.prepend B
|
163
|
-
expect(stack).to eq [ B, A ]
|
164
|
-
end
|
165
|
-
|
166
|
-
it 'reorders duplicates' do
|
167
|
-
subject.prepend A
|
168
|
-
subject.prepend B
|
169
|
-
subject.prepend A
|
170
|
-
expect(stack).to eq [ A, B ]
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
describe '#after' do
|
175
|
-
it_behaves_like 'a middleware adder method', :after
|
176
|
-
|
177
|
-
it 'adds middleware where specified' do
|
178
|
-
subject.use A
|
179
|
-
subject.use B
|
180
|
-
subject.after A, C
|
181
|
-
expect(stack).to eq [ A, C, B ]
|
182
|
-
end
|
183
|
-
|
184
|
-
it 'maintans order for duplicates' do
|
185
|
-
subject.use A
|
186
|
-
subject.use B
|
187
|
-
subject.after A, C
|
188
|
-
subject.after A, C
|
189
|
-
expect(stack).to eq [ A, C, B ]
|
190
|
-
end
|
191
|
-
|
192
|
-
it 'works when target is missing' do
|
193
|
-
subject.use A
|
194
|
-
subject.after B, C
|
195
|
-
expect(stack).to eq [ A, C ]
|
196
|
-
end
|
197
|
-
|
198
|
-
it 'works when target is nil' do
|
199
|
-
subject.use A
|
200
|
-
subject.after nil, C
|
201
|
-
expect(stack).to eq [ A, C ]
|
202
|
-
end
|
203
|
-
|
204
|
-
context 'when target is an array' do
|
205
|
-
before do
|
206
|
-
subject.use A
|
207
|
-
subject.use B
|
208
|
-
end
|
209
|
-
|
210
|
-
it 'inserts after the last target' do
|
211
|
-
subject.after [ A, B ], C
|
212
|
-
expect(stack).to eq [ A, B, C ]
|
213
|
-
end
|
214
|
-
|
215
|
-
it 'ignores missing targets' do
|
216
|
-
subject.after [ A, Meddler ], C
|
217
|
-
expect(stack).to eq [ A, C, B ]
|
218
|
-
end
|
219
|
-
|
220
|
-
it 'handles nil targets' do
|
221
|
-
subject.after [ nil, A ], C
|
222
|
-
expect(stack).to eq [ A, C, B ]
|
223
|
-
end
|
224
|
-
|
225
|
-
it 'handles an empty array' do
|
226
|
-
subject.after [], C
|
227
|
-
expect(stack).to eq [ A, B, C ]
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
describe '#before' do
|
233
|
-
it_behaves_like 'a middleware adder method', :before
|
234
|
-
|
235
|
-
it 'adds middleware where specified' do
|
236
|
-
subject.use A
|
237
|
-
subject.use B
|
238
|
-
subject.before B, C
|
239
|
-
expect(stack).to eq [ A, C, B ]
|
240
|
-
end
|
241
|
-
|
242
|
-
it 'maintans order for duplicates' do
|
243
|
-
subject.use A
|
244
|
-
subject.use B
|
245
|
-
subject.before B, C
|
246
|
-
subject.before B, C
|
247
|
-
expect(stack).to eq [ A, C, B ]
|
248
|
-
end
|
249
|
-
|
250
|
-
it 'works when target is missing' do
|
251
|
-
subject.use A
|
252
|
-
subject.before B, C
|
253
|
-
expect(stack).to eq [ C, A ]
|
254
|
-
end
|
255
|
-
|
256
|
-
it 'works when target is nil' do
|
257
|
-
subject.use A
|
258
|
-
subject.before nil, C
|
259
|
-
expect(stack).to eq [ C, A ]
|
260
|
-
end
|
261
|
-
|
262
|
-
context 'when target is an array' do
|
263
|
-
before do
|
264
|
-
subject.use A
|
265
|
-
subject.use B
|
266
|
-
end
|
267
|
-
|
268
|
-
it 'inserts before the first target' do
|
269
|
-
subject.before [ A, B ], C
|
270
|
-
expect(stack).to eq [ C, A, B ]
|
271
|
-
end
|
272
|
-
|
273
|
-
it 'ignores missing targets' do
|
274
|
-
subject.before [ B, Meddler ], C
|
275
|
-
expect(stack).to eq [ A, C, B ]
|
276
|
-
end
|
277
|
-
|
278
|
-
it 'handles nil targets' do
|
279
|
-
subject.before [ nil, B ], C
|
280
|
-
expect(stack).to eq [ A, C, B ]
|
281
|
-
end
|
282
|
-
|
283
|
-
it 'handles an empty array' do
|
284
|
-
subject.before [], C
|
285
|
-
expect(stack).to eq [ C, A, B ]
|
286
|
-
end
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
describe '#empty?' do
|
291
|
-
it 'works with empty middleware' do
|
292
|
-
expect(subject).to be_empty
|
293
|
-
expect(subject.empty?).to be true
|
294
|
-
expect(stack.empty?).to be true
|
295
|
-
end
|
296
|
-
|
297
|
-
it 'works with middleware' do
|
298
|
-
subject.use A
|
299
|
-
expect(subject).not_to be_empty
|
300
|
-
expect(subject.empty?).to be false
|
301
|
-
expect(stack.empty?).to be false
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
describe '#clear' do
|
306
|
-
it 'works' do
|
307
|
-
subject.use A
|
308
|
-
subject.clear
|
309
|
-
expect(subject).to be_empty
|
310
|
-
end
|
311
|
-
|
312
|
-
it 'works with an empty stack' do
|
313
|
-
subject.clear
|
314
|
-
expect(subject).to be_empty
|
315
|
-
end
|
316
|
-
end
|
317
|
-
|
318
|
-
describe '#count' do
|
319
|
-
it 'works' do
|
320
|
-
expect(subject.count).to be 0
|
321
|
-
|
322
|
-
subject.use A
|
323
|
-
expect(subject.count).to be 1
|
324
|
-
|
325
|
-
subject.use B
|
326
|
-
expect(subject.count).to be 2
|
327
|
-
|
328
|
-
subject.remove B
|
329
|
-
expect(subject.count).to be 1
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
describe '#include?' do
|
334
|
-
before do
|
335
|
-
subject.use A
|
336
|
-
end
|
337
|
-
|
338
|
-
it 'finds existing middleware' do
|
339
|
-
is_expected.to include A
|
340
|
-
end
|
341
|
-
|
342
|
-
it 'handles missing middleware' do
|
343
|
-
is_expected.not_to include B
|
344
|
-
end
|
345
|
-
|
346
|
-
it 'handles nil' do
|
347
|
-
is_expected.not_to include nil
|
348
|
-
end
|
349
|
-
|
350
|
-
context 'with multiple targets' do
|
351
|
-
it 'requires all targets to exist' do
|
352
|
-
expect(subject.include?(A, B)).to be false
|
353
|
-
end
|
354
|
-
|
355
|
-
it 'works when all targets exist' do
|
356
|
-
subject.use B
|
357
|
-
expect(subject.include?(A, B)).to be true
|
358
|
-
end
|
359
|
-
|
360
|
-
it 'handles nil' do
|
361
|
-
expect(subject.include?(A, nil)).to be false
|
362
|
-
end
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
describe '#remove' do
|
367
|
-
before do
|
368
|
-
subject.use A
|
369
|
-
subject.use B
|
370
|
-
subject.use C
|
371
|
-
expect(stack).to eq [ A, B, C ]
|
372
|
-
end
|
373
|
-
|
374
|
-
it 'removes middleware' do
|
375
|
-
subject.remove(B)
|
376
|
-
expect(stack).to eq [ A, C ]
|
377
|
-
subject.remove(A)
|
378
|
-
expect(stack).to eq [ C ]
|
379
|
-
subject.remove(C)
|
380
|
-
expect(subject).to be_empty
|
381
|
-
end
|
382
|
-
|
383
|
-
it 'is idempotent' do
|
384
|
-
3.times { subject.remove(A) }
|
385
|
-
expect(stack).to eq [ B, C ]
|
386
|
-
end
|
387
|
-
|
388
|
-
it 'works with nil' do
|
389
|
-
subject.remove(nil)
|
390
|
-
expect(stack).to eq [ A, B, C ]
|
391
|
-
end
|
392
|
-
|
393
|
-
context 'with multiple targets' do
|
394
|
-
it 'removes multiple middleware' do
|
395
|
-
subject.remove(A, B)
|
396
|
-
expect(stack).to eq [ C ]
|
397
|
-
end
|
398
|
-
|
399
|
-
it 'handles redundancy' do
|
400
|
-
subject.remove(A, A)
|
401
|
-
expect(stack).to eq [ B, C ]
|
402
|
-
end
|
403
|
-
|
404
|
-
it 'handles nil' do
|
405
|
-
subject.remove(A, nil)
|
406
|
-
expect(stack).to eq [ B, C ]
|
407
|
-
end
|
408
|
-
end
|
409
|
-
end
|
410
|
-
|
411
|
-
describe '#replace' do
|
412
|
-
before do
|
413
|
-
subject.use A
|
414
|
-
subject.use B
|
415
|
-
|
416
|
-
expect(stack).to eq [ A, B ]
|
417
|
-
end
|
418
|
-
|
419
|
-
it 'replaces middleware' do
|
420
|
-
subject.replace(A, C)
|
421
|
-
expect(stack).to eq [ C, B ]
|
422
|
-
end
|
423
|
-
|
424
|
-
it 'works with middleware instances' do
|
425
|
-
instance = A.new
|
426
|
-
subject.replace(A, instance)
|
427
|
-
|
428
|
-
expect(subject).to include instance
|
429
|
-
expect(subject).not_to include A
|
430
|
-
|
431
|
-
subject.replace(instance, B)
|
432
|
-
expect(stack).to eq [ B ]
|
433
|
-
end
|
434
|
-
|
435
|
-
it 'fails when target middleware is missing' do
|
436
|
-
expect {
|
437
|
-
subject.replace(C, C)
|
438
|
-
}.to raise_error(RuntimeError)
|
439
|
-
end
|
440
|
-
|
441
|
-
it 'fails when middleware is invalid' do
|
442
|
-
expect {
|
443
|
-
subject.replace(A, nil)
|
444
|
-
}.to raise_error(ArgumentError)
|
445
|
-
end
|
446
|
-
end
|
447
|
-
|
448
|
-
describe '.new' do
|
449
|
-
it 'supports block mode' do
|
450
|
-
instance = described_class.new do
|
451
|
-
use A
|
452
|
-
prepend B
|
453
|
-
end
|
454
|
-
|
455
|
-
expect(instance).to include A
|
456
|
-
expect(instance).to include B
|
457
|
-
end
|
458
|
-
end
|
459
|
-
|
460
|
-
describe '#index' do
|
461
|
-
before do
|
462
|
-
subject.use A
|
463
|
-
subject.use B
|
464
|
-
end
|
465
|
-
|
466
|
-
it do
|
467
|
-
expect(subject.send(:index, A)).to be 0
|
468
|
-
expect(subject.send(:index, B)).to be 1
|
469
|
-
expect(subject.send(:index, C)).to be nil
|
470
|
-
expect(subject.send(:index, nil)).to be nil
|
471
|
-
end
|
472
|
-
|
473
|
-
it 'is a private method' do
|
474
|
-
expect {
|
475
|
-
subject.index
|
476
|
-
}.to raise_error(NoMethodError)
|
477
|
-
end
|
478
|
-
end
|
479
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
describe 'Meddleware#call' do
|
2
|
-
subject { Meddleware.new }
|
3
|
-
|
4
|
-
let(:middleware_one) { Meddler.new }
|
5
|
-
let(:middleware_two) { Meddler.new }
|
6
|
-
|
7
|
-
before do
|
8
|
-
subject.use middleware_one
|
9
|
-
subject.use middleware_two
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'calls the whole chain' do
|
13
|
-
expect(middleware_one).to receive(:call).and_yield
|
14
|
-
expect(middleware_two).to receive(:call).and_yield
|
15
|
-
|
16
|
-
expect {|b| subject.call(&b) }.to yield_control
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'stops propagation if a middleware does not yield' do
|
20
|
-
expect(middleware_one).to receive(:call).and_yield
|
21
|
-
expect(middleware_two).to receive(:call)
|
22
|
-
|
23
|
-
expect {|b| subject.call(&b) }.not_to yield_control
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'recurses' do
|
27
|
-
order = []
|
28
|
-
|
29
|
-
expect(middleware_one).to receive(:call) do |&block|
|
30
|
-
order << 1
|
31
|
-
block.call
|
32
|
-
order << 5
|
33
|
-
end
|
34
|
-
|
35
|
-
expect(middleware_two).to receive(:call) do |&block|
|
36
|
-
order << 2
|
37
|
-
block.call
|
38
|
-
order << 4
|
39
|
-
end
|
40
|
-
|
41
|
-
subject.call { order << 3 }
|
42
|
-
expect(order).to eq((1..5).to_a)
|
43
|
-
end
|
44
|
-
|
45
|
-
context 'when arguments are altered' do
|
46
|
-
before do
|
47
|
-
expect(middleware_one).to receive(:call) do |x, &block|
|
48
|
-
block.call(x * 2)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'propagates them' do
|
53
|
-
expect(middleware_two).to receive(:call) do |x, &block|
|
54
|
-
expect(x).to be 2
|
55
|
-
block.call(x * 3)
|
56
|
-
end
|
57
|
-
|
58
|
-
subject.call(1) do |x|
|
59
|
-
expect(x).to be 6
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'propagates them as default arguments' do
|
64
|
-
expect(middleware_two).to receive(:call) do |x, &block|
|
65
|
-
expect(x).to be 2
|
66
|
-
block.call
|
67
|
-
end
|
68
|
-
|
69
|
-
subject.call(1) do |x|
|
70
|
-
expect(x).to be 2
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|