robsharp-extlib 0.9.15

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