thorero 0.9.4 → 0.9.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,1198 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
-
3
- describe Extlib::Hook do
4
-
5
- before(:each) do
6
- @module = Module.new do
7
- def greet; greetings_from_module; end;
8
- end
9
-
10
- @class = Class.new do
11
- include Extlib::Hook
12
-
13
- def hookable; end;
14
- def self.clakable; end;
15
- def ambiguous; hi_mom!; end;
16
- def self.ambiguous; hi_dad!; end;
17
- end
18
-
19
- @another_class = Class.new do
20
- include Extlib::Hook
21
- end
22
-
23
- @other = Class.new do
24
- include Extlib::Hook
25
-
26
- def hookable; end
27
- def self.clakable; end;
28
- end
29
-
30
- @class.register_instance_hooks :hookable
31
- @class.register_class_hooks :clakable
32
- end
33
-
34
- #
35
- # Specs out how hookable methods are registered
36
- #
37
- describe "explicit hookable method registration" do
38
-
39
- describe "for class methods" do
40
-
41
- it "shouldn't confuse instance method hooks and class method hooks" do
42
- @class.register_instance_hooks :ambiguous
43
- @class.register_class_hooks :ambiguous
44
-
45
- @class.should_receive(:hi_dad!)
46
- @class.ambiguous
47
- end
48
-
49
- it "should be able to register multiple hookable methods at once" do
50
- %w(method_one method_two method_three).each do |method|
51
- @another_class.class_eval %(def self.#{method}; end;)
52
- end
53
-
54
- @another_class.register_class_hooks :method_one, :method_two, :method_three
55
- @another_class.class_hooks.keys.should include(:method_one)
56
- @another_class.class_hooks.keys.should include(:method_two)
57
- @another_class.class_hooks.keys.should include(:method_three)
58
- end
59
-
60
- it "should not allow a method that does not exist to be registered as hookable" do
61
- lambda { @another_class.register_class_hooks :method_one }.should raise_error(ArgumentError)
62
- end
63
-
64
- it "should allow hooks to be registered on methods from module extensions" do
65
- @class.extend(@module)
66
- @class.register_class_hooks :greet
67
- @class.class_hooks[:greet].should_not be_nil
68
- end
69
-
70
- it "should allow modules to register hooks in the self.extended method" do
71
- @module.class_eval do
72
- def self.extended(base)
73
- base.register_class_hooks :greet
74
- end
75
- end
76
- @class.extend(@module)
77
- @class.class_hooks[:greet].should_not be_nil
78
- end
79
-
80
- it "should be able to register protected methods as hooks" do
81
- @class.class_eval %{protected; def self.protected_hookable; end;}
82
- lambda { @class.register_class_hooks(:protected_hookable) }.should_not raise_error(ArgumentError)
83
- end
84
-
85
- it "should not be able to register private methods as hooks" do
86
- @class.class_eval %{class << self; private; def private_hookable; end; end;}
87
- lambda { @class.register_class_hooks(:private_hookable) }.should raise_error(ArgumentError)
88
- end
89
-
90
- it "should allow advising methods ending in ? or !" do
91
- @class.class_eval do
92
- def self.hookable!; two!; end;
93
- def self.hookable?; three!; end;
94
- register_class_hooks :hookable!, :hookable?
95
- end
96
- @class.before_class_method(:hookable!) { one! }
97
- @class.after_class_method(:hookable?) { four! }
98
-
99
- @class.should_receive(:one!).once.ordered
100
- @class.should_receive(:two!).once.ordered
101
- @class.should_receive(:three!).once.ordered
102
- @class.should_receive(:four!).once.ordered
103
-
104
- @class.hookable!
105
- @class.hookable?
106
- end
107
-
108
- it "should allow hooking methods ending in ?, ! or = with method hooks" do
109
- @class.class_eval do
110
- def self.before_hookable!; one!; end;
111
- def self.hookable!; two!; end;
112
- def self.hookable?; three!; end;
113
- def self.after_hookable?; four!; end;
114
- register_class_hooks :hookable!, :hookable?
115
- end
116
- @class.before_class_method(:hookable!, :before_hookable!)
117
- @class.after_class_method(:hookable?, :after_hookable?)
118
-
119
- @class.should_receive(:one!).once.ordered
120
- @class.should_receive(:two!).once.ordered
121
- @class.should_receive(:three!).once.ordered
122
- @class.should_receive(:four!).once.ordered
123
-
124
- @class.hookable!
125
- @class.hookable?
126
- end
127
-
128
- it "should allow hooking methods that have single character names" do
129
- @class.class_eval do
130
- def self.a; end;
131
- def self.b; end;
132
- end
133
-
134
- @class.before_class_method(:a) { omg! }
135
- @class.before_class_method(:b) { hi2u! }
136
-
137
- @class.should_receive(:omg!).once.ordered
138
- @class.should_receive(:hi2u!).once.ordered
139
- @class.a
140
- @class.b
141
- end
142
- end
143
-
144
- describe "for instance methods" do
145
-
146
- it "shouldn't confuse instance method hooks and class method hooks" do
147
- @class.register_instance_hooks :ambiguous
148
- @class.register_class_hooks :ambiguous
149
-
150
- inst = @class.new
151
- inst.should_receive(:hi_mom!)
152
- inst.ambiguous
153
- end
154
-
155
- it "should be able to register multiple hookable methods at once" do
156
- %w(method_one method_two method_three).each do |method|
157
- @another_class.send(:define_method, method) {}
158
- end
159
-
160
- @another_class.register_instance_hooks :method_one, :method_two, :method_three
161
- @another_class.instance_hooks.keys.should include(:method_one)
162
- @another_class.instance_hooks.keys.should include(:method_two)
163
- @another_class.instance_hooks.keys.should include(:method_three)
164
- end
165
-
166
- it "should not allow a method that does not exist to be registered as hookable" do
167
- lambda { @another_class.register_instance_hooks :method_one }.should raise_error(ArgumentError)
168
- end
169
-
170
- it "should allow hooks to be registered on included module methods" do
171
- @class.send(:include, @module)
172
- @class.register_instance_hooks :greet
173
- @class.instance_hooks[:greet].should_not be_nil
174
- end
175
-
176
- it "should allow modules to register hooks in the self.included method" do
177
- @module.class_eval do
178
- def self.included(base)
179
- base.register_instance_hooks :greet
180
- end
181
- end
182
- @class.send(:include, @module)
183
- @class.instance_hooks[:greet].should_not be_nil
184
- end
185
-
186
- it "should be able to register protected methods as hooks" do
187
- @class.class_eval %{protected; def protected_hookable; end;}
188
- lambda { @class.register_instance_hooks(:protected_hookable) }.should_not raise_error(ArgumentError)
189
- end
190
-
191
- it "should not be able to register private methods as hooks" do
192
- @class.class_eval %{private; def private_hookable; end;}
193
- lambda { @class.register_instance_hooks(:private_hookable) }.should raise_error(ArgumentError)
194
- end
195
-
196
- it "should allow hooking methods ending in ? or ! with block hooks" do
197
- @class.class_eval do
198
- def hookable!; two!; end;
199
- def hookable?; three!; end;
200
- register_instance_hooks :hookable!, :hookable?
201
- end
202
- @class.before(:hookable!) { one! }
203
- @class.after(:hookable?) { four! }
204
-
205
- inst = @class.new
206
- inst.should_receive(:one!).once.ordered
207
- inst.should_receive(:two!).once.ordered
208
- inst.should_receive(:three!).once.ordered
209
- inst.should_receive(:four!).once.ordered
210
-
211
- inst.hookable!
212
- inst.hookable?
213
- end
214
-
215
- it "should allow hooking methods ending in ?, ! or = with method hooks" do
216
- @class.class_eval do
217
- def before_hookable(val); one!; end;
218
- def hookable=(val); two!; end;
219
- def hookable?; three!; end;
220
- def after_hookable?; four!; end;
221
- register_instance_hooks :hookable=, :hookable?
222
- end
223
- @class.before(:hookable=, :before_hookable)
224
- @class.after(:hookable?, :after_hookable?)
225
-
226
- inst = @class.new
227
- inst.should_receive(:one!).once.ordered
228
- inst.should_receive(:two!).once.ordered
229
- inst.should_receive(:three!).once.ordered
230
- inst.should_receive(:four!).once.ordered
231
-
232
- inst.hookable = 'hello'
233
- inst.hookable?
234
- end
235
-
236
- it "should allow hooking methods that have single character names" do
237
- @class.class_eval do
238
- def a; end;
239
- def b; end;
240
- end
241
-
242
- @class.before(:a) { omg! }
243
- @class.before(:b) { hi2u! }
244
-
245
- inst = @class.new
246
- inst.should_receive(:omg!).once.ordered
247
- inst.should_receive(:hi2u!).once.ordered
248
- inst.a
249
- inst.b
250
- end
251
- end
252
-
253
- end
254
-
255
- describe "implicit hookable method registration" do
256
-
257
- describe "for class methods" do
258
- it "should implicitly register the method as hookable" do
259
- @class.class_eval %{def self.implicit_hook; end;}
260
- @class.before_class_method(:implicit_hook) { hello }
261
-
262
- @class.should_receive(:hello)
263
- @class.implicit_hook
264
- end
265
- end
266
-
267
- describe "for instance methods" do
268
- it "should implicitly register the method as hookable" do
269
- @class.class_eval %{def implicit_hook; end;}
270
- @class.before(:implicit_hook) { hello }
271
-
272
- inst = @class.new
273
- inst.should_receive(:hello)
274
- inst.implicit_hook
275
- end
276
-
277
- it 'should not overwrite methods included by modules after the hook is declared' do
278
- my_module = Module.new do
279
- # Just another module
280
- @another_module = Module.new do
281
- def some_method; "Hello " + super; end;
282
- end
283
-
284
- def some_method; "world"; end;
285
-
286
- def self.included(base)
287
- base.before(:some_method, :a_method)
288
- base.send(:include, @another_module)
289
- end
290
- end
291
-
292
- @class.class_eval { include my_module }
293
-
294
- inst = @class.new
295
- inst.should_receive(:a_method)
296
- inst.some_method.should == "Hello world"
297
- end
298
- end
299
-
300
- end
301
-
302
- describe "hook method registration" do
303
-
304
- describe "for class methods" do
305
- it "should complain when only one argument is passed" do
306
- lambda { @class.before_class_method(:clakable) }.should raise_error(ArgumentError)
307
- lambda { @class.after_class_method(:clakable) }.should raise_error(ArgumentError)
308
- end
309
-
310
- it "should complain when target_method is not a symbol" do
311
- lambda { @class.before_class_method("clakable", :ambiguous) }.should raise_error(ArgumentError)
312
- lambda { @class.after_class_method("clakable", :ambiguous) }.should raise_error(ArgumentError)
313
- end
314
-
315
- it "should complain when method_sym is not a symbol" do
316
- lambda { @class.before_class_method(:clakable, "ambiguous") }.should raise_error(ArgumentError)
317
- lambda { @class.after_class_method(:clakable, "ambiguous") }.should raise_error(ArgumentError)
318
- end
319
-
320
- it "should not allow methods ending in = to be hooks" do
321
- lambda { @class.before_class_method(:clakable, :annoying=) }.should raise_error(ArgumentError)
322
- lambda { @class.after_class_method(:clakable, :annoying=) }.should raise_error(ArgumentError)
323
- end
324
- end
325
-
326
- describe "for instance methods" do
327
- it "should complain when only one argument is passed" do
328
- lambda { @class.before(:hookable) }.should raise_error(ArgumentError)
329
- lambda { @class.after(:hookable) }.should raise_error(ArgumentError)
330
- end
331
-
332
- it "should complain when target_method is not a symbol" do
333
- lambda { @class.before("hookable", :ambiguous) }.should raise_error(ArgumentError)
334
- lambda { @class.after("hookable", :ambiguous) }.should raise_error(ArgumentError)
335
- end
336
-
337
- it "should complain when method_sym is not a symbol" do
338
- lambda { @class.before(:hookable, "ambiguous") }.should raise_error(ArgumentError)
339
- lambda { @class.after(:hookable, "ambiguous") }.should raise_error(ArgumentError)
340
- end
341
-
342
- it "should not allow methods ending in = to be hooks" do
343
- lambda { @class.before(:hookable, :annoying=) }.should raise_error(ArgumentError)
344
- lambda { @class.after(:hookable, :annoying=) }.should raise_error(ArgumentError)
345
- end
346
- end
347
-
348
- end
349
-
350
- #
351
- # Specs out how hook methods / blocks are invoked when there is no inheritance
352
- # involved
353
- #
354
- describe "hook invocation without inheritance" do
355
-
356
- describe "for class methods" do
357
- it 'should run an advice block' do
358
- @class.before_class_method(:clakable) { hi_mom! }
359
- @class.should_receive(:hi_mom!)
360
- @class.clakable
361
- end
362
-
363
- it 'should run an advice method' do
364
- @class.class_eval %{def self.before_method; hi_mom!; end;}
365
- @class.before_class_method(:clakable, :before_method)
366
-
367
- @class.should_receive(:hi_mom!)
368
- @class.clakable
369
- end
370
-
371
- it "should not pass any of the hookable method's arguments if the hook block does not accept arguments" do
372
- @class.class_eval do
373
- def self.method_with_args(one, two, three); end;
374
- before_class_method(:method_with_args) { hi_mom! }
375
- end
376
-
377
- @class.should_receive(:hi_mom!)
378
- @class.method_with_args(1, 2, 3)
379
- end
380
-
381
- it "should not pass any of the hookable method's arguments if the hook method does not accept arguments" do
382
- @class.class_eval do
383
- def self.method_with_args(one, two, three); end;
384
- def self.before_method_with_args; hi_mom!; end;
385
- before_class_method(:method_with_args, :before_method_with_args)
386
- end
387
-
388
- @class.should_receive(:hi_mom!)
389
- @class.method_with_args(1, 2, 3)
390
- end
391
-
392
- it "should not pass any of the hookable method's arguments if the hook is declared after it is registered and does not accept arguments" do
393
- @class.class_eval do
394
- def self.method_with_args(one, two, three); end;
395
- before_class_method(:method_with_args, :before_method_with_args)
396
- def self.before_method_with_args; hi_mom!; end;
397
- end
398
-
399
- @class.should_receive(:hi_mom!)
400
- @class.method_with_args(1, 2, 3)
401
- end
402
-
403
- it "should not pass any of the hookable method's arguments if the hook has been re-defined not to accept arguments" do
404
- @class.class_eval do
405
- def self.method_with_args(one, two, three); end;
406
- def self.before_method_with_args(one, two, three); hi_mom!; end;
407
- before_class_method(:method_with_args, :before_method_with_args)
408
- def self.before_method_with_args; hi_dad!; end;
409
- end
410
-
411
- @class.should_not_receive(:hi_mom1)
412
- @class.should_receive(:hi_dad!)
413
- @class.method_with_args(1, 2, 3)
414
- end
415
-
416
- it 'should pass the hookable method arguments to the hook method if the hook method takes arguments' do
417
- @class.class_eval do
418
- def self.hook_this(word, lol); end;
419
- register_class_hooks(:hook_this)
420
- def self.before_hook_this(word, lol); hi_mom!(word, lol); end;
421
- before_class_method(:hook_this, :before_hook_this)
422
- end
423
-
424
- @class.should_receive(:hi_mom!).with("omg", "hi2u")
425
- @class.hook_this("omg", "hi2u")
426
- end
427
-
428
- it "should pass the hookable method arguments to the hook block if the hook block takes arguments" do
429
- @class.class_eval do
430
- def self.method_with_args(word, lol); end;
431
- before_class_method(:method_with_args) { |one, two| hi_mom!(one, two) }
432
- end
433
-
434
- @class.should_receive(:hi_mom!).with('omg', 'hi2u')
435
- @class.method_with_args('omg', 'hi2u')
436
- end
437
-
438
- it 'should pass the hookable method arguments to the hook method if the hook method was re-defined to accept arguments' do
439
- @class.class_eval do
440
- def self.method_with_args(word, lol); end;
441
- def self.before_method_with_args; hi_mom!; end;
442
- before_class_method(:method_with_args, :before_method_with_args)
443
- def self.before_method_with_args(word, lol); hi_dad!(word, lol); end;
444
- end
445
-
446
- @class.should_not_receive(:hi_mom!)
447
- @class.should_receive(:hi_dad!).with("omg", "hi2u")
448
- @class.method_with_args("omg", "hi2u")
449
- end
450
-
451
- it 'should work with glob arguments (or whatever you call em)' do
452
- @class.class_eval do
453
- def self.hook_this(*args); end;
454
- def self.before_hook_this(*args); hi_mom!(*args); end;
455
- before_class_method(:hook_this, :before_hook_this)
456
- end
457
-
458
- @class.should_receive(:hi_mom!).with("omg", "hi2u", "lolercoaster")
459
- @class.hook_this("omg", "hi2u", "lolercoaster")
460
- end
461
-
462
- it 'should allow the use of before and after together' do
463
- @class.class_eval %{def self.before_hook; first!; end;}
464
- @class.before_class_method(:clakable, :before_hook)
465
- @class.after_class_method(:clakable) { last! }
466
-
467
- @class.should_receive(:first!).once.ordered
468
- @class.should_receive(:last!).once.ordered
469
- @class.clakable
470
- end
471
-
472
- it 'should be able to use private methods as hooks' do
473
- @class.class_eval do
474
- class << self
475
- private
476
- def nike; doit!; end;
477
- end
478
- before_class_method(:clakable, :nike)
479
- end
480
-
481
- @class.should_receive(:doit!)
482
- @class.clakable
483
- end
484
- end
485
-
486
- describe "for instance methods" do
487
- it 'should run an advice block' do
488
- @class.before(:hookable) { hi_mom! }
489
-
490
- inst = @class.new
491
- inst.should_receive(:hi_mom!)
492
- inst.hookable
493
- end
494
-
495
- it 'should run an advice method' do
496
- @class.send(:define_method, :before_method) { hi_mom! }
497
- @class.before(:hookable, :before_method)
498
-
499
- inst = @class.new
500
- inst.should_receive(:hi_mom!)
501
- inst.hookable
502
- end
503
-
504
- it "should not pass any of the hookable method's arguments if the hook block does not accept arguments" do
505
- @class.class_eval do
506
- def method_with_args(one, two, three); end;
507
- before(:method_with_args) { hi_mom! }
508
- end
509
-
510
- inst = @class.new
511
- inst.should_receive(:hi_mom!)
512
- inst.method_with_args(1, 2, 3)
513
- end
514
-
515
- it "should not pass any of the hookable method's arguments if the hook method does not accept arguments" do
516
- @class.class_eval do
517
- def method_with_args(one, two, three); end;
518
- def before_method_with_args; hi_mom!; end;
519
- before(:method_with_args, :before_method_with_args)
520
- end
521
-
522
- inst = @class.new
523
- inst.should_receive(:hi_mom!)
524
- inst.method_with_args(1, 2, 3)
525
- end
526
-
527
- it "should not pass any of the hookable method's arguments if the hook is declared after it is registered and does not accept arguments" do
528
- @class.class_eval do
529
- def method_with_args(one, two, three); end;
530
- before(:method_with_args, :before_method_with_args)
531
- def before_method_with_args; hi_mom!; end;
532
- end
533
-
534
- inst = @class.new
535
- inst.should_receive(:hi_mom!)
536
- inst.method_with_args(1, 2, 3)
537
- end
538
-
539
- it "should not pass any of the hookable method's arguments if the hook has been re-defined not to accept arguments" do
540
- @class.class_eval do
541
- def method_with_args(one, two, three); end;
542
- def before_method_with_args(one, two, three); hi_mom!; end;
543
- before(:method_with_args, :before_method_with_args)
544
- def before_method_with_args; hi_dad!; end;
545
- end
546
-
547
- inst = @class.new
548
- inst.should_not_receive(:hi_mom1)
549
- inst.should_receive(:hi_dad!)
550
- inst.method_with_args(1, 2, 3)
551
- end
552
-
553
- it 'should pass the hookable method arguments to the hook method if the hook method takes arguments' do
554
- @class.class_eval do
555
- def method_with_args(word, lol); end;
556
- def before_method_with_args(one, two); hi_mom!(one, two); end;
557
- before(:method_with_args, :before_method_with_args)
558
- end
559
-
560
- inst = @class.new
561
- inst.should_receive(:hi_mom!).with("omg", "hi2u")
562
- inst.method_with_args("omg", "hi2u")
563
- end
564
-
565
- it "should pass the hookable method arguments to the hook block if the hook block takes arguments" do
566
- @class.class_eval do
567
- def method_with_args(word, lol); end;
568
- before(:method_with_args) { |one, two| hi_mom!(one, two) }
569
- end
570
-
571
- inst = @class.new
572
- inst.should_receive(:hi_mom!).with('omg', 'hi2u')
573
- inst.method_with_args('omg', 'hi2u')
574
- end
575
-
576
- it 'should pass the hookable method arguments to the hook method if the hook method was re-defined to accept arguments' do
577
- @class.class_eval do
578
- def method_with_args(word, lol); end;
579
- def before_method_with_args; hi_mom!; end;
580
- before(:method_with_args, :before_method_with_args)
581
- def before_method_with_args(word, lol); hi_dad!(word, lol); end;
582
- end
583
-
584
- inst = @class.new
585
- inst.should_not_receive(:hi_mom!)
586
- inst.should_receive(:hi_dad!).with("omg", "hi2u")
587
- inst.method_with_args("omg", "hi2u")
588
- end
589
-
590
- it "should not pass the method return value to the after hook if the method does not take arguments" do
591
- @class.class_eval do
592
- def method_with_ret_val; 'hello'; end;
593
- def after_method_with_ret_val; hi_mom!; end;
594
- after(:method_with_ret_val, :after_method_with_ret_val)
595
- end
596
-
597
- inst = @class.new
598
- inst.should_receive(:hi_mom!)
599
- inst.method_with_ret_val
600
- end
601
-
602
- it 'should work with glob arguments (or whatever you call em)' do
603
- @class.class_eval do
604
- def hook_this(*args); end;
605
- def before_hook_this(*args); hi_mom!(*args) end;
606
- before(:hook_this, :before_hook_this)
607
- end
608
-
609
- inst = @class.new
610
- inst.should_receive(:hi_mom!).with("omg", "hi2u", "lolercoaster")
611
- inst.hook_this("omg", "hi2u", "lolercoaster")
612
- end
613
-
614
- it 'should allow the use of before and after together' do
615
- @class.class_eval %{def after_hook; last!; end;}
616
- @class.before(:hookable) { first! }
617
- @class.after(:hookable, :after_hook)
618
-
619
- inst = @class.new
620
- inst.should_receive(:first!).once.ordered
621
- inst.should_receive(:last!).once.ordered
622
- inst.hookable
623
- end
624
-
625
- it 'should be able to use private methods as hooks' do
626
- @class.class_eval %{private; def nike; doit!; end;}
627
- @class.before(:hookable, :nike)
628
-
629
- inst = @class.new
630
- inst.should_receive(:doit!)
631
- inst.hookable
632
- end
633
- end
634
-
635
- end
636
-
637
- describe "hook invocation with class inheritance" do
638
-
639
- describe "for class methods" do
640
- it 'should run an advice block when the class is inherited' do
641
- @class.before_class_method(:clakable) { hi_mom! }
642
- @child = Class.new(@class)
643
- @child.should_receive(:hi_mom!)
644
- @child.clakable
645
- end
646
-
647
- it 'should run an advice block on child class when hook is registered in parent after inheritance' do
648
- @child = Class.new(@class)
649
- @class.before_class_method(:clakable) { hi_mom! }
650
- @child.should_receive(:hi_mom!)
651
- @child.clakable
652
- end
653
-
654
- it 'should be able to declare advice methods in child classes' do
655
- @class.class_eval %{def self.before_method; hi_dad!; end;}
656
- @class.before_class_method(:clakable, :before_method)
657
-
658
- @child = Class.new(@class) do
659
- def self.child; hi_mom!; end;
660
- before_class_method(:clakable, :child)
661
- end
662
-
663
- @child.should_receive(:hi_dad!).once.ordered
664
- @child.should_receive(:hi_mom!).once.ordered
665
- @child.clakable
666
- end
667
-
668
- it "should not execute hooks added in the child classes when in the parent class" do
669
- @child = Class.new(@class) { def self.child; hi_mom!; end; }
670
- @child.before_class_method(:clakable, :child)
671
- @class.should_not_receive(:hi_mom!)
672
- @class.clakable
673
- end
674
-
675
- it 'should not call the hook stack if the hookable method is overwritten and does not call super' do
676
- @class.before_class_method(:clakable) { hi_mom! }
677
- @child = Class.new(@class) do
678
- def self.clakable; end;
679
- end
680
-
681
- @child.should_not_receive(:hi_mom!)
682
- @child.clakable
683
- end
684
-
685
- it 'should not call hooks defined in the child class for a hookable method in a parent if the child overwrites the hookable method without calling super' do
686
- @child = Class.new(@class) do
687
- before_class_method(:clakable) { hi_mom! }
688
- def self.clakable; end;
689
- end
690
-
691
- @child.should_not_receive(:hi_mom!)
692
- @child.clakable
693
- end
694
-
695
- it 'should not call hooks defined in child class even if hook method exists in parent' do
696
- @class.class_eval %{def self.hello_world; hello_world!; end;}
697
- @child = Class.new(@class) do
698
- before_class_method(:clakable, :hello_world)
699
- end
700
-
701
- @class.should_not_receive(:hello_world!)
702
- @class.clakable
703
- end
704
- end
705
-
706
- describe "for instance methods" do
707
- it 'should run an advice block when the class is inherited' do
708
- @inherited_class = Class.new(@class)
709
- @class.before(:hookable) { hi_dad! }
710
-
711
- inst = @inherited_class.new
712
- inst.should_receive(:hi_dad!)
713
- inst.hookable
714
- end
715
-
716
- it 'should run an advice block on child class when hook is registered in parent after inheritance' do
717
- @child = Class.new(@class)
718
- @class.before(:hookable) { hi_mom! }
719
-
720
- inst = @child.new
721
- inst.should_receive(:hi_mom!)
722
- inst.hookable
723
- end
724
-
725
- it 'should be able to declare advice methods in child classes' do
726
- @class.send(:define_method, :before_method) { hi_dad! }
727
- @class.before(:hookable, :before_method)
728
-
729
- @child = Class.new(@class) do
730
- def child; hi_mom!; end;
731
- before :hookable, :child
732
- end
733
-
734
- inst = @child.new
735
- inst.should_receive(:hi_dad!).once.ordered
736
- inst.should_receive(:hi_mom!).once.ordered
737
- inst.hookable
738
- end
739
-
740
- it "should not execute hooks added in the child classes when in parent class" do
741
- @child = Class.new(@class)
742
- @child.send(:define_method, :child) { hi_mom! }
743
- @child.before(:hookable, :child)
744
-
745
- inst = @class.new
746
- inst.should_not_receive(:hi_mom!)
747
- inst.hookable
748
- end
749
-
750
- it 'should not call the hook stack if the hookable method is overwritten and does not call super' do
751
- @class.before(:hookable) { hi_mom! }
752
- @child = Class.new(@class) do
753
- def hookable; end;
754
- end
755
-
756
- inst = @child.new
757
- inst.should_not_receive(:hi_mom!)
758
- inst.hookable
759
- end
760
-
761
- it 'should not call hooks defined in the child class for a hookable method in a parent if the child overwrites the hookable method without calling super' do
762
- @child = Class.new(@class) do
763
- before(:hookable) { hi_mom! }
764
- def hookable; end;
765
- end
766
-
767
- inst = @child.new
768
- inst.should_not_receive(:hi_mom!)
769
- inst.hookable
770
- end
771
-
772
- it 'should not call hooks defined in child class even if hook method exists in parent' do
773
- @class.send(:define_method, :hello_world) { hello_world! }
774
- @child = Class.new(@class) do
775
- before(:hookable, :hello_world)
776
- end
777
-
778
- inst = @class.new
779
- inst.should_not_receive(:hello_world!)
780
- inst.hookable
781
- end
782
- end
783
-
784
- end
785
-
786
- describe "hook invocation with module inclusions / extensions" do
787
-
788
- describe "for class methods" do
789
- it "should not overwrite methods included by extensions after the hook is declared" do
790
- @module.class_eval do
791
- @another_module = Module.new do
792
- def greet; greetings_from_another_module; super; end;
793
- end
794
-
795
- def self.extended(base)
796
- base.before_class_method(:clakable, :greet)
797
- base.extend(@another_module)
798
- end
799
- end
800
-
801
- @class.extend(@module)
802
- @class.should_receive(:greetings_from_another_module).once.ordered
803
- @class.should_receive(:greetings_from_module).once.ordered
804
- @class.clakable
805
- end
806
- end
807
-
808
- describe "for instance methods" do
809
- it 'should not overwrite methods included by modules after the hook is declared' do
810
- @module.class_eval do
811
- @another_module = Module.new do
812
- def greet; greetings_from_another_module; super; end;
813
- end
814
-
815
- def self.included(base)
816
- base.before(:hookable, :greet)
817
- base.send(:include, @another_module)
818
- end
819
- end
820
-
821
- @class.send(:include, @module)
822
-
823
- inst = @class.new
824
- inst.should_receive(:greetings_from_another_module).once.ordered
825
- inst.should_receive(:greetings_from_module).once.ordered
826
- inst.hookable
827
- end
828
- end
829
-
830
- end
831
-
832
- describe "hook invocation with unrelated classes" do
833
-
834
- describe "for class methods" do
835
- it "should not execute hooks registered in an unrelated class" do
836
- @class.before_class_method(:clakable) { hi_mom! }
837
-
838
- @other.should_not_receive(:hi_mom!)
839
- @other.clakable
840
- end
841
- end
842
-
843
- describe "for instance methods" do
844
- it "should not execute hooks registered in an unrelated class" do
845
- @class.before(:hookable) { hi_mom! }
846
-
847
- inst = @other.new
848
- inst.should_not_receive(:hi_mom!)
849
- inst.hookable
850
- end
851
- end
852
-
853
- end
854
-
855
- describe "using before hook" do
856
-
857
- describe "for class methods" do
858
-
859
- it 'should run the advice before the advised method' do
860
- @class.class_eval %{def self.hook_me; second!; end;}
861
- @class.register_class_hooks(:hook_me)
862
- @class.before_class_method(:hook_me, :first!)
863
-
864
- @class.should_receive(:first!).ordered
865
- @class.should_receive(:second!).ordered
866
- @class.hook_me
867
- end
868
-
869
- it 'should execute all advices once in order' do
870
- @class.before_class_method(:clakable, :hook_1)
871
- @class.before_class_method(:clakable, :hook_2)
872
- @class.before_class_method(:clakable, :hook_3)
873
-
874
- @class.should_receive(:hook_1).once.ordered
875
- @class.should_receive(:hook_2).once.ordered
876
- @class.should_receive(:hook_3).once.ordered
877
- @class.clakable
878
- end
879
- end
880
-
881
- describe "for instance methods" do
882
-
883
- it 'should run the advice before the advised method' do
884
- @class.class_eval %{
885
- def hook_me; second!; end;
886
- }
887
- @class.register_instance_hooks(:hook_me)
888
- @class.before(:hook_me, :first!)
889
-
890
- inst = @class.new
891
- inst.should_receive(:first!).ordered
892
- inst.should_receive(:second!).ordered
893
- inst.hook_me
894
- end
895
-
896
- it 'should execute all advices once in order' do
897
- @class.before(:hookable, :hook_1)
898
- @class.before(:hookable, :hook_2)
899
- @class.before(:hookable, :hook_3)
900
-
901
- inst = @class.new
902
- inst.should_receive(:hook_1).once.ordered
903
- inst.should_receive(:hook_2).once.ordered
904
- inst.should_receive(:hook_3).once.ordered
905
- inst.hookable
906
- end
907
- end
908
-
909
- end
910
-
911
- describe 'using after hook' do
912
-
913
- describe "for class methods" do
914
-
915
- it 'should run the advice after the advised method' do
916
- @class.class_eval %{def self.hook_me; first!; end;}
917
- @class.register_class_hooks(:hook_me)
918
- @class.after_class_method(:hook_me, :second!)
919
-
920
- @class.should_receive(:first!).ordered
921
- @class.should_receive(:second!).ordered
922
- @class.hook_me
923
- end
924
-
925
- it 'should execute all advices once in order' do
926
- @class.after_class_method(:clakable, :hook_1)
927
- @class.after_class_method(:clakable, :hook_2)
928
- @class.after_class_method(:clakable, :hook_3)
929
-
930
- @class.should_receive(:hook_1).once.ordered
931
- @class.should_receive(:hook_2).once.ordered
932
- @class.should_receive(:hook_3).once.ordered
933
- @class.clakable
934
- end
935
-
936
- it "the advised method should still return its normal value" do
937
- @class.class_eval %{def self.hello; "hello world"; end;}
938
- @class.register_class_hooks(:hello)
939
- @class.after_class_method(:hello) { "BAM" }
940
-
941
- @class.hello.should == "hello world"
942
- end
943
-
944
- it "should pass the return value to a hook method" do
945
- @class.class_eval do
946
- def self.with_return_val; 'hello'; end;
947
- def self.after_with_return_val(retval); retval.should == 'hello'; end;
948
- after_class_method(:with_return_val, :after_with_return_val)
949
- end
950
-
951
- @class.with_return_val
952
- end
953
-
954
- it "should pass the return value to a hook block" do
955
- @class.class_eval do
956
- def self.with_return_val; 'hello'; end;
957
- after_class_method(:with_return_val) { |ret| ret.should == 'hello' }
958
- end
959
-
960
- @class.with_return_val
961
- end
962
-
963
- it "should pass the return value and method arguments to a hook block" do
964
- @class.class_eval do
965
- def self.with_args_and_return_val(world); 'hello'; end;
966
- after_class_method(:with_args_and_return_val) do |hello, world|
967
- hello.should == "hello"
968
- world.should == "world"
969
- end
970
- end
971
-
972
- @class.with_args_and_return_val('world')
973
- end
974
- end
975
-
976
- describe "for instance methods" do
977
-
978
- it 'should run the advice after the advised method' do
979
- @class.class_eval %{def hook_me; first!; end;}
980
- @class.register_instance_hooks(:hook_me)
981
- @class.after(:hook_me, :second!)
982
-
983
- inst = @class.new
984
- inst.should_receive(:first!).ordered
985
- inst.should_receive(:second!).ordered
986
- inst.hook_me
987
- end
988
-
989
- it 'should execute all advices once in order' do
990
- @class.after(:hookable, :hook_1)
991
- @class.after(:hookable, :hook_2)
992
- @class.after(:hookable, :hook_3)
993
-
994
- inst = @class.new
995
- inst.should_receive(:hook_1).once.ordered
996
- inst.should_receive(:hook_2).once.ordered
997
- inst.should_receive(:hook_3).once.ordered
998
- inst.hookable
999
- end
1000
-
1001
- it "the advised method should still return its normal value" do
1002
- @class.class_eval %{def hello; "hello world"; end;}
1003
- @class.register_instance_hooks(:hello)
1004
- @class.after(:hello) { "BAM" }
1005
-
1006
- @class.new.hello.should == "hello world"
1007
- end
1008
-
1009
- it "should return nil if an after hook throws :halt without a return value" do
1010
- @class.class_eval %{def with_value; "hello"; end;}
1011
- @class.register_instance_hooks(:with_value)
1012
- @class.after(:with_value) { throw :halt }
1013
-
1014
- @class.new.with_value.should be_nil
1015
- end
1016
-
1017
- it "should pass the return value to a hook method" do
1018
- @class.class_eval do
1019
- def with_return_val; 'hello'; end;
1020
- def after_with_return_val(retval); retval.should == 'hello'; end;
1021
- after(:with_return_val, :after_with_return_val)
1022
- end
1023
-
1024
- @class.new.with_return_val
1025
- end
1026
-
1027
- it "should pass the return value to a hook block" do
1028
- @class.class_eval do
1029
- def with_return_val; 'hello'; end;
1030
- after(:with_return_val) { |ret| ret.should == 'hello' }
1031
- end
1032
-
1033
- @class.new.with_return_val
1034
- end
1035
-
1036
- it "should pass the return value and method arguments to a hook block" do
1037
- @class.class_eval do
1038
- def with_args_and_return_val(world); 'hello'; end;
1039
- after(:with_args_and_return_val) do |hello, world|
1040
- hello.should == "hello"
1041
- world.should == "world"
1042
- end
1043
- end
1044
-
1045
- @class.new.with_args_and_return_val('world')
1046
- end
1047
- end
1048
-
1049
- end
1050
-
1051
- describe 'aborting' do
1052
-
1053
- describe "for class methods" do
1054
- it "should catch :halt from a before hook and abort the advised method" do
1055
- @class.class_eval %{def self.no_love; love_me!; end;}
1056
- @class.register_class_hooks :no_love
1057
- @class.before_class_method(:no_love) { maybe! }
1058
- @class.before_class_method(:no_love) { throw :halt }
1059
- @class.before_class_method(:no_love) { what_about_me? }
1060
-
1061
- @class.should_receive(:maybe!)
1062
- @class.should_not_receive(:what_about_me?)
1063
- @class.should_not_receive(:love_me!)
1064
- lambda { @class.no_love }.should_not throw_symbol(:halt)
1065
- end
1066
-
1067
- it "should not run after hooks if a before hook throws :halt" do
1068
- @class.before_class_method(:clakable) { throw :halt }
1069
- @class.after_class_method(:clakable) { bam! }
1070
-
1071
- @class.should_not_receive(:bam!)
1072
- lambda { @class.clakable }.should_not throw_symbol(:halt)
1073
- end
1074
-
1075
- it "should return nil from the hookable method if a before hook throws :halt" do
1076
- @class.class_eval %{def self.with_value; "hello"; end;}
1077
- @class.register_class_hooks(:with_value)
1078
- @class.before_class_method(:with_value) { throw :halt }
1079
-
1080
- @class.with_value.should be_nil
1081
- end
1082
-
1083
- it "should catch :halt from an after hook and cease the advice" do
1084
- @class.after_class_method(:clakable) { throw :halt }
1085
- @class.after_class_method(:clakable) { never_see_me! }
1086
-
1087
- @class.should_not_receive(:never_see_me!)
1088
- lambda { @class.clakable }.should_not throw_symbol(:halt)
1089
- end
1090
-
1091
- it "should return nil if an after hook throws :halt without a return value" do
1092
- @class.class_eval %{def self.with_value; "hello"; end;}
1093
- @class.register_class_hooks(:with_value)
1094
- @class.after_class_method(:with_value) { throw :halt }
1095
-
1096
- @class.with_value.should be_nil
1097
- end
1098
- end
1099
-
1100
- describe "for instance methods" do
1101
- it "should catch :halt from a before hook and abort the advised method" do
1102
- @class.class_eval %{def no_love; love_me!; end;}
1103
- @class.register_instance_hooks :no_love
1104
- @class.before(:no_love) { maybe! }
1105
- @class.before(:no_love) { throw :halt }
1106
- @class.before(:no_love) { what_about_me? }
1107
-
1108
- inst = @class.new
1109
- inst.should_receive(:maybe!)
1110
- inst.should_not_receive(:what_about_me?)
1111
- inst.should_not_receive(:love_me!)
1112
- lambda { inst.no_love }.should_not throw_symbol(:halt)
1113
- end
1114
-
1115
- it "should not run after hooks if a before hook throws :halt" do
1116
- @class.before(:hookable) { throw :halt }
1117
- @class.after(:hookable) { bam! }
1118
-
1119
- inst = @class.new
1120
- inst.should_not_receive(:bam!)
1121
- lambda { inst.hookable }.should_not throw_symbol(:halt)
1122
- end
1123
-
1124
- it "should return nil from the hookable method if a before hook throws :halt" do
1125
- @class.class_eval %{def with_value; "hello"; end;}
1126
- @class.register_instance_hooks(:with_value)
1127
- @class.before(:with_value) { throw :halt }
1128
-
1129
- @class.new.with_value.should be_nil
1130
- end
1131
-
1132
- it "should catch :halt from an after hook and cease the advice" do
1133
- @class.after(:hookable) { throw :halt }
1134
- @class.after(:hookable) { never_see_me! }
1135
-
1136
- inst = @class.new
1137
- inst.should_not_receive(:never_see_me!)
1138
- lambda { inst.hookable }.should_not throw_symbol(:halt)
1139
- end
1140
- end
1141
-
1142
- end
1143
-
1144
- describe 'aborting with return values' do
1145
-
1146
- describe "for class methods" do
1147
-
1148
- it "should be able to abort from a before hook with a return value" do
1149
- @class.before_class_method(:clakable) { throw :halt, 'omg' }
1150
- @class.clakable.should == 'omg'
1151
- end
1152
-
1153
- it "should be able to abort from an after hook with a return value" do
1154
- @class.after_class_method(:clakable) { throw :halt, 'omg' }
1155
- @class.clakable.should == 'omg'
1156
- end
1157
-
1158
- end
1159
-
1160
- describe "for instance methods" do
1161
-
1162
- it "should be able to abort from a before hook with a return value" do
1163
- @class.before(:hookable) { throw :halt, 'omg' }
1164
-
1165
- inst = @class.new
1166
- inst.hookable.should == 'omg'
1167
- end
1168
-
1169
- it "should be able to abort from an after hook with a return value" do
1170
- @class.after(:hookable) { throw :halt, 'omg' }
1171
-
1172
- inst = @class.new
1173
- inst.hookable.should == 'omg'
1174
- end
1175
-
1176
- end
1177
-
1178
- end
1179
-
1180
- describe "helper methods" do
1181
- it 'should generate the correct argument signature' do
1182
- @class.class_eval do
1183
- def some_method(a, b, c)
1184
- [a, b, c]
1185
- end
1186
-
1187
- def yet_another(a, *heh)
1188
- [a, *heh]
1189
- end
1190
- end
1191
-
1192
- @class.args_for(@class.instance_method(:hookable)).should == "&block"
1193
- @class.args_for(@class.instance_method(:some_method)).should == "_1, _2, _3, &block"
1194
- @class.args_for(@class.instance_method(:yet_another)).should == "_1, *args, &block"
1195
- end
1196
- end
1197
-
1198
- end