sundbp-extlib 0.9.14

Sign up to get free protection for your applications and to get access to all the features.
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