As the documentation says, class_eval
evaluates the string or block in the context of the Module or Class. So the following pieces of code are equivalent:
class String
def lowercase
self.downcase
end
end
String.class_eval do
def lowercase
self.downcase
end
end
In each case, the String class has been reopened and a new method defined. That method is available across all instances of the class, so:
"This Is Confusing".lowercase
=> "this is confusing"
"The Smiths on Charlie's Bus".lowercase
=> "the smiths on charlie's bus"
class_eval
has a number of advantages over simply reopening the class. Firstly, you can easily call it on a variable, and it's clear what your intent is. Another advantage is that it will fail if the class doesn't exist. So the example below will fail as Array
is spelt incorrectly. If the class was simply reopened, it would succeed (and a new incorrect Aray
class would be defined):
Aray.class_eval do
include MyAmazingArrayExtensions
end
Finally class_eval
can take a string, which can be useful if you're doing something a little more nefarious...
instance_eval
on the other hand evaluates code against a single object instance:
confusing = "This Is Confusing"
confusing.instance_eval do
def lowercase
self.downcase
end
end
confusing.lowercase
=> "this is confusing"
"The Smiths on Charlie's Bus".lowercase
NoMethodError: undefined method ‘lowercase’ for "The Smiths on Charlie's Bus":String
So with instance_eval
, the method is only defined for that single instance of a string.
So why does instance_eval
on a Class
define class methods?
Just as "This Is Confusing"
and "The Smiths on Charlie's Bus"
are both String
instances, Array
, String
, Hash
and all other classes are themselves instances of Class
. You can check this by calling #class
on them:
"This Is Confusing".class
=> String
String.class
=> Class
So when we call instance_eval
it does the same on a class as it would on any other object. If we use instance_eval
to define a method on a class, it will define a method for just that instance of class, not all classes. We might call that method a class method, but it is just an instance method for that particular class.