meddleware 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af421278a6c18f72f28e6ad86e214bcbaab0e77cc9e77a58db94493045be3bf7
4
- data.tar.gz: 912d29bc7b291ad682cdf7aadcfd05631aec896cc578957048f233478f5cbb2f
3
+ metadata.gz: 453a4fea42903735f1b7e502f5fb5ba323ecfd1240db7d476453dabd0e773f8d
4
+ data.tar.gz: c459598e2a9145a7ad8a4128cefc5de8ed3a018db28e1cf95a24a26b15b42883
5
5
  SHA512:
6
- metadata.gz: 0b792cee28734eeea2b632d17e45ec139b92eaeb8dc8e5d9421dd27ebf54f62dbbf63453b526d50c483406f502dfff696785ea37a31ecbc988a295333b5c728f
7
- data.tar.gz: b854aa5aa9dee535ea746ac333dcbfd222a0a11dbc36d6262e96fe2930ef8827a5c93c08afb41d38564b79079d43d03b2225d8e0b87cbe7ce63c1ac5b1705965
6
+ metadata.gz: 94db19316854023dece52b027bd87f0c423936c3ccf4fba424b85eaa798672aa936820ecb0b5e427c5832c29fe7deb6dce876563c70c3869b15b1b137d26b511
7
+ data.tar.gz: 57188689d33ca8a987e4cdcde3792da430b86946c6c0ec99ace62b6e7be05c9658eacbc83f6e3cc26c20d3c8e06a47ef53fa4937919d7d4c1e49a556469cc0c3
data/lib/meddleware.rb CHANGED
@@ -1,77 +1,158 @@
1
1
  require 'meddleware/version'
2
2
 
3
3
  class Meddleware
4
- include Enumerable
5
-
6
- def initialize
4
+ def initialize(&block)
7
5
  instance_eval(&block) if block_given?
8
6
  end
9
7
 
10
- def each(&block)
11
- stack.each(&block)
8
+ def use(*klass_and_args, &block)
9
+ entry = create_entry(klass_and_args, block)
10
+ stack << entry
11
+ self
12
12
  end
13
+ alias append use
13
14
 
14
- def index(klass)
15
- stack.index {|entry| entry.klass == klass }
15
+ def prepend(*klass_and_args, &block)
16
+ entry = create_entry(klass_and_args, block)
17
+ stack.insert(0, entry)
18
+ self
16
19
  end
17
20
 
18
- def remove(klass)
19
- stack.reject! { |entry| entry.klass == klass }
21
+ def after(after_klass, *klass_and_args, &block)
22
+ entry = create_entry(klass_and_args, block)
23
+ i = index(after_klass) || count - 1
24
+ stack.insert(i + 1, entry)
25
+ self
20
26
  end
21
27
 
22
- def use(klass, *args)
23
- remove(klass)
24
- stack << Entry.new(klass, args)
28
+ def before(before_klass, *klass_and_args, &block)
29
+ entry = create_entry(klass_and_args, block)
30
+ i = index(before_klass) || 0
31
+ stack.insert(i, entry)
32
+ self
25
33
  end
26
- alias append use
27
34
 
28
- def prepend(klass, *args)
29
- remove(klass)
30
- stack.insert(0, Entry.new(klass, args))
35
+ def include?(klass)
36
+ !!index(klass)
31
37
  end
32
38
 
33
- def after(after_klass, klass, *args)
34
- remove(klass)
35
- i = index(after_klass) || count - 1
36
- stack.insert(i + 1, Entry.new(klass, args))
39
+ def remove(klass)
40
+ stack.reject! { |entry| entry[0] == klass }
41
+ self
37
42
  end
38
43
 
39
- def before(before_klass, klass, *args)
40
- remove(klass)
41
- i = index(before_klass) || 0
42
- stack.insert(i, Entry.new(klass, args))
44
+ def replace(old_klass, *klass_and_args, &block)
45
+ entry = create_entry(klass_and_args, block)
46
+ i = index(old_klass)
47
+
48
+ unless i
49
+ raise RuntimeError, "middleware not present: #{old_klass}"
50
+ end
51
+
52
+ stack[i] = entry
53
+ self
43
54
  end
44
55
 
45
- def empty?
46
- stack.empty?
56
+ def count
57
+ stack.count
47
58
  end
59
+ alias size count
48
60
 
49
61
  def clear
50
62
  stack.clear
51
63
  end
52
64
 
53
- def call(*args, &block)
54
- chain = map(&:build)
55
- traverse = proc do |*updated_args|
56
- args = updated_args unless updated_args.empty?
65
+ def empty?
66
+ stack.empty?
67
+ end
68
+
69
+ def call(*args)
70
+ chain = build_chain
71
+ default_args = args
72
+
73
+ traverse = proc do |*args|
74
+ if args.empty?
75
+ args = default_args
76
+ else
77
+ default_args = args
78
+ end
79
+
57
80
  if chain.empty?
58
- yield *args
81
+ yield(*args) if block_given?
59
82
  else
60
- chain.shift.call(*args, &traverse)
83
+ middleware = chain.shift
84
+
85
+ if middleware.is_a?(Proc) && !middleware.lambda?
86
+ middleware.call(*args)
87
+
88
+ # implicit yield
89
+ traverse.call(*args)
90
+ else
91
+ middleware.call(*args, &traverse)
92
+ end
61
93
  end
62
94
  end
63
95
  traverse.call(*args)
64
96
  end
65
97
 
98
+
66
99
  private
67
100
 
68
101
  def stack
69
102
  @stack ||= []
70
103
  end
71
104
 
72
- Entry = Struct.new(:klass, :args) do
73
- def build
74
- klass.new(*args)
105
+ def index(klass)
106
+ stack.index {|entry| entry[0] == klass }
107
+ end
108
+
109
+ def create_entry(klass_and_args, block)
110
+ klass, *args = klass_and_args
111
+
112
+ if [ klass, block ].compact.count == 0
113
+ raise ArgumentError, 'either a middleware or block must be provided'
114
+ end
115
+
116
+ # dedup
117
+ remove(klass || block)
118
+
119
+ if klass
120
+ # validate
121
+ if klass.is_a? Class
122
+ unless klass.method_defined?(:call)
123
+ raise ArgumentError, "middleware must implement `.call`: #{klass}"
124
+ end
125
+ else
126
+ unless klass.respond_to?(:call)
127
+ raise ArgumentError, "middleware must respond to `.call`: #{klass}"
128
+ end
129
+
130
+ unless block.nil?
131
+ raise ArgumentError, 'can not supply middleware instance and block'
132
+ end
133
+ end
134
+
135
+ [ klass, args, block ]
136
+ else
137
+ [ block ]
138
+ end
139
+ end
140
+
141
+ def build_chain
142
+ # build the middleware stack
143
+ stack.map do |klass, args, block|
144
+ if klass.is_a? Class
145
+ klass.new(*args, &block)
146
+ else
147
+ if args.nil? || args.empty?
148
+ klass
149
+ else
150
+ # curry args
151
+ ->(*more_args, &block) do
152
+ klass.call(*args, *more_args, &block)
153
+ end
154
+ end
155
+ end
75
156
  end
76
157
  end
77
158
  end
@@ -1,3 +1,3 @@
1
1
  class Meddleware
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -0,0 +1,384 @@
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
+ end
204
+
205
+ describe '#before' do
206
+ it_behaves_like 'a middleware adder method', :before
207
+
208
+ it 'adds middleware where specified' do
209
+ subject.use A
210
+ subject.use B
211
+ subject.before B, C
212
+ expect(stack).to eq [ A, C, B ]
213
+ end
214
+
215
+ it 'maintans order for duplicates' do
216
+ subject.use A
217
+ subject.use B
218
+ subject.before B, C
219
+ subject.before B, C
220
+ expect(stack).to eq [ A, C, B ]
221
+ end
222
+
223
+ it 'works when target is missing' do
224
+ subject.use A
225
+ subject.before B, C
226
+ expect(stack).to eq [ C, A ]
227
+ end
228
+
229
+ it 'works when target is nil' do
230
+ subject.use A
231
+ subject.before nil, C
232
+ expect(stack).to eq [ C, A ]
233
+ end
234
+ end
235
+
236
+ describe '#empty?' do
237
+ it 'works with empty middleware' do
238
+ expect(subject).to be_empty
239
+ expect(subject.empty?).to be true
240
+ expect(stack.empty?).to be true
241
+ end
242
+
243
+ it 'works with middleware' do
244
+ subject.use A
245
+ expect(subject).not_to be_empty
246
+ expect(subject.empty?).to be false
247
+ expect(stack.empty?).to be false
248
+ end
249
+ end
250
+
251
+ describe '#clear' do
252
+ it 'works' do
253
+ subject.use A
254
+ subject.clear
255
+ expect(subject).to be_empty
256
+ end
257
+
258
+ it 'works with an empty stack' do
259
+ subject.clear
260
+ expect(subject).to be_empty
261
+ end
262
+ end
263
+
264
+ describe '#count' do
265
+ it 'works' do
266
+ expect(subject.count).to be 0
267
+
268
+ subject.use A
269
+ expect(subject.count).to be 1
270
+
271
+ subject.use B
272
+ expect(subject.count).to be 2
273
+
274
+ subject.remove B
275
+ expect(subject.count).to be 1
276
+ end
277
+ end
278
+
279
+ describe '#include?' do
280
+ it 'works' do
281
+ expect(subject.include?(A)).to be false
282
+
283
+ subject.use A
284
+ expect(subject.include?(A)).to be true
285
+ end
286
+ end
287
+
288
+ describe '#remove' do
289
+ before do
290
+ subject.use A
291
+ subject.use B
292
+ subject.use C
293
+ expect(stack).to eq [ A, B, C ]
294
+ end
295
+
296
+ it 'removes middleware' do
297
+ subject.remove(B)
298
+ expect(stack).to eq [ A, C ]
299
+ subject.remove(A)
300
+ expect(stack).to eq [ C ]
301
+ subject.remove(C)
302
+ expect(subject).to be_empty
303
+ end
304
+
305
+ it 'is idempotent' do
306
+ 3.times { subject.remove(A) }
307
+ expect(stack).to eq [ B, C ]
308
+ end
309
+
310
+ it 'works with nil' do
311
+ subject.remove(nil)
312
+ expect(stack).to eq [ A, B, C ]
313
+ end
314
+ end
315
+
316
+ describe '#replace' do
317
+ before do
318
+ subject.use A
319
+ subject.use B
320
+
321
+ expect(stack).to eq [ A, B ]
322
+ end
323
+
324
+ it 'replaces middleware' do
325
+ subject.replace(A, C)
326
+ expect(stack).to eq [ C, B ]
327
+ end
328
+
329
+ it 'works with middleware instances' do
330
+ instance = A.new
331
+ subject.replace(A, instance)
332
+
333
+ expect(subject).to include instance
334
+ expect(subject).not_to include A
335
+
336
+ subject.replace(instance, B)
337
+ expect(stack).to eq [ B ]
338
+ end
339
+
340
+ it 'fails when target middleware is missing' do
341
+ expect {
342
+ subject.replace(C, C)
343
+ }.to raise_error(RuntimeError)
344
+ end
345
+
346
+ it 'fails when middleware is invalid' do
347
+ expect {
348
+ subject.replace(A, nil)
349
+ }.to raise_error(ArgumentError)
350
+ end
351
+ end
352
+
353
+ describe '.new' do
354
+ it 'supports block mode' do
355
+ instance = described_class.new do
356
+ use A
357
+ prepend B
358
+ end
359
+
360
+ expect(instance).to include A
361
+ expect(instance).to include B
362
+ end
363
+ end
364
+
365
+ describe '#index' do
366
+ before do
367
+ subject.use A
368
+ subject.use B
369
+ end
370
+
371
+ it do
372
+ expect(subject.send(:index, A)).to be 0
373
+ expect(subject.send(:index, B)).to be 1
374
+ expect(subject.send(:index, C)).to be nil
375
+ expect(subject.send(:index, nil)).to be nil
376
+ end
377
+
378
+ it 'is a private method' do
379
+ expect {
380
+ subject.index
381
+ }.to raise_error(NoMethodError, /private/)
382
+ end
383
+ end
384
+ end
@@ -0,0 +1,74 @@
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
@@ -0,0 +1,259 @@
1
+ describe 'Meddleware#call' do
2
+ subject { Meddleware.new }
3
+
4
+ let(:middleware) { Meddler.new }
5
+
6
+ it 'works with no block, no stack' do
7
+ expect(subject.call).to be nil
8
+ end
9
+
10
+ it 'returns the blocks value' do
11
+ res = subject.call { 123 }
12
+ expect(res).to be 123
13
+ end
14
+
15
+ it 'works with args' do
16
+ res = subject.call(:abc) { 123 }
17
+ expect(res).to be 123
18
+ end
19
+
20
+ it 'passes args through to block' do
21
+ subject.call(:abc, x: :yz) do |*args|
22
+ expect(args).to eq [ :abc, { x: :yz } ]
23
+ end
24
+ end
25
+
26
+ context 'with a middleware class' do
27
+ it 'instantiates and calls the middleware' do
28
+ expect(Meddler).to receive(:new).and_return(middleware)
29
+ expect(middleware).to receive(:call)
30
+
31
+ subject.use Meddler
32
+ subject.call
33
+ end
34
+ end
35
+
36
+ context 'with a middleware instance' do
37
+ before do
38
+ subject.use middleware
39
+ end
40
+
41
+ it 'calls middleware' do
42
+ expect(middleware).to receive(:call)
43
+ subject.call
44
+ end
45
+
46
+ it 'calls middleware with args' do
47
+ expect(middleware).to receive(:call).with(:abc)
48
+ subject.call(:abc)
49
+ end
50
+
51
+ it 'calls middleware with block' do
52
+ expect(middleware).to receive(:call) do |&block|
53
+ expect(block).to be_a Proc
54
+ end
55
+
56
+ subject.call {}
57
+ end
58
+
59
+ it 'calls middleware with args and block' do
60
+ expect(middleware).to receive(:call) do |a, b, &block|
61
+ expect(a).to be :a
62
+ expect(b).to eq({ b: :c })
63
+ expect(block).to be_a Proc
64
+ end
65
+
66
+ subject.call(:a, b: :c) {}
67
+ end
68
+
69
+ it 'can return a value' do
70
+ expect(middleware).to receive(:call) { 123 }
71
+
72
+ expect(subject.call).to be 123
73
+ end
74
+
75
+ context 'when middleware calls block without explicit arguments' do
76
+ before do
77
+ expect(middleware).to receive(:call) do |&block|
78
+ block.call
79
+ end
80
+ end
81
+
82
+ it 'implicitly passes along original arguments' do
83
+ subject.call(:abc) do |arg|
84
+ expect(arg).to be :abc
85
+ end
86
+ end
87
+ end
88
+
89
+ context 'when middleware calls block with explicit arguments' do
90
+ it 'can add arguments' do
91
+ expect(middleware).to receive(:call) do |&block|
92
+ block.call(:abc)
93
+ end
94
+
95
+ subject.call do |arg|
96
+ expect(arg).to be :abc
97
+ end
98
+ end
99
+
100
+ it 'can override the arguments passed on' do
101
+ expect(middleware).to receive(:call) do |&block|
102
+ block.call(:abc)
103
+ end
104
+
105
+ subject.call(123) do |arg|
106
+ expect(arg).to be :abc
107
+ end
108
+ end
109
+
110
+ it 'can remove arguments' do
111
+ expect(middleware).to receive(:call) do |&block|
112
+ block.call(nil)
113
+ end
114
+
115
+ subject.call(:abc, :xyz) do |a, x|
116
+ expect(a).to be nil
117
+ expect(x).to be nil
118
+ end
119
+ end
120
+ end
121
+
122
+ context 'when middleware meddles with pass-by-ref arguments' do
123
+ before do
124
+ expect(middleware).to receive(:call) do |arg, &block|
125
+ arg[:abc] = 123
126
+ block.call
127
+ end
128
+ end
129
+
130
+ it 'alters the value for the block' do
131
+ subject.call({}) do |info|
132
+ expect(info).to eq({ abc: 123 })
133
+ end
134
+ end
135
+
136
+ it 'alters the value for the caller' do
137
+ info = {}
138
+ subject.call(info)
139
+ expect(info).to eq({ abc: 123 })
140
+ end
141
+ end
142
+
143
+ context 'when middleware meddles with pass-by-value arguments' do
144
+ before do
145
+ expect(middleware).to receive(:call) do |arg, &block|
146
+ arg = 123
147
+ block.call
148
+ end
149
+ end
150
+
151
+ it 'has no effect...unfortunately' do
152
+ subject.call(:abc) do |arg|
153
+ expect(arg).to be :abc
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ context 'with a middleware instance and arguments' do
160
+ before do
161
+ subject.use middleware, :abc
162
+ end
163
+
164
+ it 'curries the arguments' do
165
+ expect(middleware).to receive(:call) do |*args, &block|
166
+ expect(args).to eq([ :abc ])
167
+ end
168
+
169
+ subject.call
170
+ end
171
+
172
+ it 'curries and appends extra arguments' do
173
+ expect(middleware).to receive(:call) do |*args, &block|
174
+ expect(args).to eq([ :abc, :xyz ])
175
+ end
176
+
177
+ subject.call(:xyz)
178
+ end
179
+
180
+ it 'curries and appends, without yielding implicitly' do
181
+ res = subject.call(:xyz) { 123 }
182
+ expect(res).to be nil
183
+ end
184
+
185
+ it 'curries and appends, and can yield explicitly' do
186
+ expect(middleware).to receive(:call) do |*args, &block|
187
+ block.call
188
+ end
189
+
190
+ res = subject.call(:xyz) { 123 }
191
+ expect(res).to be 123
192
+ end
193
+ end
194
+
195
+ context 'with a middleware Proc' do
196
+ it 'passes arguments to the Proc' do
197
+ fn = proc {|arg| expect(arg).to be :abc }
198
+ expect(fn).to receive(:call).and_call_original
199
+
200
+ subject.use fn
201
+ subject.call(:abc)
202
+ end
203
+
204
+ it 'curries arguments' do
205
+ fn = proc {|*args| expect(args).to eq [ :xyz, :abc ] }
206
+ expect(fn).to receive(:call).and_call_original
207
+
208
+ subject.use fn, :xyz
209
+ subject.call(:abc)
210
+ end
211
+
212
+ it 'can alter arguments' do
213
+ fn = proc {|data| data[:abc] = 123 }
214
+ subject.use fn
215
+
216
+ data = {}
217
+ subject.call(data)
218
+ expect(data).to eq({ abc: 123 })
219
+ end
220
+
221
+ it 'can not abort middleware chain...unfortunately' do
222
+ fn = proc { return }
223
+
224
+ subject.use fn
225
+ expect {
226
+ subject.call
227
+ }.to raise_error(LocalJumpError)
228
+ end
229
+
230
+ it 'calls yield implicitly' do
231
+ fn = proc {}
232
+ expect(fn).to receive(:call).and_call_original
233
+
234
+ subject.use fn
235
+ res = subject.call { 123 }
236
+ expect(res).to be 123
237
+ end
238
+ end
239
+
240
+ context 'with a middleware Lambda' do
241
+ it 'does not explicitly call yield' do
242
+ fn = ->{}
243
+ expect(fn).to receive(:call).and_call_original
244
+
245
+ subject.use fn
246
+ res = subject.call { 123 }
247
+ expect(res).to be nil
248
+ end
249
+
250
+ it 'does can explicitly yield' do
251
+ fn = ->(&block) { block.call }
252
+ expect(fn).to receive(:call).and_call_original
253
+
254
+ subject.use fn
255
+ res = subject.call { 123 }
256
+ expect(res).to be 123
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,49 @@
1
+ module MyList
2
+ extend self
3
+
4
+ def middleware(&block)
5
+ (@middleware ||= Meddleware.new).tap do
6
+ @middleware.instance_eval(&block) if block_given?
7
+ end
8
+ end
9
+
10
+ def generate(n)
11
+ middleware.call(n) {|n| (1..n).to_a }
12
+ end
13
+ end
14
+
15
+ class OneExtra
16
+ def call(n)
17
+ yield(n + 1)
18
+ end
19
+ end
20
+
21
+ class Doubler
22
+ def call(*)
23
+ yield.map {|x| x * 2 }
24
+ end
25
+ end
26
+
27
+
28
+ describe MyList do
29
+ before do
30
+ MyList.middleware do
31
+ use OneExtra
32
+ use Doubler
33
+
34
+ # loggers
35
+ prepend {|x| puts "n starts as #{x}" }
36
+ append {|x| puts "n ends as #{x}" }
37
+ end
38
+ end
39
+
40
+ it 'calls middleware chain and generates a list' do
41
+ res = nil
42
+
43
+ expect {
44
+ res = MyList.generate(2)
45
+ }.to output("n starts as 2\nn ends as 3\n").to_stdout
46
+
47
+ expect(res).to eq [ 2, 4, 6 ]
48
+ end
49
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meddleware
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Pepper
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-01 00:00:00.000000000 Z
11
+ date: 2021-04-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -80,7 +80,7 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- description: work...within limits
83
+ description: A middleware framework to make meddling easy.
84
84
  email:
85
85
  executables: []
86
86
  extensions: []
@@ -88,7 +88,10 @@ extra_rdoc_files: []
88
88
  files:
89
89
  - lib/meddleware.rb
90
90
  - lib/meddleware/version.rb
91
- - spec/meddleware_spec.rb
91
+ - spec/build_meddleware_spec.rb
92
+ - spec/call_meddleware_chain_spec.rb
93
+ - spec/call_meddleware_spec.rb
94
+ - spec/examples_spec.rb
92
95
  homepage: https://github.com/dpep/meddleware_rb
93
96
  licenses:
94
97
  - MIT
@@ -113,4 +116,7 @@ signing_key:
113
116
  specification_version: 4
114
117
  summary: Meddleware
115
118
  test_files:
116
- - spec/meddleware_spec.rb
119
+ - spec/call_meddleware_spec.rb
120
+ - spec/call_meddleware_chain_spec.rb
121
+ - spec/build_meddleware_spec.rb
122
+ - spec/examples_spec.rb
@@ -1,3 +0,0 @@
1
- describe Meddleware do
2
-
3
- end