sundbp-extlib 0.9.14

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.
Files changed (72) hide show
  1. data/.autotest +21 -0
  2. data/.document +5 -0
  3. data/.gitignore +22 -0
  4. data/LICENSE +47 -0
  5. data/README.rdoc +17 -0
  6. data/Rakefile +28 -0
  7. data/VERSION +1 -0
  8. data/extlib.gemspec +146 -0
  9. data/lib/extlib.rb +50 -0
  10. data/lib/extlib/array.rb +36 -0
  11. data/lib/extlib/assertions.rb +8 -0
  12. data/lib/extlib/blank.rb +89 -0
  13. data/lib/extlib/boolean.rb +11 -0
  14. data/lib/extlib/byte_array.rb +6 -0
  15. data/lib/extlib/class.rb +177 -0
  16. data/lib/extlib/datetime.rb +29 -0
  17. data/lib/extlib/dictionary.rb +433 -0
  18. data/lib/extlib/hash.rb +442 -0
  19. data/lib/extlib/hook.rb +403 -0
  20. data/lib/extlib/inflection.rb +440 -0
  21. data/lib/extlib/lazy_array.rb +451 -0
  22. data/lib/extlib/lazy_module.rb +18 -0
  23. data/lib/extlib/logger.rb +198 -0
  24. data/lib/extlib/mash.rb +155 -0
  25. data/lib/extlib/module.rb +47 -0
  26. data/lib/extlib/nil.rb +5 -0
  27. data/lib/extlib/numeric.rb +5 -0
  28. data/lib/extlib/object.rb +175 -0
  29. data/lib/extlib/object_space.rb +13 -0
  30. data/lib/extlib/pathname.rb +20 -0
  31. data/lib/extlib/pooling.rb +235 -0
  32. data/lib/extlib/rubygems.rb +38 -0
  33. data/lib/extlib/simple_set.rb +66 -0
  34. data/lib/extlib/string.rb +176 -0
  35. data/lib/extlib/struct.rb +17 -0
  36. data/lib/extlib/symbol.rb +21 -0
  37. data/lib/extlib/time.rb +43 -0
  38. data/lib/extlib/virtual_file.rb +10 -0
  39. data/spec/array_spec.rb +39 -0
  40. data/spec/blank_spec.rb +85 -0
  41. data/spec/byte_array_spec.rb +7 -0
  42. data/spec/class_spec.rb +157 -0
  43. data/spec/datetime_spec.rb +22 -0
  44. data/spec/hash_spec.rb +537 -0
  45. data/spec/hook_spec.rb +1234 -0
  46. data/spec/inflection/plural_spec.rb +564 -0
  47. data/spec/inflection/singular_spec.rb +497 -0
  48. data/spec/inflection_extras_spec.rb +110 -0
  49. data/spec/lazy_array_spec.rb +1957 -0
  50. data/spec/lazy_module_spec.rb +38 -0
  51. data/spec/mash_spec.rb +311 -0
  52. data/spec/module_spec.rb +70 -0
  53. data/spec/object_space_spec.rb +9 -0
  54. data/spec/object_spec.rb +114 -0
  55. data/spec/pooling_spec.rb +511 -0
  56. data/spec/rcov.opts +6 -0
  57. data/spec/simple_set_spec.rb +57 -0
  58. data/spec/spec.opts +4 -0
  59. data/spec/spec_helper.rb +10 -0
  60. data/spec/string_spec.rb +221 -0
  61. data/spec/struct_spec.rb +12 -0
  62. data/spec/symbol_spec.rb +8 -0
  63. data/spec/time_spec.rb +29 -0
  64. data/spec/try_call_spec.rb +73 -0
  65. data/spec/try_dup_spec.rb +45 -0
  66. data/spec/virtual_file_spec.rb +21 -0
  67. data/tasks/ci.rake +1 -0
  68. data/tasks/metrics.rake +36 -0
  69. data/tasks/spec.rake +25 -0
  70. data/tasks/yard.rake +9 -0
  71. data/tasks/yardstick.rake +19 -0
  72. metadata +180 -0
@@ -0,0 +1,1234 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ describe Extlib::Hook do
4
+
5
+ before 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.should have_key(:method_one)
56
+ @another_class.class_hooks.should have_key(:method_two)
57
+ @another_class.class_hooks.should have_key(: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.should have_key(:method_one)
162
+ @another_class.instance_hooks.should have_key(:method_two)
163
+ @another_class.instance_hooks.should have_key(: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
+ orig_verbose, $VERBOSE = $VERBOSE, false
409
+ def self.before_method_with_args; hi_dad!; end;
410
+ $VERBOSE = orig_verbose
411
+ end
412
+
413
+ @class.should_not_receive(:hi_mom1)
414
+ @class.should_receive(:hi_dad!)
415
+ @class.method_with_args(1, 2, 3)
416
+ end
417
+
418
+ it 'should pass the hookable method arguments to the hook method if the hook method takes arguments' do
419
+ @class.class_eval do
420
+ def self.hook_this(word, lol); end;
421
+ register_class_hooks(:hook_this)
422
+ def self.before_hook_this(word, lol); hi_mom!(word, lol); end;
423
+ before_class_method(:hook_this, :before_hook_this)
424
+ end
425
+
426
+ @class.should_receive(:hi_mom!).with("omg", "hi2u")
427
+ @class.hook_this("omg", "hi2u")
428
+ end
429
+
430
+ it "should pass the hookable method arguments to the hook block if the hook block takes arguments" do
431
+ @class.class_eval do
432
+ def self.method_with_args(word, lol); end;
433
+ before_class_method(:method_with_args) { |one, two| hi_mom!(one, two) }
434
+ end
435
+
436
+ @class.should_receive(:hi_mom!).with('omg', 'hi2u')
437
+ @class.method_with_args('omg', 'hi2u')
438
+ end
439
+
440
+ it 'should pass the hookable method arguments to the hook method if the hook method was re-defined to accept arguments' do
441
+ @class.class_eval do
442
+ def self.method_with_args(word, lol); end;
443
+ def self.before_method_with_args; hi_mom!; end;
444
+ before_class_method(:method_with_args, :before_method_with_args)
445
+ orig_verbose, $VERBOSE = $VERBOSE, false
446
+ def self.before_method_with_args(word, lol); hi_dad!(word, lol); end;
447
+ $VERBOSE = orig_verbose
448
+ end
449
+
450
+ @class.should_not_receive(:hi_mom!)
451
+ @class.should_receive(:hi_dad!).with("omg", "hi2u")
452
+ @class.method_with_args("omg", "hi2u")
453
+ end
454
+
455
+ it 'should work with glob arguments (or whatever you call em)' do
456
+ @class.class_eval do
457
+ def self.hook_this(*args); end;
458
+ def self.before_hook_this(*args); hi_mom!(*args); end;
459
+ before_class_method(:hook_this, :before_hook_this)
460
+ end
461
+
462
+ @class.should_receive(:hi_mom!).with("omg", "hi2u", "lolercoaster")
463
+ @class.hook_this("omg", "hi2u", "lolercoaster")
464
+ end
465
+
466
+ it 'should allow the use of before and after together' do
467
+ @class.class_eval %{def self.before_hook; first!; end;}
468
+ @class.before_class_method(:clakable, :before_hook)
469
+ @class.after_class_method(:clakable) { last! }
470
+
471
+ @class.should_receive(:first!).once.ordered
472
+ @class.should_receive(:last!).once.ordered
473
+ @class.clakable
474
+ end
475
+
476
+ it 'should be able to use private methods as hooks' do
477
+ @class.class_eval do
478
+ class << self
479
+ private
480
+ def nike; doit!; end;
481
+ end
482
+ before_class_method(:clakable, :nike)
483
+ end
484
+
485
+ @class.should_receive(:doit!)
486
+ @class.clakable
487
+ end
488
+ end
489
+
490
+ describe "for instance methods" do
491
+ it 'should run an advice block' do
492
+ @class.before(:hookable) { hi_mom! }
493
+
494
+ inst = @class.new
495
+ inst.should_receive(:hi_mom!)
496
+ inst.hookable
497
+ end
498
+
499
+ it 'should run an advice method' do
500
+ @class.send(:define_method, :before_method) { hi_mom! }
501
+ @class.before(:hookable, :before_method)
502
+
503
+ inst = @class.new
504
+ inst.should_receive(:hi_mom!)
505
+ inst.hookable
506
+ end
507
+
508
+ it "should not pass any of the hookable method's arguments if the hook block does not accept arguments" do
509
+ @class.class_eval do
510
+ def method_with_args(one, two, three); end;
511
+ before(:method_with_args) { hi_mom! }
512
+ end
513
+
514
+ inst = @class.new
515
+ inst.should_receive(:hi_mom!)
516
+ inst.method_with_args(1, 2, 3)
517
+ end
518
+
519
+ it "should not pass any of the hookable method's arguments if the hook method does not accept arguments" do
520
+ @class.class_eval do
521
+ def method_with_args(one, two, three); end;
522
+ def before_method_with_args; hi_mom!; end;
523
+ before(:method_with_args, :before_method_with_args)
524
+ end
525
+
526
+ inst = @class.new
527
+ inst.should_receive(:hi_mom!)
528
+ inst.method_with_args(1, 2, 3)
529
+ end
530
+
531
+ 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
532
+ @class.class_eval do
533
+ def method_with_args(one, two, three); end;
534
+ before(:method_with_args, :before_method_with_args)
535
+ def before_method_with_args; hi_mom!; end;
536
+ end
537
+
538
+ inst = @class.new
539
+ inst.should_receive(:hi_mom!)
540
+ inst.method_with_args(1, 2, 3)
541
+ end
542
+
543
+ it "should not pass any of the hookable method's arguments if the hook has been re-defined not to accept arguments" do
544
+ @class.class_eval do
545
+ def method_with_args(one, two, three); end;
546
+ def before_method_with_args(one, two, three); hi_mom!; end;
547
+ before(:method_with_args, :before_method_with_args)
548
+ orig_verbose, $VERBOSE = $VERBOSE, false
549
+ def before_method_with_args; hi_dad!; end;
550
+ $VERBOSE = orig_verbose
551
+ end
552
+
553
+ inst = @class.new
554
+ inst.should_not_receive(:hi_mom1)
555
+ inst.should_receive(:hi_dad!)
556
+ inst.method_with_args(1, 2, 3)
557
+ end
558
+
559
+ it 'should pass the hookable method arguments to the hook method if the hook method takes arguments' do
560
+ @class.class_eval do
561
+ def method_with_args(word, lol); end;
562
+ def before_method_with_args(one, two); hi_mom!(one, two); end;
563
+ before(:method_with_args, :before_method_with_args)
564
+ end
565
+
566
+ inst = @class.new
567
+ inst.should_receive(:hi_mom!).with("omg", "hi2u")
568
+ inst.method_with_args("omg", "hi2u")
569
+ end
570
+
571
+ it "should pass the hookable method arguments to the hook block if the hook block takes arguments" do
572
+ @class.class_eval do
573
+ def method_with_args(word, lol); end;
574
+ before(:method_with_args) { |one, two| hi_mom!(one, two) }
575
+ end
576
+
577
+ inst = @class.new
578
+ inst.should_receive(:hi_mom!).with('omg', 'hi2u')
579
+ inst.method_with_args('omg', 'hi2u')
580
+ end
581
+
582
+ it 'should pass the hookable method arguments to the hook method if the hook method was re-defined to accept arguments' do
583
+ @class.class_eval do
584
+ def method_with_args(word, lol); end;
585
+ def before_method_with_args; hi_mom!; end;
586
+ before(:method_with_args, :before_method_with_args)
587
+ orig_verbose, $VERBOSE = $VERBOSE, false
588
+ def before_method_with_args(word, lol); hi_dad!(word, lol); end;
589
+ $VERBOSE = orig_verbose
590
+ end
591
+
592
+ inst = @class.new
593
+ inst.should_not_receive(:hi_mom!)
594
+ inst.should_receive(:hi_dad!).with("omg", "hi2u")
595
+ inst.method_with_args("omg", "hi2u")
596
+ end
597
+
598
+ it "should not pass the method return value to the after hook if the method does not take arguments" do
599
+ @class.class_eval do
600
+ def method_with_ret_val; 'hello'; end;
601
+ def after_method_with_ret_val; hi_mom!; end;
602
+ after(:method_with_ret_val, :after_method_with_ret_val)
603
+ end
604
+
605
+ inst = @class.new
606
+ inst.should_receive(:hi_mom!)
607
+ inst.method_with_ret_val
608
+ end
609
+
610
+ it 'should work with glob arguments (or whatever you call em)' do
611
+ @class.class_eval do
612
+ def hook_this(*args); end;
613
+ def before_hook_this(*args); hi_mom!(*args) end;
614
+ before(:hook_this, :before_hook_this)
615
+ end
616
+
617
+ inst = @class.new
618
+ inst.should_receive(:hi_mom!).with("omg", "hi2u", "lolercoaster")
619
+ inst.hook_this("omg", "hi2u", "lolercoaster")
620
+ end
621
+
622
+ it 'should allow the use of before and after together' do
623
+ @class.class_eval %{def after_hook; last!; end;}
624
+ @class.before(:hookable) { first! }
625
+ @class.after(:hookable, :after_hook)
626
+
627
+ inst = @class.new
628
+ inst.should_receive(:first!).once.ordered
629
+ inst.should_receive(:last!).once.ordered
630
+ inst.hookable
631
+ end
632
+
633
+ it 'should be able to use private methods as hooks' do
634
+ @class.class_eval %{private; def nike; doit!; end;}
635
+ @class.before(:hookable, :nike)
636
+
637
+ inst = @class.new
638
+ inst.should_receive(:doit!)
639
+ inst.hookable
640
+ end
641
+ end
642
+
643
+ end
644
+
645
+ describe "hook invocation with class inheritance" do
646
+
647
+ describe "for class methods" do
648
+ it 'should run an advice block when the class is inherited' do
649
+ @class.before_class_method(:clakable) { hi_mom! }
650
+ @child = Class.new(@class)
651
+ @child.should_receive(:hi_mom!)
652
+ @child.clakable
653
+ end
654
+
655
+ it 'should run an advice block on child class when hook is registered in parent after inheritance' do
656
+ @child = Class.new(@class)
657
+ @class.before_class_method(:clakable) { hi_mom! }
658
+ @child.should_receive(:hi_mom!)
659
+ @child.clakable
660
+ end
661
+
662
+ it 'should be able to declare advice methods in child classes' do
663
+ @class.class_eval %{def self.before_method; hi_dad!; end;}
664
+ @class.before_class_method(:clakable, :before_method)
665
+
666
+ @child = Class.new(@class) do
667
+ def self.child; hi_mom!; end;
668
+ before_class_method(:clakable, :child)
669
+ end
670
+
671
+ @child.should_receive(:hi_dad!).once.ordered
672
+ @child.should_receive(:hi_mom!).once.ordered
673
+ @child.clakable
674
+ end
675
+
676
+ it "should not execute hooks added in the child classes when in the parent class" do
677
+ @child = Class.new(@class) { def self.child; hi_mom!; end; }
678
+ @child.before_class_method(:clakable, :child)
679
+ @class.should_not_receive(:hi_mom!)
680
+ @class.clakable
681
+ end
682
+
683
+ it 'should not call the hook stack if the hookable method is overwritten and does not call super' do
684
+ @class.before_class_method(:clakable) { hi_mom! }
685
+ @child = Class.new(@class) do
686
+ def self.clakable; end;
687
+ end
688
+
689
+ @child.should_not_receive(:hi_mom!)
690
+ @child.clakable
691
+ end
692
+
693
+ 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
694
+ @child = Class.new(@class) do
695
+ before_class_method(:clakable) { hi_mom! }
696
+ def self.clakable; end;
697
+ end
698
+
699
+ @child.should_not_receive(:hi_mom!)
700
+ @child.clakable
701
+ end
702
+
703
+ it 'should not call hooks defined in child class even if hook method exists in parent' do
704
+ @class.class_eval %{def self.hello_world; hello_world!; end;}
705
+ @child = Class.new(@class) do
706
+ before_class_method(:clakable, :hello_world)
707
+ end
708
+
709
+ @class.should_not_receive(:hello_world!)
710
+ @class.clakable
711
+ end
712
+ end
713
+
714
+ describe "for instance methods" do
715
+ it 'should run an advice block when the class is inherited' do
716
+ @inherited_class = Class.new(@class)
717
+ @class.before(:hookable) { hi_dad! }
718
+
719
+ inst = @inherited_class.new
720
+ inst.should_receive(:hi_dad!)
721
+ inst.hookable
722
+ end
723
+
724
+ it 'should run an advice block on child class when hook is registered in parent after inheritance' do
725
+ @child = Class.new(@class)
726
+ @class.before(:hookable) { hi_mom! }
727
+
728
+ inst = @child.new
729
+ inst.should_receive(:hi_mom!)
730
+ inst.hookable
731
+ end
732
+
733
+ it 'should be able to declare advice methods in child classes' do
734
+ @class.send(:define_method, :before_method) { hi_dad! }
735
+ @class.before(:hookable, :before_method)
736
+
737
+ @child = Class.new(@class) do
738
+ def child; hi_mom!; end;
739
+ before :hookable, :child
740
+ end
741
+
742
+ inst = @child.new
743
+ inst.should_receive(:hi_dad!).once.ordered
744
+ inst.should_receive(:hi_mom!).once.ordered
745
+ inst.hookable
746
+ end
747
+
748
+ it "should not execute hooks added in the child classes when in parent class" do
749
+ @child = Class.new(@class)
750
+ @child.send(:define_method, :child) { hi_mom! }
751
+ @child.before(:hookable, :child)
752
+
753
+ inst = @class.new
754
+ inst.should_not_receive(:hi_mom!)
755
+ inst.hookable
756
+ end
757
+
758
+ it 'should not call the hook stack if the hookable method is overwritten and does not call super' do
759
+ @class.before(:hookable) { hi_mom! }
760
+ @child = Class.new(@class) do
761
+ def hookable; end;
762
+ end
763
+
764
+ inst = @child.new
765
+ inst.should_not_receive(:hi_mom!)
766
+ inst.hookable
767
+ end
768
+
769
+ 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
770
+ @child = Class.new(@class) do
771
+ before(:hookable) { hi_mom! }
772
+ def hookable; end;
773
+ end
774
+
775
+ inst = @child.new
776
+ inst.should_not_receive(:hi_mom!)
777
+ inst.hookable
778
+ end
779
+
780
+ it 'should not call hooks defined in child class even if hook method exists in parent' do
781
+ @class.send(:define_method, :hello_world) { hello_world! }
782
+ @child = Class.new(@class) do
783
+ before(:hookable, :hello_world)
784
+ end
785
+
786
+ inst = @class.new
787
+ inst.should_not_receive(:hello_world!)
788
+ inst.hookable
789
+ end
790
+
791
+ it 'should call different hooks in different children when they are defined there' do
792
+ @class.send(:define_method, :hello_world) {}
793
+
794
+ @child1 = Class.new(@class) do
795
+ before(:hello_world){ hi_dad! }
796
+ end
797
+
798
+ @child2 = Class.new(@class) do
799
+ before(:hello_world){ hi_mom! }
800
+ end
801
+
802
+ @child3 = Class.new(@child1) do
803
+ before(:hello_world){ hi_grandma! }
804
+ end
805
+
806
+ inst1 = @child1.new
807
+ inst2 = @child2.new
808
+ inst3 = @child3.new
809
+ inst1.should_receive(:hi_dad!).once
810
+ inst2.should_receive(:hi_mom!).once
811
+ inst3.should_receive(:hi_dad!).once
812
+ inst3.should_receive(:hi_grandma!).once
813
+ inst1.hello_world
814
+ inst2.hello_world
815
+ inst3.hello_world
816
+ end
817
+
818
+ end
819
+
820
+ end
821
+
822
+ describe "hook invocation with module inclusions / extensions" do
823
+
824
+ describe "for class methods" do
825
+ it "should not overwrite methods included by extensions after the hook is declared" do
826
+ @module.class_eval do
827
+ @another_module = Module.new do
828
+ def greet; greetings_from_another_module; super; end;
829
+ end
830
+
831
+ def self.extended(base)
832
+ base.before_class_method(:clakable, :greet)
833
+ base.extend(@another_module)
834
+ end
835
+ end
836
+
837
+ @class.extend(@module)
838
+ @class.should_receive(:greetings_from_another_module).once.ordered
839
+ @class.should_receive(:greetings_from_module).once.ordered
840
+ @class.clakable
841
+ end
842
+ end
843
+
844
+ describe "for instance methods" do
845
+ it 'should not overwrite methods included by modules after the hook is declared' do
846
+ @module.class_eval do
847
+ @another_module = Module.new do
848
+ def greet; greetings_from_another_module; super; end;
849
+ end
850
+
851
+ def self.included(base)
852
+ base.before(:hookable, :greet)
853
+ base.send(:include, @another_module)
854
+ end
855
+ end
856
+
857
+ @class.send(:include, @module)
858
+
859
+ inst = @class.new
860
+ inst.should_receive(:greetings_from_another_module).once.ordered
861
+ inst.should_receive(:greetings_from_module).once.ordered
862
+ inst.hookable
863
+ end
864
+ end
865
+
866
+ end
867
+
868
+ describe "hook invocation with unrelated classes" do
869
+
870
+ describe "for class methods" do
871
+ it "should not execute hooks registered in an unrelated class" do
872
+ @class.before_class_method(:clakable) { hi_mom! }
873
+
874
+ @other.should_not_receive(:hi_mom!)
875
+ @other.clakable
876
+ end
877
+ end
878
+
879
+ describe "for instance methods" do
880
+ it "should not execute hooks registered in an unrelated class" do
881
+ @class.before(:hookable) { hi_mom! }
882
+
883
+ inst = @other.new
884
+ inst.should_not_receive(:hi_mom!)
885
+ inst.hookable
886
+ end
887
+ end
888
+
889
+ end
890
+
891
+ describe "using before hook" do
892
+
893
+ describe "for class methods" do
894
+
895
+ it 'should run the advice before the advised method' do
896
+ @class.class_eval %{def self.hook_me; second!; end;}
897
+ @class.register_class_hooks(:hook_me)
898
+ @class.before_class_method(:hook_me, :first!)
899
+
900
+ @class.should_receive(:first!).ordered
901
+ @class.should_receive(:second!).ordered
902
+ @class.hook_me
903
+ end
904
+
905
+ it 'should execute all advices once in order' do
906
+ @class.before_class_method(:clakable, :hook_1)
907
+ @class.before_class_method(:clakable, :hook_2)
908
+ @class.before_class_method(:clakable, :hook_3)
909
+
910
+ @class.should_receive(:hook_1).once.ordered
911
+ @class.should_receive(:hook_2).once.ordered
912
+ @class.should_receive(:hook_3).once.ordered
913
+ @class.clakable
914
+ end
915
+ end
916
+
917
+ describe "for instance methods" do
918
+
919
+ it 'should run the advice before the advised method' do
920
+ @class.class_eval %{
921
+ def hook_me; second!; end;
922
+ }
923
+ @class.register_instance_hooks(:hook_me)
924
+ @class.before(:hook_me, :first!)
925
+
926
+ inst = @class.new
927
+ inst.should_receive(:first!).ordered
928
+ inst.should_receive(:second!).ordered
929
+ inst.hook_me
930
+ end
931
+
932
+ it 'should execute all advices once in order' do
933
+ @class.before(:hookable, :hook_1)
934
+ @class.before(:hookable, :hook_2)
935
+ @class.before(:hookable, :hook_3)
936
+
937
+ inst = @class.new
938
+ inst.should_receive(:hook_1).once.ordered
939
+ inst.should_receive(:hook_2).once.ordered
940
+ inst.should_receive(:hook_3).once.ordered
941
+ inst.hookable
942
+ end
943
+ end
944
+
945
+ end
946
+
947
+ describe 'using after hook' do
948
+
949
+ describe "for class methods" do
950
+
951
+ it 'should run the advice after the advised method' do
952
+ @class.class_eval %{def self.hook_me; first!; end;}
953
+ @class.register_class_hooks(:hook_me)
954
+ @class.after_class_method(:hook_me, :second!)
955
+
956
+ @class.should_receive(:first!).ordered
957
+ @class.should_receive(:second!).ordered
958
+ @class.hook_me
959
+ end
960
+
961
+ it 'should execute all advices once in order' do
962
+ @class.after_class_method(:clakable, :hook_1)
963
+ @class.after_class_method(:clakable, :hook_2)
964
+ @class.after_class_method(:clakable, :hook_3)
965
+
966
+ @class.should_receive(:hook_1).once.ordered
967
+ @class.should_receive(:hook_2).once.ordered
968
+ @class.should_receive(:hook_3).once.ordered
969
+ @class.clakable
970
+ end
971
+
972
+ it "the advised method should still return its normal value" do
973
+ @class.class_eval %{def self.hello; "hello world"; end;}
974
+ @class.register_class_hooks(:hello)
975
+ @class.after_class_method(:hello) { "BAM" }
976
+
977
+ @class.hello.should == "hello world"
978
+ end
979
+
980
+ it "should pass the return value to a hook method" do
981
+ @class.class_eval do
982
+ def self.with_return_val; 'hello'; end;
983
+ def self.after_with_return_val(retval); retval.should == 'hello'; end;
984
+ after_class_method(:with_return_val, :after_with_return_val)
985
+ end
986
+
987
+ @class.with_return_val
988
+ end
989
+
990
+ it "should pass the return value to a hook block" do
991
+ @class.class_eval do
992
+ def self.with_return_val; 'hello'; end;
993
+ after_class_method(:with_return_val) { |ret| ret.should == 'hello' }
994
+ end
995
+
996
+ @class.with_return_val
997
+ end
998
+
999
+ it "should pass the return value and method arguments to a hook block" do
1000
+ @class.class_eval do
1001
+ def self.with_args_and_return_val(world); 'hello'; end;
1002
+ after_class_method(:with_args_and_return_val) do |hello, world|
1003
+ hello.should == "hello"
1004
+ world.should == "world"
1005
+ end
1006
+ end
1007
+
1008
+ @class.with_args_and_return_val('world')
1009
+ end
1010
+ end
1011
+
1012
+ describe "for instance methods" do
1013
+
1014
+ it 'should run the advice after the advised method' do
1015
+ @class.class_eval %{def hook_me; first!; end;}
1016
+ @class.register_instance_hooks(:hook_me)
1017
+ @class.after(:hook_me, :second!)
1018
+
1019
+ inst = @class.new
1020
+ inst.should_receive(:first!).ordered
1021
+ inst.should_receive(:second!).ordered
1022
+ inst.hook_me
1023
+ end
1024
+
1025
+ it 'should execute all advices once in order' do
1026
+ @class.after(:hookable, :hook_1)
1027
+ @class.after(:hookable, :hook_2)
1028
+ @class.after(:hookable, :hook_3)
1029
+
1030
+ inst = @class.new
1031
+ inst.should_receive(:hook_1).once.ordered
1032
+ inst.should_receive(:hook_2).once.ordered
1033
+ inst.should_receive(:hook_3).once.ordered
1034
+ inst.hookable
1035
+ end
1036
+
1037
+ it "the advised method should still return its normal value" do
1038
+ @class.class_eval %{def hello; "hello world"; end;}
1039
+ @class.register_instance_hooks(:hello)
1040
+ @class.after(:hello) { "BAM" }
1041
+
1042
+ @class.new.hello.should == "hello world"
1043
+ end
1044
+
1045
+ it "should return nil if an after hook throws :halt without a return value" do
1046
+ @class.class_eval %{def with_value; "hello"; end;}
1047
+ @class.register_instance_hooks(:with_value)
1048
+ @class.after(:with_value) { throw :halt }
1049
+
1050
+ @class.new.with_value.should be_nil
1051
+ end
1052
+
1053
+ it "should pass the return value to a hook method" do
1054
+ @class.class_eval do
1055
+ def with_return_val; 'hello'; end;
1056
+ def after_with_return_val(retval); retval.should == 'hello'; end;
1057
+ after(:with_return_val, :after_with_return_val)
1058
+ end
1059
+
1060
+ @class.new.with_return_val
1061
+ end
1062
+
1063
+ it "should pass the return value to a hook block" do
1064
+ @class.class_eval do
1065
+ def with_return_val; 'hello'; end;
1066
+ after(:with_return_val) { |ret| ret.should == 'hello' }
1067
+ end
1068
+
1069
+ @class.new.with_return_val
1070
+ end
1071
+
1072
+ it "should pass the return value and method arguments to a hook block" do
1073
+ @class.class_eval do
1074
+ def with_args_and_return_val(world); 'hello'; end;
1075
+ after(:with_args_and_return_val) do |hello, world|
1076
+ hello.should == "hello"
1077
+ world.should == "world"
1078
+ end
1079
+ end
1080
+
1081
+ @class.new.with_args_and_return_val('world')
1082
+ end
1083
+ end
1084
+
1085
+ end
1086
+
1087
+ describe 'aborting' do
1088
+
1089
+ describe "for class methods" do
1090
+ it "should catch :halt from a before hook and abort the advised method" do
1091
+ @class.class_eval %{def self.no_love; love_me!; end;}
1092
+ @class.register_class_hooks :no_love
1093
+ @class.before_class_method(:no_love) { maybe! }
1094
+ @class.before_class_method(:no_love) { throw :halt }
1095
+ @class.before_class_method(:no_love) { what_about_me? }
1096
+
1097
+ @class.should_receive(:maybe!)
1098
+ @class.should_not_receive(:what_about_me?)
1099
+ @class.should_not_receive(:love_me!)
1100
+ lambda { @class.no_love }.should_not throw_symbol(:halt)
1101
+ end
1102
+
1103
+ it "should not run after hooks if a before hook throws :halt" do
1104
+ @class.before_class_method(:clakable) { throw :halt }
1105
+ @class.after_class_method(:clakable) { bam! }
1106
+
1107
+ @class.should_not_receive(:bam!)
1108
+ lambda { @class.clakable }.should_not throw_symbol(:halt)
1109
+ end
1110
+
1111
+ it "should return nil from the hookable method if a before hook throws :halt" do
1112
+ @class.class_eval %{def self.with_value; "hello"; end;}
1113
+ @class.register_class_hooks(:with_value)
1114
+ @class.before_class_method(:with_value) { throw :halt }
1115
+
1116
+ @class.with_value.should be_nil
1117
+ end
1118
+
1119
+ it "should catch :halt from an after hook and cease the advice" do
1120
+ @class.after_class_method(:clakable) { throw :halt }
1121
+ @class.after_class_method(:clakable) { never_see_me! }
1122
+
1123
+ @class.should_not_receive(:never_see_me!)
1124
+ lambda { @class.clakable }.should_not throw_symbol(:halt)
1125
+ end
1126
+
1127
+ it "should return nil if an after hook throws :halt without a return value" do
1128
+ @class.class_eval %{def self.with_value; "hello"; end;}
1129
+ @class.register_class_hooks(:with_value)
1130
+ @class.after_class_method(:with_value) { throw :halt }
1131
+
1132
+ @class.with_value.should be_nil
1133
+ end
1134
+ end
1135
+
1136
+ describe "for instance methods" do
1137
+ it "should catch :halt from a before hook and abort the advised method" do
1138
+ @class.class_eval %{def no_love; love_me!; end;}
1139
+ @class.register_instance_hooks :no_love
1140
+ @class.before(:no_love) { maybe! }
1141
+ @class.before(:no_love) { throw :halt }
1142
+ @class.before(:no_love) { what_about_me? }
1143
+
1144
+ inst = @class.new
1145
+ inst.should_receive(:maybe!)
1146
+ inst.should_not_receive(:what_about_me?)
1147
+ inst.should_not_receive(:love_me!)
1148
+ lambda { inst.no_love }.should_not throw_symbol(:halt)
1149
+ end
1150
+
1151
+ it "should not run after hooks if a before hook throws :halt" do
1152
+ @class.before(:hookable) { throw :halt }
1153
+ @class.after(:hookable) { bam! }
1154
+
1155
+ inst = @class.new
1156
+ inst.should_not_receive(:bam!)
1157
+ lambda { inst.hookable }.should_not throw_symbol(:halt)
1158
+ end
1159
+
1160
+ it "should return nil from the hookable method if a before hook throws :halt" do
1161
+ @class.class_eval %{def with_value; "hello"; end;}
1162
+ @class.register_instance_hooks(:with_value)
1163
+ @class.before(:with_value) { throw :halt }
1164
+
1165
+ @class.new.with_value.should be_nil
1166
+ end
1167
+
1168
+ it "should catch :halt from an after hook and cease the advice" do
1169
+ @class.after(:hookable) { throw :halt }
1170
+ @class.after(:hookable) { never_see_me! }
1171
+
1172
+ inst = @class.new
1173
+ inst.should_not_receive(:never_see_me!)
1174
+ lambda { inst.hookable }.should_not throw_symbol(:halt)
1175
+ end
1176
+ end
1177
+
1178
+ end
1179
+
1180
+ describe 'aborting with return values' do
1181
+
1182
+ describe "for class methods" do
1183
+
1184
+ it "should be able to abort from a before hook with a return value" do
1185
+ @class.before_class_method(:clakable) { throw :halt, 'omg' }
1186
+ @class.clakable.should == 'omg'
1187
+ end
1188
+
1189
+ it "should be able to abort from an after hook with a return value" do
1190
+ @class.after_class_method(:clakable) { throw :halt, 'omg' }
1191
+ @class.clakable.should == 'omg'
1192
+ end
1193
+
1194
+ end
1195
+
1196
+ describe "for instance methods" do
1197
+
1198
+ it "should be able to abort from a before hook with a return value" do
1199
+ @class.before(:hookable) { throw :halt, 'omg' }
1200
+
1201
+ inst = @class.new
1202
+ inst.hookable.should == 'omg'
1203
+ end
1204
+
1205
+ it "should be able to abort from an after hook with a return value" do
1206
+ @class.after(:hookable) { throw :halt, 'omg' }
1207
+
1208
+ inst = @class.new
1209
+ inst.hookable.should == 'omg'
1210
+ end
1211
+
1212
+ end
1213
+
1214
+ end
1215
+
1216
+ describe "helper methods" do
1217
+ it 'should generate the correct argument signature' do
1218
+ @class.class_eval do
1219
+ def some_method(a, b, c)
1220
+ [a, b, c]
1221
+ end
1222
+
1223
+ def yet_another(a, *heh)
1224
+ [a, *heh]
1225
+ end
1226
+ end
1227
+
1228
+ @class.args_for(@class.instance_method(:hookable)).should == "&block"
1229
+ @class.args_for(@class.instance_method(:some_method)).should == "_1, _2, _3, &block"
1230
+ @class.args_for(@class.instance_method(:yet_another)).should == "_1, *args, &block"
1231
+ end
1232
+ end
1233
+
1234
+ end