On Oct 6, 2008, at 9:56 AM, Paul Brannan wrote:

> Instance_eval for initialization has surprising behavior for instance
> variables (e.g. as in Ruby/Tk).
>
> A method that affects only method calls and not instance variables  
> would
> make this idiom more viable.
>
> I don't know whether that is a good thing or a bad thing.

Here's an thread-safe, pure Ruby version of with:

-- Start Code ----------------------------------------
if RUBY_VERSION < "1.9"
   require 'builder/blankslate'
   BasicObject = BlankSlate
end

class MethodDirector < BasicObject
   def initialize(objs)
     @objects = objs
   end

   def method_missing(sym, *args, &block)
     @objects.each do |obj|
       begin
         return obj.send(sym, *args, &block)
       rescue ::NoMethodError => ex
         # Try the next one
       end
     end
     super
   end
end

def with(obj, &block)
   containing_obj = eval("self", block.binding)
   director = MethodDirector.new([obj, containing_obj])
   director.instance_eval(&block)
end
-- End Code ----------------------------------------

The above code has the quirk that within the block, "self" is neither  
the containing object, nor the object given to with, but the  
MethodDirector object.

The performance characteristics of this implementation are propably  
pretty poor.  Not only do we create a new MethodDirector object each  
time, but we rely on method_missing to catch all method calls with an  
implicit object.

I considered using something like this for Builder at one point in  
time and rejected it because of the complexity/magic.  I still think  
that was a good decision.

-- 
-- Jim Weirich
-- jim.weirich / gmail.com