Ruby instance_eval and friends
The instance_eval
and class_eval
methods have always been slightly obscure (at least to me). Let’s try understanding better what they are and what is their purpose.
instance_eval
Let’s see what the documentation says:
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.
A common scenario to use instance_eval
is when for some reason we’re calling many methods on the same object:
This can be rewritten this way:
The example is silly but you get the point. For the same reason we can use it to call private methods (that, you might remember, can be called only through an implicit receiver):
Method creation
You’re free to create some methods:
This is equivalent to
The first interesting use of this feature is when we want to add class methods to a class. Remember that in Ruby a class name is a constant assigned to an instance of the Class object.
Therefore adding a class method consists in adding an instance method to an object that happens to be an instance of the Class
class. This is one of the things that has been puzzling me for a while. The name instance_eval
makes you think you will be creating instance methods but in this case you’re actually creating class methods. That’s because the receiver is an instance of Class
!
class_eval
This is what the documentation says:
mod.class_eval(string [, filename [, lineno]]) 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. The optional filename and lineno parameters set the text for error messages.
The module_eval
method is an alias. These methods, unlike instance_eval
, can only be called on classes and modules.
As instance_eval
it changes self
, but it changes the current class as well.
Basicly what it does is adding instance methods to an existing class:
These two things are equivalent:
You would expect, given its name, to use this method to add class methods. It works the opposite way:
- with
instance_eval
on a class you add class methods to that class - with
class_eval
on a class you’re adding instance methods
But if you do something like this:
You’ve just added a class method!
Sum up
There are many ways to define or add a method to a class or to an instance. Let’s try to list them all:
class method
In the class definition
Outside the class definition
Opening the singleton internally
Opening the singleton externally
Through class_eval
on the class name and self
receiver
Through instance_eval
on the class name
instance method
Basic syntax
With class_eval
With define_method
instance method on a single instance
Basic syntax
With instance_eval
Reopening the singleton class:
Another comparison between the two methods
instance_eval
- can be called on any object
- method definitions will be added to the receiver singleton class, thus if it is an instance it will be an instance method, if it is a class it will be a class method: current class is set to the singleton
class_eval
- can be called only on classes and modules
- method definitions will be added to the object itself, not to its singleton: current class is set to the class/module itself
Sources
- http://railstalk.com/2010/1/8/instance_eval-vs-class_eval-in-ruby
- http://stackoverflow.com/questions/900419/how-to-understand-the-difference-between-class-eval-and-instance-eval
- http://briancarper.net/blog/196/