As the documentation says, class_eval evaluates a row or block in the context of a module or class. Thus, the following code fragments 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 was reopened and a new method defined. This method is available for all instances of the class, therefore:
"This Is Confusing".lowercase => "this is confusing" "The Smiths on Charlie Bus".lowercase => "the smiths on charlie bus"
class_eval has several advantages over just reopening a class. First, you can easily call it a variable, and itโs clear what your intentions are. Another advantage is that it will not work if the class does not exist. Thus, the example below will not be executed, as Array will be incorrectly specified. If the class was simply reopened, it will succeed (and a new invalid Aray class will be defined):
Aray.class_eval do include MyAmazingArrayExtensions end
Finally, class_eval can take a line that might be useful if you are doing something more vile ...
instance_eval , on the other hand, evaluates the code for one instance of an object:
confusing = "This Is Confusing" confusing.instance_eval do def lowercase self.downcase end end confusing.lowercase => "this is confusing" "The Smiths on Charlie Bus".lowercase NoMethodError: undefined method 'lowercase' for "The Smiths on Charlie Bus":String
So, with instance_eval method is defined only for this single row instance.
So why does instance_eval in Class define class methods?
Just like "This Is Confusing" and "The Smiths on Charlie Bus" are instances of String , Array , String , Hash , and all other classes themselves are instances of Class . You can verify this by calling #class on them:
"This Is Confusing".class => String String.class => Class
Therefore, when we call instance_eval , it does the same in the class as it does on any other object. If we use instance_eval to define a method for a class, it will define a method only for that instance of the class, and not for all classes. We can call this method a class method, but it is just an instance method for this particular class.