aspectory 0.1.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.
- data/README.textile +206 -0
- data/Rakefile +9 -0
- data/lib/aspectory.rb +56 -0
- data/lib/aspectory/callbacker.rb +112 -0
- data/lib/aspectory/hook.rb +51 -0
- data/lib/aspectory/introspector.rb +59 -0
- data/lib/aspectory/observed_method.rb +36 -0
- data/lib/core_ext/method.rb +5 -0
- data/spec/booty_call_spec.rb +7 -0
- data/spec/callbacker_spec.rb +655 -0
- data/spec/hook_spec.rb +233 -0
- data/spec/introspector_spec.rb +280 -0
- data/spec/spec_helper.rb +8 -0
- metadata +67 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
module Aspectory
|
2
|
+
class ObservedMethod
|
3
|
+
attr_reader :method_id
|
4
|
+
|
5
|
+
def initialize(method_id, options={})
|
6
|
+
@method_id = method_id
|
7
|
+
@handlers = []
|
8
|
+
@count = 0
|
9
|
+
@times = options[:times] || 1
|
10
|
+
end
|
11
|
+
|
12
|
+
def match(sym)
|
13
|
+
return unless case method_id
|
14
|
+
when Symbol then valid? and method_id === sym
|
15
|
+
when Regexp then valid? and method_id.try(:match, sym.to_s)
|
16
|
+
else ; nil
|
17
|
+
end
|
18
|
+
@handlers.each { |fn| fn[sym] }
|
19
|
+
@count += 1
|
20
|
+
end
|
21
|
+
|
22
|
+
def valid?
|
23
|
+
if @times.to_s.match(/^(inf|any|all|every)/)
|
24
|
+
def self.valid?; true end
|
25
|
+
true # memoizing the result
|
26
|
+
else
|
27
|
+
@count < @times
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def push(*args)
|
32
|
+
@handlers += args
|
33
|
+
@handlers.tap.compact!.uniq!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,655 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe Aspectory::Callbacker do
|
4
|
+
attr_reader :klass, :subklass, :callbacker, :object
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@klass = Class.new do
|
8
|
+
attr_reader :results
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@results = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def no
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def foo(arg=:foo, &block)
|
19
|
+
@results << (block_given? ? block.call : arg)
|
20
|
+
arg
|
21
|
+
end
|
22
|
+
|
23
|
+
def bar(arg=:bar, &block)
|
24
|
+
return arg unless arg
|
25
|
+
@results << (block_given? ? block.call : arg)
|
26
|
+
end
|
27
|
+
|
28
|
+
def bar!(arg)
|
29
|
+
@results << arg
|
30
|
+
end
|
31
|
+
|
32
|
+
def bar=(arg)
|
33
|
+
@results << arg
|
34
|
+
end
|
35
|
+
|
36
|
+
def bar?(arg)
|
37
|
+
@results << (arg == :bar)
|
38
|
+
end
|
39
|
+
|
40
|
+
def wrapify
|
41
|
+
@results << :before
|
42
|
+
yield
|
43
|
+
@results << :after
|
44
|
+
end
|
45
|
+
|
46
|
+
def pitch
|
47
|
+
throw :foo, :result
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
@callbacker = Aspectory::Callbacker.new(klass)
|
52
|
+
@object = klass.new
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "klass#__PRISTINE__" do
|
56
|
+
it "allows original method calling" do
|
57
|
+
callbacker.before(:foo) { @results << :before }
|
58
|
+
|
59
|
+
object.__PRISTINE__(:foo)
|
60
|
+
object.results.should == [:foo]
|
61
|
+
end
|
62
|
+
|
63
|
+
it "allows arguments" do
|
64
|
+
callbacker.before(:foo) { @results << :before }
|
65
|
+
|
66
|
+
object.__PRISTINE__(:foo, :bar)
|
67
|
+
object.results.should == [:bar]
|
68
|
+
end
|
69
|
+
|
70
|
+
it "allows a block" do
|
71
|
+
callbacker.before(:foo) { @results << :before }
|
72
|
+
|
73
|
+
object.__PRISTINE__(:foo) { :bar }
|
74
|
+
object.results.should == [:bar]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "raises when method doesn't exist" do
|
78
|
+
proc {
|
79
|
+
callbacker.__PRISTINE__(:whiz)
|
80
|
+
}.should raise_error(NoMethodError)
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "*_without_callbacks methods" do
|
84
|
+
it "are generated for methods with callbacks" do
|
85
|
+
callbacker.before(:foo) { @results << :before }
|
86
|
+
|
87
|
+
object.foo_without_callbacks
|
88
|
+
object.results.should == [:foo]
|
89
|
+
end
|
90
|
+
|
91
|
+
it "are generated for bang methods" do
|
92
|
+
callbacker.before(:bar!) { @results << :before }
|
93
|
+
|
94
|
+
object.bar_without_callbacks! :bar
|
95
|
+
object.results.should == [:bar]
|
96
|
+
end
|
97
|
+
|
98
|
+
it "are generated for predicate methods" do
|
99
|
+
callbacker.before(:bar?) { @results << :before }
|
100
|
+
|
101
|
+
object.bar_without_callbacks? :bar
|
102
|
+
object.results.should == [true]
|
103
|
+
end
|
104
|
+
|
105
|
+
it "are generated for assignment methods" do
|
106
|
+
callbacker.before(:bar=) { @results << :before }
|
107
|
+
|
108
|
+
object.bar_without_callbacks = :bar
|
109
|
+
object.results.should == [:bar]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "#before" do
|
115
|
+
context "with a block" do
|
116
|
+
it "defines before behavior" do
|
117
|
+
callbacker.before(:foo) { @results << :before }
|
118
|
+
|
119
|
+
object.foo
|
120
|
+
object.results.should == [:before, :foo]
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "special method name endings" do
|
124
|
+
it "works with bang methods" do
|
125
|
+
callbacker.before(:bar=) { @results << :banged }
|
126
|
+
object.bar = :bar
|
127
|
+
object.results.should == [:banged, :bar]
|
128
|
+
end
|
129
|
+
|
130
|
+
it "works with predicate methods" do
|
131
|
+
callbacker.before(:bar?) { @results << :banged }
|
132
|
+
object.bar?(:bar)
|
133
|
+
object.results.should == [:banged, true]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "subclass behavior" do
|
138
|
+
before(:each) do
|
139
|
+
callbacker.before(:foo) { @results << :before }
|
140
|
+
@subklass = Class.new(klass)
|
141
|
+
@object = @subklass.new
|
142
|
+
end
|
143
|
+
|
144
|
+
it "runs superclass' callbacks" do
|
145
|
+
object.foo
|
146
|
+
object.results.should == [:before, :foo]
|
147
|
+
end
|
148
|
+
|
149
|
+
it "works with subclasses of subclasses" do
|
150
|
+
subsubklass = Class.new(subklass)
|
151
|
+
subobject = subsubklass.new
|
152
|
+
subobject.foo
|
153
|
+
subobject.results.should == [:before, :foo]
|
154
|
+
end
|
155
|
+
|
156
|
+
it "has subclass specific callbacks" do
|
157
|
+
callbacker.before(:bar) { @results << :subbed }
|
158
|
+
object.bar
|
159
|
+
object.results.should == [:before, :subbed, :bar]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe "redefining methods" do
|
164
|
+
it "allows arguments" do
|
165
|
+
callbacker.before(:foo) { @results << :before }
|
166
|
+
|
167
|
+
object.foo(:arg)
|
168
|
+
object.results.should == [:before, :arg]
|
169
|
+
end
|
170
|
+
|
171
|
+
it "allows a block" do
|
172
|
+
callbacker.before(:foo) { @results << :before }
|
173
|
+
|
174
|
+
object.foo { :block }
|
175
|
+
object.results.should == [:before, :block]
|
176
|
+
end
|
177
|
+
|
178
|
+
it "only happens once" do
|
179
|
+
mock(callbacker).redefine_method(anything).once
|
180
|
+
callbacker.before(:foo) { true }
|
181
|
+
callbacker.before(:foo) { false }
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "callback blocks" do
|
186
|
+
it "enables halting of method call" do
|
187
|
+
callbacker.before(:foo) { false }
|
188
|
+
|
189
|
+
object.foo
|
190
|
+
object.results.should be_empty
|
191
|
+
end
|
192
|
+
|
193
|
+
it "can be more than one per method" do
|
194
|
+
callbacker.before(:foo) { ping! }
|
195
|
+
callbacker.before(:foo) { pong! }
|
196
|
+
|
197
|
+
mock(object) do |expect|
|
198
|
+
expect.ping!
|
199
|
+
expect.pong!
|
200
|
+
end
|
201
|
+
|
202
|
+
object.foo
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "throwing alternative result" do
|
206
|
+
before(:each) do
|
207
|
+
callbacker.before(:foo) { throw :foo, :result }
|
208
|
+
end
|
209
|
+
|
210
|
+
it "returns alternative" do
|
211
|
+
object.foo.should == :result
|
212
|
+
end
|
213
|
+
|
214
|
+
it "doesn't run original method" do
|
215
|
+
object.results.should be_empty
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context "with a symbol" do
|
222
|
+
it "defines before behavior" do
|
223
|
+
callbacker.before(:foo, :bar)
|
224
|
+
|
225
|
+
object.foo
|
226
|
+
object.results.should == [:bar, :foo]
|
227
|
+
end
|
228
|
+
|
229
|
+
describe "redefining methods" do
|
230
|
+
it "allows arguments" do
|
231
|
+
callbacker.before(:foo, :bar)
|
232
|
+
|
233
|
+
object.foo(:arg)
|
234
|
+
object.results.should == [:bar, :arg]
|
235
|
+
end
|
236
|
+
|
237
|
+
it "allows a block" do
|
238
|
+
callbacker.before(:foo, :bar)
|
239
|
+
|
240
|
+
object.foo { :block }
|
241
|
+
object.results.should == [:bar, :block]
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe "callback blocks" do
|
246
|
+
it "enables halting of method call" do
|
247
|
+
callbacker.before(:foo, :no)
|
248
|
+
|
249
|
+
object.foo
|
250
|
+
object.results.should be_empty
|
251
|
+
end
|
252
|
+
|
253
|
+
it "can be more than one per method" do
|
254
|
+
callbacker.before(:foo, :ping!)
|
255
|
+
callbacker.before(:foo, :pong!)
|
256
|
+
|
257
|
+
mock(object) do |expect|
|
258
|
+
expect.ping!
|
259
|
+
expect.pong!
|
260
|
+
end
|
261
|
+
|
262
|
+
object.foo
|
263
|
+
end
|
264
|
+
|
265
|
+
it "doesn't run same callback twice for same method" do
|
266
|
+
callbacker.before(:foo, :ping!)
|
267
|
+
callbacker.before(:foo, :ping!)
|
268
|
+
|
269
|
+
mock(object).ping!.once
|
270
|
+
|
271
|
+
object.foo
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
describe "#after" do
|
278
|
+
context "with a block" do
|
279
|
+
it "defines after behavior" do
|
280
|
+
callbacker.after(:foo) { @results << :after }
|
281
|
+
|
282
|
+
object.foo
|
283
|
+
object.results.should == [:foo, :after]
|
284
|
+
end
|
285
|
+
|
286
|
+
describe "redefining methods" do
|
287
|
+
it "allows arguments" do
|
288
|
+
callbacker.after(:foo) { @results << :after }
|
289
|
+
|
290
|
+
object.foo(:arg)
|
291
|
+
object.results.should == [:arg, :after]
|
292
|
+
end
|
293
|
+
|
294
|
+
it "allows a block" do
|
295
|
+
callbacker.after(:foo) { @results << :after }
|
296
|
+
|
297
|
+
object.foo { :block }
|
298
|
+
object.results.should == [:block, :after]
|
299
|
+
end
|
300
|
+
|
301
|
+
it "only happens once" do
|
302
|
+
mock(callbacker).redefine_method(anything).once
|
303
|
+
|
304
|
+
callbacker.after(:bar) { true }
|
305
|
+
callbacker.after(:bar) { false }
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
describe "special method name endings" do
|
310
|
+
it "works with bang methods" do
|
311
|
+
callbacker.after(:bar=) { @results << :banged }
|
312
|
+
object.bar = :bar
|
313
|
+
object.results.should == [:bar, :banged]
|
314
|
+
end
|
315
|
+
|
316
|
+
it "works with predicate methods" do
|
317
|
+
callbacker.after(:bar?) { @results << :banged }
|
318
|
+
object.bar?(:bar)
|
319
|
+
object.results.should == [true, :banged]
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
describe "subclass behavior" do
|
324
|
+
before(:each) do
|
325
|
+
callbacker.after(:foo) { @results << :after }
|
326
|
+
@subklass = Class.new(klass)
|
327
|
+
@object = @subklass.new
|
328
|
+
end
|
329
|
+
|
330
|
+
it "runs superclass' callbacks" do
|
331
|
+
object.foo
|
332
|
+
object.results.should == [:foo, :after]
|
333
|
+
end
|
334
|
+
|
335
|
+
it "works with subclasses of subclasses" do
|
336
|
+
subsubklass = Class.new(subklass)
|
337
|
+
subobject = subsubklass.new
|
338
|
+
subobject.foo
|
339
|
+
subobject.results.should == [:foo, :after]
|
340
|
+
end
|
341
|
+
|
342
|
+
it "has subclass specific callbacks" do
|
343
|
+
callbacker.after(:bar) { @results << :subbed }
|
344
|
+
object.bar
|
345
|
+
object.results.should == [:bar, :after, :subbed]
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
describe "callback blocks" do
|
350
|
+
it "cannot enable halting of method call" do
|
351
|
+
callbacker.after(:foo) { false }
|
352
|
+
|
353
|
+
object.foo
|
354
|
+
object.results.should == [:foo]
|
355
|
+
end
|
356
|
+
|
357
|
+
it "still gets called when method returns false" do
|
358
|
+
callbacker.after(:bar?) { @results << :called }
|
359
|
+
object.bar?(:foo)
|
360
|
+
object.results.should == [false, :called]
|
361
|
+
end
|
362
|
+
|
363
|
+
it "can be more than one per method" do
|
364
|
+
callbacker.after(:foo) { ping! }
|
365
|
+
callbacker.after(:foo) { pong! }
|
366
|
+
|
367
|
+
mock(object).ping!
|
368
|
+
mock(object).pong!
|
369
|
+
|
370
|
+
object.foo
|
371
|
+
end
|
372
|
+
|
373
|
+
it "gets access to result of method call" do
|
374
|
+
callbacker.after(:foo) { |result| @results << result }
|
375
|
+
|
376
|
+
object.foo
|
377
|
+
object.results.should == [:foo, :foo]
|
378
|
+
end
|
379
|
+
|
380
|
+
it "can throw alternative result" do
|
381
|
+
callbacker.after(:foo) { throw :foo, :result }
|
382
|
+
|
383
|
+
object.foo.should == :result
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
context "with a symbol" do
|
389
|
+
it "defines after behavior" do
|
390
|
+
callbacker.after(:foo, :bar?)
|
391
|
+
|
392
|
+
object.foo
|
393
|
+
object.results.should == [:foo, false]
|
394
|
+
end
|
395
|
+
|
396
|
+
it "doesn't run same callback twice for same method" do
|
397
|
+
callbacker.after(:foo, :ping!)
|
398
|
+
callbacker.after(:foo, :ping!)
|
399
|
+
|
400
|
+
mock(object).ping!(anything).once
|
401
|
+
|
402
|
+
object.foo
|
403
|
+
end
|
404
|
+
|
405
|
+
describe "redefining methods" do
|
406
|
+
it "allows arguments" do
|
407
|
+
callbacker.after(:foo, :bar?)
|
408
|
+
|
409
|
+
object.foo(:bar)
|
410
|
+
object.results.should == [:bar, true]
|
411
|
+
end
|
412
|
+
|
413
|
+
it "allows a block" do
|
414
|
+
callbacker.after(:foo, :bar)
|
415
|
+
|
416
|
+
object.foo { :block }
|
417
|
+
object.results.should == [:block, :foo]
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
describe "callback blocks" do
|
422
|
+
it "cannot enable halting of method call" do
|
423
|
+
callbacker.after(:foo, :no)
|
424
|
+
|
425
|
+
object.foo
|
426
|
+
object.results.should == [:foo]
|
427
|
+
end
|
428
|
+
|
429
|
+
it "gets access to result of method call" do
|
430
|
+
callbacker.after(:foo, :bar)
|
431
|
+
|
432
|
+
object.foo(:arg)
|
433
|
+
object.results.should == [:arg, :arg]
|
434
|
+
end
|
435
|
+
|
436
|
+
it "can be more than one per method" do
|
437
|
+
callbacker.after(:foo, :ping!)
|
438
|
+
callbacker.after(:foo, :pong!)
|
439
|
+
|
440
|
+
mock(object).ping!.with(:foo)
|
441
|
+
mock(object).pong!.with(:foo)
|
442
|
+
|
443
|
+
object.foo
|
444
|
+
end
|
445
|
+
|
446
|
+
it "can throw alternative result" do
|
447
|
+
callbacker.after(:foo, :pitch)
|
448
|
+
|
449
|
+
object.foo.should == :result
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
describe "#around" do
|
456
|
+
context "with a block" do
|
457
|
+
it "returns proper result" do
|
458
|
+
callbacker.around(:foo) do |fn|
|
459
|
+
@results << :before
|
460
|
+
fn.call
|
461
|
+
@results << :after
|
462
|
+
end
|
463
|
+
|
464
|
+
object.foo.should == :foo
|
465
|
+
end
|
466
|
+
|
467
|
+
it "defines after behavior" do
|
468
|
+
callbacker.around(:foo) do |fn|
|
469
|
+
@results << :before
|
470
|
+
fn.call
|
471
|
+
@results << :after
|
472
|
+
end
|
473
|
+
|
474
|
+
object.foo
|
475
|
+
object.results.should == [:before, :foo, :after]
|
476
|
+
end
|
477
|
+
|
478
|
+
describe "redefining methods" do
|
479
|
+
it "allows arguments" do
|
480
|
+
callbacker.around(:foo) do |fn|
|
481
|
+
@results << :before
|
482
|
+
fn.call
|
483
|
+
@results << :after
|
484
|
+
end
|
485
|
+
|
486
|
+
object.foo(:arg)
|
487
|
+
object.results.should == [:before, :arg, :after]
|
488
|
+
end
|
489
|
+
|
490
|
+
it "allows a block" do
|
491
|
+
callbacker.around(:foo) do |fn|
|
492
|
+
@results << :before
|
493
|
+
fn.call
|
494
|
+
@results << :after
|
495
|
+
end
|
496
|
+
|
497
|
+
object.foo { :block }
|
498
|
+
object.results.should == [:before, :block, :after]
|
499
|
+
end
|
500
|
+
|
501
|
+
it "only happens once" do
|
502
|
+
mock(callbacker).redefine_method(anything).once
|
503
|
+
|
504
|
+
callbacker.around(:bar) { true }
|
505
|
+
callbacker.around(:bar) { false }
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
describe "special method name endings" do
|
510
|
+
it "works with bang methods" do
|
511
|
+
callbacker.around(:bar!) do |fn|
|
512
|
+
@results << :before
|
513
|
+
fn.call
|
514
|
+
@results << :after
|
515
|
+
end
|
516
|
+
object.bar! :bar
|
517
|
+
object.results.should == [:before, :bar, :after]
|
518
|
+
end
|
519
|
+
|
520
|
+
it "works with predicate methods" do
|
521
|
+
callbacker.around(:bar?) do |fn|
|
522
|
+
@results << :before
|
523
|
+
fn.call
|
524
|
+
@results << :after
|
525
|
+
end
|
526
|
+
object.bar?(:bar)
|
527
|
+
object.results.should == [:before, true, :after]
|
528
|
+
end
|
529
|
+
|
530
|
+
it "works with assignment methods" do
|
531
|
+
callbacker.around(:bar=) do |fn|
|
532
|
+
@results << :before
|
533
|
+
fn.call
|
534
|
+
@results << :after
|
535
|
+
end
|
536
|
+
object.bar = :bar
|
537
|
+
object.results.should == [:before, :bar, :after]
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
describe "subclass behavior" do
|
542
|
+
before(:each) do
|
543
|
+
callbacker.around(:foo) do |fn|
|
544
|
+
@results << :before
|
545
|
+
fn.call
|
546
|
+
@results << :after
|
547
|
+
end
|
548
|
+
@subklass = Class.new(klass)
|
549
|
+
@object = @subklass.new
|
550
|
+
end
|
551
|
+
|
552
|
+
it "runs superclass' callbacks" do
|
553
|
+
object.foo
|
554
|
+
object.results.should == [:before, :foo, :after]
|
555
|
+
end
|
556
|
+
|
557
|
+
it "works with subclasses of subclasses" do
|
558
|
+
subsubklass = Class.new(subklass)
|
559
|
+
subobject = subsubklass.new
|
560
|
+
subobject.foo
|
561
|
+
subobject.results.should == [:before, :foo, :after]
|
562
|
+
end
|
563
|
+
|
564
|
+
it "has subclass specific callbacks" do
|
565
|
+
callbacker.after(:bar) { @results << :subbed }
|
566
|
+
object.bar
|
567
|
+
object.results.should == [:before, :bar, :after, :subbed]
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
describe "callback blocks" do
|
572
|
+
it "can enable halting of method call" do
|
573
|
+
callbacker.around(:foo) { false }
|
574
|
+
|
575
|
+
object.foo
|
576
|
+
object.results.should be_empty
|
577
|
+
end
|
578
|
+
|
579
|
+
it "can be more than one per method" do
|
580
|
+
callbacker.around(:foo) { ping! }
|
581
|
+
callbacker.around(:foo) { pong! }
|
582
|
+
|
583
|
+
mock(object).ping!
|
584
|
+
mock(object).pong!
|
585
|
+
|
586
|
+
object.foo
|
587
|
+
end
|
588
|
+
|
589
|
+
it "can throw alternative result" do
|
590
|
+
callbacker.around(:foo) { |fn| fn.call and throw :foo, :result }
|
591
|
+
|
592
|
+
object.foo.should == :result
|
593
|
+
end
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
context "with a symbol" do
|
598
|
+
it "returns proper result" do
|
599
|
+
callbacker.around(:foo, :wrapify)
|
600
|
+
|
601
|
+
object.foo.should == :foo
|
602
|
+
end
|
603
|
+
|
604
|
+
it "defines after behavior" do
|
605
|
+
callbacker.around(:foo, :wrapify)
|
606
|
+
|
607
|
+
object.foo
|
608
|
+
object.results.should == [:before, :foo, :after]
|
609
|
+
end
|
610
|
+
|
611
|
+
it "doesn't run same callback twice for same method" do
|
612
|
+
callbacker.around(:foo, :ping!)
|
613
|
+
callbacker.around(:foo, :ping!)
|
614
|
+
|
615
|
+
mock(object).ping!.once
|
616
|
+
|
617
|
+
object.foo
|
618
|
+
end
|
619
|
+
|
620
|
+
describe "redefining methods" do
|
621
|
+
it "allows arguments" do
|
622
|
+
callbacker.around(:foo, :wrapify)
|
623
|
+
|
624
|
+
object.foo(:bar)
|
625
|
+
object.results.should == [:before, :bar, :after]
|
626
|
+
end
|
627
|
+
|
628
|
+
it "allows a block" do
|
629
|
+
callbacker.around(:foo, :wrapify)
|
630
|
+
|
631
|
+
object.foo { :block }
|
632
|
+
object.results.should == [:before, :block, :after]
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
describe "callback blocks" do
|
637
|
+
it "can be more than one per method" do
|
638
|
+
callbacker.around(:foo, :ping!)
|
639
|
+
callbacker.around(:foo, :pong!)
|
640
|
+
|
641
|
+
mock(object).ping!
|
642
|
+
mock(object).pong!
|
643
|
+
|
644
|
+
object.foo
|
645
|
+
end
|
646
|
+
|
647
|
+
it "can throw alternative result" do
|
648
|
+
callbacker.around(:foo, :pitch)
|
649
|
+
|
650
|
+
object.foo.should == :result
|
651
|
+
end
|
652
|
+
end
|
653
|
+
end
|
654
|
+
end
|
655
|
+
end
|