Module_eval and scope question

When trying to understand a piece of code from the Ruby-On-Rails
framework,
I found that I’m still lacking knowledge about scope issues in Ruby.
Here is a
stripped down version of the code I’m trying to understand (in case
you
happen to use Rails: This is from file scaffolding.rb):

module ActionController
module Scaffolding

module ClassMethods
def scaffold(model_id, options = {})

unless options[:suffix]
module_eval <<-“end_eval”, FILE, LINE
def index
list
end
end_eval
end

end
end
end

The purpose of this code is to create at run-time the function
‘index’.
My question is: Why do I need ‘module_eval’ here? I understand that
I can use module_eval to evaluate an expression in the context of
a different class/module, for example

mymodule.module_eval <<“END”
def foo
end
END

would define foo in the context of mymodule. In the example code
above,
however, there is no SOMETHING.module_eval defined, so the scope
would be ClassMethods anyway and, so I had thought, the author could
have written simply:

module ActionController
module Scaffolding

module ClassMethods
def scaffold(model_id, options = {})

unless options[:suffix]
def index
list
end
end

end
end
end

Of course I’m pretty sure that there was some purpose in using
module_eval
here, though. Could anybody enlighten me why it is necessary, and why
my
simpler solution would not work?

I posted this question already in Ruby-Talk, and got the comment

“I believe the answer is that it’s evaluated at run-time, so the
module_eval refers to a different module, but I’m not sure about that.
It could just be that the Rails guys screwed up or something.”

which is not entirely convincingly to me. Maybe some Rails expert
could either
confirm that comment or propose a different answer?

Ronald

On Jan 13, 2008 7:24 PM, Ronny [email protected] wrote:

Of course I’m pretty sure that there was some purpose in using
module_eval
here, though. Could anybody enlighten me why it is necessary, and why
my
simpler solution would not work?

With the #module_eval, #index becomes an instance method of self
(which would be the client code’s controller class at this point).

Without the #module_eval, #index becomes an instance method of
ClassMethods. Since this module is not #included in anything (it
#extends a class, but is not #include-d in one), this does nothing
useful.

Here’s a concentrated version of what’s going on. Give it a run and
see if it clears things up.

module ClassMethods
def add_f
module_eval <<-EOS
def f
p self
end
EOS
end
end

class C
extend ClassMethods
add_f
end

p C.instance_methods.include?(‘f’)
p ClassMethods.instance_methods.include?(‘f’)

Regards,
George.

With the #module_eval, #index becomes an instance method of self
(which would be the client code’s controller class at this point).

Without the #module_eval, #index becomes an instance method of
ClassMethods. Since this module is not #included in anything (it
#extends a class, but is not #include-d in one), this does nothing
useful.

Thank you so much! This really clarifies it!!

Ronald