First, I'd like to say it makes sense to define instance_eval in
BasicObject. Both object instances (e.g. obj = Object.new or obj =
MyClass.new) and class objects (e.g. MyClass = Class.new) are both
instances of a class, in the former of the class Object or a client-
defined class (which implicitly inherits from Object) and in the
latter of the class Class. But because they are both instances, we
want to give them both access to the method instance_eval. It makes
sense to define this method instance_eval in either Object or
BasicObject, so that they will be inherited by regular object
instances and class objects.

class_eval is justifiably declared in the Module class. class_eval
evaluates a class and adds instance methods to that class. All class
objects are instances of Class, and Module is the superclass of Class.
Hence, all class objects have access to the instance methods of
Module, where class_eval is defined, in addition to them having access
to the instance methods of class Class. For example:

1.9.3p0 :092 > MyClass.class_eval {
1.9.3p0 :093 >     def my_class
1.9.3p0 :094?>     puts "yes im an instance method of
#{self.class.name}"
1.9.3p0 :095?>     end
1.9.3p0 :096?>   }
 => nil
1.9.3p0 :097 > MyClass.new.my_class
yes im an instance method of MyClass

Basically, what we did with class_eval is evaluate the class context
to add methods to it for the class' instances. So it really would not
make sense to have a class_eval definition available to instances
themselves. Yet, in the current library, it's possible:

1.9.3p0 :098 > obj = Object.new
 => #<Object:0x007ff4ec8fc0f8>
1.9.3p0 :099 > obj.class_eval {}
 => nil

What's written above really doesn't make any sense, but it works.
There's no NoMethodError exception raised when invoking class_eval on
the object instance. In actuality, that class_eval invocation does not
trace to Module's definition of class_eval. That would be impossible,
because obj is an instance of Object class, which inherits from
BasicObject and the inheritance chain stops there. There's no Module
in obj's inheritance chain. So then where is class_eval defined for
obj? It's defined in Kernel:

1.9.3p0 :083 > Kernel.instance_methods(false).include? :class_eval
 => true

As you may know, the Kernel module is included in Object and hence all
its method definitions become available as instance methods to Object,
so that when our obj instance invokes class_eval, it will first search
Object class, and then check the module Kernel, where the definition
will be found.

But I don't see why class_eval is defined in Object. The obj instance
is not a class object, and therefore the new method is not available
to it, so it's not like we can add instance methods to obj within the
block of class_eval:

1.9.3p0 :098 > obj = Object.new
 => #<Object:0x007ff4ec8fc0f8>
1.9.3p0 :101 > obj.class_eval {
1.9.3p0 :102 >     def my_class
1.9.3p0 :103?>     puts "yes im an instance method of
#{self.class.name}"
1.9.3p0 :104?>     end
1.9.3p0 :105?>   }
 => nil
1.9.3p0 :106 > obj.new.my_class
NoMethodError: undefined method `new' for #<Object:0x007ff4ec8fc0f8>

#as expected, the exception is raised, because obj is not a class
object.

So why is class_eval in Kernel? obj is not a class object, and we
shouldn't be allowed to invoke class_eval on obj...

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Talk" group.
To post to this group, send email to rubyonrails-talk@googlegroups.com.
To unsubscribe from this group, send email to 
rubyonrails-talk+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to