Class_eval() problem

Here is some code that works as expected:

def create_class
  Class.new
end

MyClass = create_class

MyClass.class_eval do
  def greet
    puts 'hi'
  end
end

obj = MyClass.new
obj.greet

--output:--
hi

Now here is a more complex version:

def create_class
  cl = Class.new

  cl.class_eval do
    yield
  end

  return cl
end

MyClass = create_class do

  def greet
    puts 'hello'
  end

end

obj = MyClass.new
obj.send(:greet)
#obj.greet #private method -- NoMethodError

Why is greet() a private method?

···

--
Posted via http://www.ruby-forum.com/.

The greet method is a private method of Object not of MyClass.
So it seems that the def in the block is evaluated in the toplevel scope
(where the block is defined) and not in the MyClass scope.

···

2011/3/11 7stud -- <bbxx789_05ss@yahoo.com>

Here is some code that works as expected:

def create_class
Class.new
end

MyClass = create_class

MyClass.class_eval do
def greet
   puts 'hi'
end
end

obj = MyClass.new
obj.greet

--output:--
hi

Now here is a more complex version:

def create_class
cl = Class.new

cl.class_eval do
   yield
end

return cl
end

MyClass = create_class do

def greet
   puts 'hello'
end

end

obj = MyClass.new
obj.send(:greet)
#obj.greet #private method -- NoMethodError

Why is greet() a private method?

--
Posted via http://www.ruby-forum.com/\.

Gunther Diemant wrote in post #986869:

The greet method is a private method of Object not of MyClass.

Thanks. I didn't realize that Object#methods() returned only public
methods.

So it seems that the def in the block is evaluated in the toplevel scope
(where the block is defined) and not in the MyClass scope.

This is what I've come up with:

def create_class
  cl = Class.new

  cl.class_eval do

    #In this block self=cl because that is
    #what class_eval() does

    yield #However, the block being yielded to
           #doesn't care what the bindings are
           #in this block--the block being yielded
           #to got its bindings when the block was
           #created. (bindings = variable_name/value pairs)

  end

  return cl
end

#self = main

MyClass = create_class do

#This block takes the bindings present when it was
#created along with it no matter where the block ends up,
#and in the current binding self=main. Remember
#blocks can see the variable bindings present outside the
#block.

  def greet
    puts 'hello'
  end

end

obj = MyClass.new
obj.send(:greet) #hello

The block isn't executed until the yield, and when yield is finally
called the block sees self=main. def statements create instance methods
in the "current class", and when self is not a class, the current class
ends up being the class of self. Because self=main the current class
for the block is main's class, which is Object, so the def becomes in
instance method of Object. In other words, when that block executes
it's the exact same thing as defining a method in the top-level, and by
ruby dictate top-level methods are private methods of Object.

···

--
Posted via http://www.ruby-forum.com/\.