M
Minkoo Seo
Hi.
I have a question on the semantics of define_method and alias_method.
Let me start with class_eval and instance_eval. Following is the
excerpt from ri class_eval and ri instance_eval:
* Module.class_eval
Evaluates the string or block in the context of mod. This can be used
to add methods to a class. module_eval returns the result of
evaluating its argument.
* Object.instance_eval
Evaluates a string containing Ruby source code, or the given block,
within the context of the receiver (obj). In order to set the context,
the variable self is set to obj while the code is executing, giving
the code access to obj's instance variables. In the version of
instance_eval that takes a String, the optional second and third
parameters supply a filename and starting line number that are used
when reporting compilation errors.
Therefore, given class Foo; end, Foo.class_eval interprets given block
while treating Foo as a class. Hence, because Foo is a class,
following code adds instance method "instance_hello2".
Foo.class_eval %{
# Add f.instance_hello2 and
# g.instance_hello2
#
# class Foo
# def instance_hello2
# "instance_hello2"
# end
# end
#
def instance_hello2
"instance_hello2"
end
}
On the other hand, Foo.instance_eval interprets given block while
treating Foo itself as the context . Hence, following code adds class
method to "Foo.class_hello2":
Foo.instance_eval %{
# Add Foo.class_hello2
#
# def Foo.class_hello2
# "class_hello2"
# end
def class_hello2
"class_hello2"
end
}
But the problem is define_method do not run differently whatever the
context is:
Foo.class_eval %q[
define_methodyyy) { "yyy" }
]
generates instance method yyy. And,
Foo.class_eval %q[
define_methodyyy) { "yyy" }
]
also generates instance method yyy. Following code generates Foo.zzz
regardless of the context, instance_eval/class_eval, too:
class << Foo; self; end.instance_eval %q[
define_methodzzz) { "zzz" }
]
And I wonder why instance_eval/class_eval do not matter when it comes
to define_method and alias_method. "ri define_method" gives me
"Defines an instance method in the receiver. The method parameter can
be a Proc or Method object. If a block is specified, it is used as the
method body."
So I guess instance_eval and class_eval set context, but the receiver
is always the one precedes the instance_eval and class_eval clause. As
an example,
Foo.instance_eval { # Foo is the receiver
# Interprets under the context of Foo object. Hence, add method to
Foo itself, resulting in class method.
def ...
end
# Because Foo is the receiver, an instance method is added to Foo.
define_method ...
}
On the other hand,
class << Foo; self; end.class_eval { # Foo's metaclass(I'll denote
this as (Foo) fron now on) is the receiver
# Interprets treating (Foo) as a class. Hence, Foo's class method
like Foo.bar is generated.
def ...
end
# Because (Foo) is the receiver, an instance method is added to
(Foo). And this means
# methods are added to Foo which is the instance of (Foo).
define_method ...
}
Did I miss anything? Please verify whether my reasoning is correct.
Sincerely Yours,
Minkoo Seo
I have a question on the semantics of define_method and alias_method.
Let me start with class_eval and instance_eval. Following is the
excerpt from ri class_eval and ri instance_eval:
* Module.class_eval
Evaluates the string or block in the context of mod. This can be used
to add methods to a class. module_eval returns the result of
evaluating its argument.
* Object.instance_eval
Evaluates a string containing Ruby source code, or the given block,
within the context of the receiver (obj). In order to set the context,
the variable self is set to obj while the code is executing, giving
the code access to obj's instance variables. In the version of
instance_eval that takes a String, the optional second and third
parameters supply a filename and starting line number that are used
when reporting compilation errors.
Therefore, given class Foo; end, Foo.class_eval interprets given block
while treating Foo as a class. Hence, because Foo is a class,
following code adds instance method "instance_hello2".
Foo.class_eval %{
# Add f.instance_hello2 and
# g.instance_hello2
#
# class Foo
# def instance_hello2
# "instance_hello2"
# end
# end
#
def instance_hello2
"instance_hello2"
end
}
On the other hand, Foo.instance_eval interprets given block while
treating Foo itself as the context . Hence, following code adds class
method to "Foo.class_hello2":
Foo.instance_eval %{
# Add Foo.class_hello2
#
# def Foo.class_hello2
# "class_hello2"
# end
def class_hello2
"class_hello2"
end
}
But the problem is define_method do not run differently whatever the
context is:
Foo.class_eval %q[
define_methodyyy) { "yyy" }
]
generates instance method yyy. And,
Foo.class_eval %q[
define_methodyyy) { "yyy" }
]
also generates instance method yyy. Following code generates Foo.zzz
regardless of the context, instance_eval/class_eval, too:
class << Foo; self; end.instance_eval %q[
define_methodzzz) { "zzz" }
]
And I wonder why instance_eval/class_eval do not matter when it comes
to define_method and alias_method. "ri define_method" gives me
"Defines an instance method in the receiver. The method parameter can
be a Proc or Method object. If a block is specified, it is used as the
method body."
So I guess instance_eval and class_eval set context, but the receiver
is always the one precedes the instance_eval and class_eval clause. As
an example,
Foo.instance_eval { # Foo is the receiver
# Interprets under the context of Foo object. Hence, add method to
Foo itself, resulting in class method.
def ...
end
# Because Foo is the receiver, an instance method is added to Foo.
define_method ...
}
On the other hand,
class << Foo; self; end.class_eval { # Foo's metaclass(I'll denote
this as (Foo) fron now on) is the receiver
# Interprets treating (Foo) as a class. Hence, Foo's class method
like Foo.bar is generated.
def ...
end
# Because (Foo) is the receiver, an instance method is added to
(Foo). And this means
# methods are added to Foo which is the instance of (Foo).
define_method ...
}
Did I miss anything? Please verify whether my reasoning is correct.
Sincerely Yours,
Minkoo Seo