C0 code coverage information
Generated on Sun Oct 26 11:18:12 -0500 2008 with rcov 0.8.1.2
Code reported as executed by Ruby looks like this...
and this: this line is also marked as covered.
Lines considered as run by rcov, but not reported by Ruby, look like this,
and this: these lines were inferred by rcov (using simple heuristics).
Finally, here's a line marked as not executed.
1 require File.dirname(__FILE__) + '/../spec_helper'
2 require 'aquarium/spec_example_types'
3 require 'aquarium/dsl/aspect_dsl'
4
5 class DSLClass
6 include Aquarium::DSL
7 end
8
9 describe "Aquarium::DSL" do
10 before :all do
11 @advice = proc {|jp, obj, *args| "advice"}
12 @pointcut_opts = {:calls_to => :public_watchful_method, :in_type => Watchful}
13 end
14
15 describe "DSL method #before" do
16 before :each do
17 @aspects = []
18 end
19 after :each do
20 @aspects.each {|a| a.unadvise}
21 end
22
23 it "should be equivalent to advice kind :before." do
24 @aspects << DSLClass.advise(:before, :noop => true, :pointcut => @pointcut_opts, &@advice)
25 @aspects << DSLClass.before( :noop => true, :pointcut => @pointcut_opts, &@advice)
26 @aspects[1].should == @aspects[0]
27 end
28 end
29
30 describe "DSL method #after" do
31 before :each do
32 @aspects = []
33 end
34 after :each do
35 @aspects.each {|a| a.unadvise}
36 end
37
38 it "should be equivalent to advice kind :after." do
39 @aspects << DSLClass.advise(:after, :noop => true, :pointcut => @pointcut_opts, &@advice)
40 @aspects << DSLClass.after( :noop => true, :pointcut => @pointcut_opts, &@advice)
41 @aspects[1].should == @aspects[0]
42 end
43 end
44
45 describe "DSL method #after_raising" do
46 before :each do
47 @aspects = []
48 end
49 after :each do
50 @aspects.each {|a| a.unadvise}
51 end
52
53 it "should be equivalent to advice kind :after_raising." do
54 @aspects << DSLClass.advise(:after_raising, :noop => true, :pointcut => @pointcut_opts, &@advice)
55 @aspects << DSLClass.after_raising( :noop => true, :pointcut => @pointcut_opts, &@advice)
56 @aspects[1].should == @aspects[0]
57 end
58
59 it "should be equivalent to advice kind :after_raising => exceptions, when used with the :exceptions argument." do
60 @aspects << DSLClass.advise(:after_raising, :exceptions => [StandardError], :noop => true, :pointcut => @pointcut_opts, &@advice)
61 @aspects << DSLClass.after_raising( :exceptions => [StandardError], :noop => true, :pointcut => @pointcut_opts, &@advice)
62 @aspects << Aquarium::Aspects::Aspect.new(:after_raising => [StandardError], :noop => true, :pointcut => @pointcut_opts, &@advice)
63 @aspects[1].should == @aspects[0]
64 @aspects[2].specification[:after_raising].should == @aspects[0].specification[:after_raising]
65 end
66 end
67
68 describe "DSL method #after_raising_within_or_returning_from" do
69 before :each do
70 @dsl = DSLClass.new
71 @advice = proc {|jp, obj, *args| "advice"}
72 @aspects = []
73 end
74 after :each do
75 @aspects.each {|a| a.unadvise}
76 end
77
78 it "should be equivalent to advice kind :after." do
79 @aspects << DSLClass.after( :noop => true, :pointcut => @pointcut_opts, &@advice)
80 @aspects << DSLClass.after_raising_within_or_returning_from(:noop => true, :pointcut => @pointcut_opts, &@advice)
81 @aspects[1].should == @aspects[0]
82 end
83 end
84
85 describe "DSL method #after_returning" do
86 before :each do
87 @dsl = DSLClass.new
88 @advice = proc {|jp, obj, *args| "advice"}
89 @aspects = []
90 end
91 after :each do
92 @aspects.each {|a| a.unadvise}
93 end
94
95 it "should be equivalent to advice kind :after_returning." do
96 @aspects << DSLClass.advise(:after_returning, :noop => true, :pointcut => @pointcut_opts, &@advice)
97 @aspects << DSLClass.after_returning( :noop => true, :pointcut => @pointcut_opts, &@advice)
98 @aspects[1].should == @aspects[0]
99 end
100 end
101
102 describe "DSL method #after_returning_from" do
103 before :each do
104 @dsl = DSLClass.new
105 @advice = proc {|jp, obj, *args| "advice"}
106 @aspects = []
107 end
108 after :each do
109 @aspects.each {|a| a.unadvise}
110 end
111
112 it "should be equivalent to advice kind :after_returning." do
113 @aspects << DSLClass.advise(:after_returning, :noop => true, :pointcut => @pointcut_opts, &@advice)
114 @aspects << DSLClass.after_returning_from( :noop => true, :pointcut => @pointcut_opts, &@advice)
115 @aspects[1].should == @aspects[0]
116 end
117 end
118
119 describe "DSL method #after_raising" do
120 before :each do
121 @dsl = DSLClass.new
122 @advice = proc {|jp, obj, *args| "advice"}
123 @aspects = []
124 end
125 after :each do
126 @aspects.each {|a| a.unadvise}
127 end
128
129 it "should be equivalent to advice kind :after_raising." do
130 class ThrowsUp
131 def tosses_cookies *args; raise Exception.new(args.inspect); end
132 end
133 @aspects << DSLClass.advise(:after_raising, :noop => true, :pointcut => {:sending_messages_to => :tosses_cookies, :in_type => ThrowsUp}, &@advice)
134 @aspects << DSLClass.after_raising( :noop => true, :pointcut => {:sending_messages_to => :tosses_cookies, :in_type => ThrowsUp}, &@advice)
135 @aspects[1].should == @aspects[0]
136 end
137 end
138
139 describe "DSL method #after_raising_within" do
140 before :each do
141 @dsl = DSLClass.new
142 @advice = proc {|jp, obj, *args| "advice"}
143 @aspects = []
144 end
145 after :each do
146 @aspects.each {|a| a.unadvise}
147 end
148
149 it "should be equivalent to advice kind :after_raising." do
150 class ThrowsUp
151 def tosses_cookies *args; raise Exception.new(args.inspect); end
152 end
153 @aspects << DSLClass.advise(:after_raising, :noop => true, :pointcut => {:sending_messages_to => :tosses_cookies, :in_type => ThrowsUp}, &@advice)
154 @aspects << DSLClass.after_raising_within( :noop => true, :pointcut => {:sending_messages_to => :tosses_cookies, :in_type => ThrowsUp}, &@advice)
155 @aspects[1].should == @aspects[0]
156 end
157 end
158
159 describe "DSL method #before_and_after" do
160 before :each do
161 @dsl = DSLClass.new
162 @advice = proc {|jp, obj, *args| "advice"}
163 @aspects = []
164 end
165 after :each do
166 @aspects.each {|a| a.unadvise}
167 end
168
169 it "should be equivalent to advice kind :before, :after." do
170 @aspects << DSLClass.advise(:before, :after, :noop => true, :pointcut => @pointcut_opts, &@advice)
171 @aspects << DSLClass.before_and_after( :noop => true, :pointcut => @pointcut_opts, &@advice)
172 @aspects[1].should == @aspects[0]
173 end
174 end
175
176 describe "DSL method #before_and_after_raising_within_or_returning_from" do
177 before :each do
178 @dsl = DSLClass.new
179 @advice = proc {|jp, obj, *args| "advice"}
180 @aspects = []
181 end
182 after :each do
183 @aspects.each {|a| a.unadvise}
184 end
185
186 it "should be equivalent to advice kind :before and advice :after." do
187 @aspects << DSLClass.advise(:before, :after, :noop => true, :pointcut => @pointcut_opts, &@advice)
188 @aspects << DSLClass.before_and_after_raising_within_or_returning_from(:noop => true, :pointcut => @pointcut_opts, &@advice)
189 @aspects[1].should == @aspects[0]
190 end
191 end
192
193 describe "DSL method #before_and_after_returning" do
194 before :each do
195 @dsl = DSLClass.new
196 @advice = proc {|jp, obj, *args| "advice"}
197 @aspects = []
198 end
199 after :each do
200 @aspects.each {|a| a.unadvise}
201 end
202
203 it "should be equivalent to advice kind :before and advice :after_returning." do
204 @aspects << DSLClass.advise(:before, :after_returning, :noop => true, :pointcut => @pointcut_opts, &@advice)
205 @aspects << DSLClass.before_and_after_returning( :noop => true, :pointcut => @pointcut_opts, &@advice)
206 @aspects[1].should == @aspects[0]
207 end
208 end
209
210 describe "DSL method #before_and_after_returning_from" do
211 before :each do
212 @dsl = DSLClass.new
213 @advice = proc {|jp, obj, *args| "advice"}
214 @aspects = []
215 end
216 after :each do
217 @aspects.each {|a| a.unadvise}
218 end
219
220 it "should be equivalent to advice kind :before and advice :after_returning." do
221 @aspects << DSLClass.advise(:before, :after_returning, :noop => true, :pointcut => @pointcut_opts, &@advice)
222 @aspects << DSLClass.before_and_after_returning_from( :noop => true, :pointcut => @pointcut_opts, &@advice)
223 @aspects[1].should == @aspects[0]
224 end
225 end
226
227 describe "DSL method #before_and_after_raising" do
228 before :each do
229 @dsl = DSLClass.new
230 @advice = proc {|jp, obj, *args| "advice"}
231 @aspects = []
232 end
233 after :each do
234 @aspects.each {|a| a.unadvise}
235 end
236
237 it "should be equivalent to advice kind :before and advice :after_raising." do
238 @aspects << DSLClass.advise(:before, :after_raising, :noop => true, :pointcut => @pointcut_opts, &@advice)
239 @aspects << DSLClass.before_and_after_raising( :noop => true, :pointcut => @pointcut_opts, &@advice)
240 @aspects[1].should == @aspects[0]
241 end
242 end
243
244 describe "DSL method #around" do
245 before :each do
246 @dsl = DSLClass.new
247 @advice = proc {|jp, obj, *args| "advice"}
248 @aspects = []
249 end
250 after :each do
251 @aspects.each {|a| a.unadvise}
252 end
253
254 it "should be equivalent to advice kind :around." do
255 @aspects << DSLClass.advise(:around, :noop => true, :pointcut => @pointcut_opts, &@advice)
256 @aspects << DSLClass.around( :noop => true, :pointcut => @pointcut_opts, &@advice)
257 @aspects[1].should == @aspects[0]
258 end
259 end
260
261 describe "DSL method #advise, when determining the \"self\" to advise," do
262 before :each do
263 @aspects = []
264 end
265 after :each do
266 @aspects.each {|a| a.unadvise}
267 end
268
269 it "should ignore the default object \"self\" when an :object is specified." do
270 class Watchful1
271 include Aquarium::DSL
272 def public_watchful_method; end
273 @@watchful = Watchful1.new
274 @@aspect = after(:invoking => :public_watchful_method, :on_object => @@watchful) {|jp, obj, *args|}
275 def self.watchful; @@watchful; end
276 def self.aspect; @@aspect; end
277 end
278 @aspects << Watchful1.after(:invoking => :public_watchful_method, :on_object => Watchful1.watchful) {|jp, obj, *args|}
279 @aspects << Watchful1.aspect
280 @aspects[0].join_points_matched.should_not be_empty
281 @aspects[1].join_points_matched.should == @aspects[0].join_points_matched
282 @aspects[1].pointcuts.should == @aspects[0].pointcuts
283 end
284
285 it "should ignore the default object \"self\" when a :type is specified." do
286 class Watchful2
287 include Aquarium::DSL
288 def public_watchful_method; end
289 @@aspect = after(:calls_to => :public_watchful_method, :in_type => Watchful2) {|jp, obj, *args|}
290 def self.aspect; @@aspect; end
291 end
292 @aspects << Watchful2.after(:calls_to => :public_watchful_method, :in_type => Watchful2) {|jp, obj, *args|}
293 @aspects << Watchful2.aspect
294 @aspects[1].join_points_matched.should == @aspects[0].join_points_matched
295 @aspects[1].pointcuts.should == @aspects[0].pointcuts
296 end
297 end
298
299 describe "DSL method #advise, when determining the type or object to advise," do
300 before :each do
301 @aspects = []
302 end
303 after :each do
304 @aspects.each {|a| a.unadvise}
305 end
306
307 class WatchfulSelf
308 include Aquarium::DSL
309 @@aspect = nil
310 def self.aspect; @@aspect; end
311 def public_watchful_method; "public_watchful_method"; end
312 end
313
314 it "should infer the type as \"self\" when no :object, :type, or :pointcut is specified." do
315 @aspects << WatchfulSelf.after(:calls_to => :public_watchful_method, :in_type => WatchfulSelf) {|jp, obj, *args|}
316 class WatchfulSelf
317 @@aspect = after(:method => :public_watchful_method) {|jp, obj, *args|}
318 end
319 @aspects << WatchfulSelf.aspect
320 @aspects[1].join_points_matched.should == @aspects[0].join_points_matched
321 @aspects[1].pointcuts.should == @aspects[0].pointcuts
322 end
323
324 it "should infer the object as \"self\" when no :object, :type, or :pointcut is specified." do
325 watchful_self = WatchfulSelf.new
326 watchful_self.extend Aquarium::DSL
327 @aspects << WatchfulSelf.advise(:after, :pointcut => {:invoking => :public_watchful_method, :on_object => watchful_self}) {|jp, obj, *args|}
328 @aspects << watchful_self.after(:method => :public_watchful_method) {|jp, obj, *args|}
329 @aspects[1].join_points_matched.should == @aspects[0].join_points_matched
330 end
331
332 it "should infer no types or objects if a :pointcut => {...} parameter is used and it does not specify a type or object." do
333 @aspects << DSLClass.after(:pointcut => {:method => /method/}, :ignore_no_matching_join_points=>true) {|jp, obj, *args|}
334 @aspects[0].join_points_matched.size.should == 0
335 end
336 end
337
338 describe "DSL method #advise, when parsing the parameter list," do
339 class Watchful3
340 include Aquarium::DSL
341 def public_watchful_method; "public_watchful_method"; end
342 end
343
344 before :each do
345 @aspects = []
346 end
347 after :each do
348 @aspects.each {|a| a.unadvise}
349 end
350
351 it "should infer the first symbol parameter after the advice kind parameter to be the method name to advise if no other :method => ... parameter is used." do
352 @aspects << Watchful3.after(:public_watchful_method) {|jp, obj, *args|}
353 @aspects.each do |aspect|
354 aspect.join_points_matched.size.should == 1
355 aspect.specification[:methods].should == Set.new([:public_watchful_method])
356 end
357 end
358 end
359
360 describe "DSL method #advise, when determining instance or class methods to advise," do
361 before :each do
362 @aspects = []
363 end
364 after :each do
365 @aspects.each {|a| a.unadvise}
366 end
367
368 it "should treat \"ClassName.advise\" as advising instance methods, by default." do
369 class WatchfulExampleWithSeparateAdviseCall
370 include Aquarium::DSL
371 def public_watchful_method *args; end
372 end
373 advice_called = 0
374 WatchfulExampleWithSeparateAdviseCall.advise :before, :public_watchful_method do |jp, obj, *args|
375 advice_called += 1
376 end
377 WatchfulExampleWithSeparateAdviseCall.new.public_watchful_method :a1, :a2
378 WatchfulExampleWithSeparateAdviseCall.new.public_watchful_method :a3, :a4
379 advice_called.should == 2
380 end
381
382 it "should treat \"ClassName.advise\" as advising instance methods when the :instance method option is specified." do
383 class WatchfulExampleWithSeparateAdviseCall2
384 include Aquarium::DSL
385 def self.class_public_watchful_method *args; end
386 def public_watchful_method *args; end
387 end
388 advice_called = 0
389 WatchfulExampleWithSeparateAdviseCall2.advise :before, :sending_messages_to => /public_watchful_method/, :on_types => WatchfulExampleWithSeparateAdviseCall2, :restricting_methods_to =>[:instance_methods] do |jp, obj, *args|
390 advice_called += 1
391 end
392 WatchfulExampleWithSeparateAdviseCall2.class_public_watchful_method :a1, :a2
393 WatchfulExampleWithSeparateAdviseCall2.class_public_watchful_method :a3, :a4
394 advice_called.should == 0
395 WatchfulExampleWithSeparateAdviseCall2.new.public_watchful_method :a1, :a2
396 WatchfulExampleWithSeparateAdviseCall2.new.public_watchful_method :a3, :a4
397 advice_called.should == 2
398 end
399
400 it "should treat \"ClassName.advise\" as advising class methods when the :class method option is specified." do
401 class WatchfulExampleWithSeparateAdviseCall3
402 include Aquarium::DSL
403 def self.class_public_watchful_method *args; end
404 def public_watchful_method *args; end
405 end
406 advice_called = 0
407 WatchfulExampleWithSeparateAdviseCall3.advise :before, :calling => /public_watchful_method/, :restricting_methods_to =>[:class_methods] do |jp, obj, *args|
408 advice_called += 1
409 end
410 WatchfulExampleWithSeparateAdviseCall3.class_public_watchful_method :a1, :a2
411 WatchfulExampleWithSeparateAdviseCall3.class_public_watchful_method :a3, :a4
412 advice_called.should == 2
413 WatchfulExampleWithSeparateAdviseCall3.new.public_watchful_method :a1, :a2
414 WatchfulExampleWithSeparateAdviseCall3.new.public_watchful_method :a3, :a4
415 advice_called.should == 2
416 end
417
418 it "should invoke the type-based advise for all objects when the aspect is defined by calling #advise within the class definition." do
419 class WatchfulExampleWithBeforeAdvice
420 include Aquarium::DSL
421 @@advice_called = 0
422 def public_watchful_method *args; end
423 before :public_watchful_method do |jp, obj, *args|
424 @@advice_called += 1
425 end
426 def self.advice_called; @@advice_called; end
427 end
428 WatchfulExampleWithBeforeAdvice.new.public_watchful_method :a1, :a2
429 WatchfulExampleWithBeforeAdvice.new.public_watchful_method :a3, :a4
430 WatchfulExampleWithBeforeAdvice.advice_called.should == 2
431 end
432 end
433
434 describe "DSL methods for the advice kind, when determining instance or class methods to advise," do
435 class Watchful4
436 include Aquarium::DSL
437 def public_watchful_method; "public_watchful_method"; end
438 end
439
440 before :each do
441 @advice = proc {|jp, obj, *args| "advice"}
442 @aspects = []
443 end
444 after :each do
445 @aspects.each {|a| a.unadvise}
446 end
447
448 (Aquarium::Aspects::Advice.kinds + [:after_raising_within_or_returning_from]).each do |advice_kind|
449 it "##{advice_kind} method should infer the first symbol parameter as the method name to advise if no other :method => ... parameter is used." do
450 @aspects << Watchful4.method(advice_kind).call(:public_watchful_method, &@advice)
451 @aspects.each do |aspect|
452 aspect.join_points_matched.size.should == 1
453 aspect.specification[:methods].should == Set.new([:public_watchful_method])
454 end
455 end
456 end
457 end
458
459 describe "Synonyms for :types" do
460 Aquarium::Aspects::Aspect::CANONICAL_OPTIONS["types"].each do |key|
461 it "should accept :#{key} as a synonym for :types." do
462 advice = proc {|jp, obj, *args| "advice"}
463 aspect1 = DSLClass.after :noop => true, :calls_to => :public_watchful_method, :types => Watchful, &advice
464 aspect2 = DSLClass.after :noop => true, :calls_to => :public_watchful_method, key.intern => Watchful, &advice
465 aspect2.should == aspect1
466 aspect1.unadvise
467 aspect2.unadvise
468 end
469 end
470 end
471
472 describe "Synonyms for :objects" do
473 Aquarium::Aspects::Aspect::CANONICAL_OPTIONS["objects"].each do |key|
474 it "should accept :#{key} as a synonym for :objects." do
475 watchful = Watchful.new
476 advice = proc {|jp, obj, *args| "advice"}
477 aspect1 = DSLClass.after :noop => true, :calls_to => :public_watchful_method, :objects => watchful, &advice
478 aspect2 = DSLClass.after :noop => true, :calls_to => :public_watchful_method, key.intern => watchful, &advice
479 aspect2.should == aspect1
480 aspect1.unadvise
481 aspect2.unadvise
482 end
483 end
484 end
485
486 describe "Synonyms for :methods" do
487 Aquarium::Aspects::Aspect::CANONICAL_OPTIONS["methods"].each do |key|
488 it "should accept :#{key} as a synonym for :methods." do
489 advice = proc {|jp, obj, *args| "advice"}
490 aspect1 = DSLClass.after :noop => true, :methods => :public_watchful_method, :in_types => Watchful, &advice
491 aspect2 = DSLClass.after :noop => true, key.intern => :public_watchful_method, :in_types => Watchful, &advice
492 aspect2.should == aspect1
493 aspect1.unadvise
494 aspect2.unadvise
495 end
496 end
497 end
498
499 describe "Synonyms for :pointcuts" do
500 Aquarium::Aspects::Aspect::CANONICAL_OPTIONS["pointcuts"].each do |key|
501 it "should accept :#{key} as a synonym for :pointcuts." do
502 watchful = Watchful.new
503 advice = proc {|jp, obj, *args| "advice"}
504 aspect1 = DSLClass.after :noop => true, :pointcuts => {:calls_to => :public_watchful_method, :within_objects => watchful}, &advice
505 aspect2 = DSLClass.after :noop => true, key.intern => {:calls_to => :public_watchful_method, :within_objects => watchful}, &advice
506 aspect2.should == aspect1
507 aspect1.unadvise
508 aspect2.unadvise
509 end
510 end
511 end
512
513 describe "DSL method #advise (or synonyms) called within a type body" do
514 it "will not advise a method whose definition hasn't been seen yet in the type body." do
515 class WatchfulWithMethodAlreadyDefined
516 include Aquarium::DSL
517 @@advice_called = 0
518 def public_watchful_method *args; end
519 before :public_watchful_method do |jp, obj, *args|
520 @@advice_called += 1
521 end
522 def self.advice_called; @@advice_called; end
523 end
524 WatchfulWithMethodAlreadyDefined.new.public_watchful_method :a1, :a2
525 WatchfulWithMethodAlreadyDefined.new.public_watchful_method :a3, :a4
526 WatchfulWithMethodAlreadyDefined.advice_called.should == 2
527 class WatchfulWithMethodNotYetDefined
528 include Aquarium::DSL
529 @@advice_called = 0
530 before(:public_watchful_method, :ignore_no_matching_join_points=>true) {|jp, obj, *args| @@advice_called += 1}
531 def public_watchful_method *args; end
532 def self.advice_called; @@advice_called; end
533 end
534 WatchfulWithMethodNotYetDefined.new.public_watchful_method :a1, :a2
535 WatchfulWithMethodNotYetDefined.new.public_watchful_method :a3, :a4
536 WatchfulWithMethodNotYetDefined.advice_called.should == 0
537 end
538 end
539
540 describe "DSL method #pointcut" do
541 class PC1;
542 def doit; end
543 end
544
545 it "should match equivalent join points as Pointcut.new" do
546 pointcut1 = DSLClass.pointcut :type => PC1, :method => :doit
547 pointcut2 = Aquarium::Aspects::Pointcut.new :type => PC1, :method => :doit
548 pointcut1.join_points_matched.should == pointcut2.join_points_matched
549 pointcut1.join_points_not_matched.should == pointcut2.join_points_not_matched
550 end
551
552 it "should use self as the object if no object or type is specified." do
553 class PC2
554 include Aquarium::DSL
555 POINTCUT = pointcut :method => :doit
556 end
557 pointcut2 = Aquarium::Aspects::Pointcut.new :type => PC2, :method => :doit
558 PC2::POINTCUT.join_points_matched.should == pointcut2.join_points_matched
559 PC2::POINTCUT.join_points_not_matched.should == pointcut2.join_points_not_matched
560 end
561 end
562 end
563
564 class OldDSLClass
565 include Aquarium::Aspects::DSL::AspectDSL
566 end
567 describe "DSL methods available through the old package Aquarium::Aspects::DSL::AspectDSL" do
568 before :each do
569 @dsl = OldDSLClass.new
570 @advice = proc {|jp, obj, *args| "advice"}
571 @aspects = []
572 end
573 after :each do
574 @aspects.each {|a| a.unadvise}
575 end
576
577 it "should be equivalent to advice kind :around." do
578 @aspects << OldDSLClass.advise(:around, :noop => true, :pointcut => @pointcut_opts, &@advice)
579 @aspects << OldDSLClass.around( :noop => true, :pointcut => @pointcut_opts, &@advice)
580 @aspects[1].should == @aspects[0]
581 end
582 end
583
Generated using the rcov code coverage analysis tool for Ruby version 0.8.1.2.