I’m stuck. I’m trying to dynamically define a class method and I can’t wrap my head around the ruby metaclass model. Consider the following class:
class Example
def self.meta; (class << self; self; end); end
def self.class_instance; self; end
end
Example.class_instance.class # => Class
Example.meta.class # => Class
Example.class_instance == Example # => true
Example.class_instance == Example.meta # => false
Obviously both methods return an instance of Class. But these two instances
are not the same. They also have different ancestors:
Example.meta.ancestors # => [Class, Module, Object, Kernel]
Example.class_instance.ancestors # => [Example, Object, Kernel]
What’s the point in making a difference between the metaclass and the class instance?
I figured out, that I can send :define_method to the metaclass to dynamically define a method, but if I try to send it to the class instance it won’t work. At least I could solve my problem, but I still want to understand why it is working this way.
Update Mar 15, 2010 13:40
Are the following assumptions correct.
- If I have an instance method which calls self.instance_eval and defines a method, it will only affect the particular instance of that class.
- If I have an instance method which calls self.class.instance_eval (which would be the same as calling class_eval) and defines a method it will affect all instances of that particular class resulting in a new instance method.
- If I have a class method which calls instance_eval and defines a method it will result in a new instance method for all instances.
- If I have a class method which calls instance_eval on the meta/eigen class and defines a method it will result in a class method.
I think it starts to make sense to me. It would certainly limit your possibilities if self inside an class method would point to the eigen class. If so it would not be possible to define an instance method from inside a class method. Is that correct?
Defining a singleton method dynamically is simple when you use
instance_eval:As for the difference above, you are confusing 2 things:
The meta class defined by you, is what called in Ruby community as singelton class or eigen class. That singleton class is the class that you can add class(singleton) methods to.
As for the class instance you are trying to define using the
class_instancemethod, is nothing but the class itself, to prove it, just try adding an instance method to the classExampleand check if theclass_instancemethod defined by you returns the classExampleitself by checking the existence of that method:Anyway to sum it for you, when you want to add class methods, just add them to that meta class. As for the
class_instancemethod is useless, just remove it.Anyway I suggest you read this post to grasp some concepts of Ruby reflection system.
UPDATE
I suggest you read this nice post: Fun with Ruby’s instance_eval and class_eval,
Unfortunately
class_evalandinstance_evalare confusing because they somehow work against their naming!Now answering your assumptions:
yes:
no
instance_evalin that context will define singleton methods(not instance ones) on the class itself:For that to work replace
instance_evalwithclass_evalabove.Nope:
That will make singleton methods, not instance methods. For that to work replace
instance_evalwithclass_evalabove.well no, that will make so sophisticated stuff, as it will add singleton method to the singleton class, I don’t think that will have any practical use.