Ruby metaprogramming is fun and very rewarding, but also a little bewildering. One of the great things about Ruby is that you can dynamically add methods to objects. Ruby gives us #eval
, #instance_eval
, and #class_eval
for this purpose, but the names aren’t as clear as one might expect, and can lead to some confusion. Hopefully the code examples below help clarify how each is used, and get on on the way to meta-mastery.
One important thing to remember in Ruby is that objects are instances of a class, but classes are also objects... classes are instances of class Class
!!
class_eval(string)
means that we are defining a class, and we are eval'ing in that context basically, the equivalent of:
class ClassDemo
eval(string)
end
Demo 1 - class_eval
on a class:
speak_method = 'def speak; puts "hi"; end'
class ClassDemo; end
ClassDemo.class_eval speak_method
ClassDemo.new.speak # hi
ClassDemo.speak # NoMethodError: undefined method `speak' for ClassDemo:Class
Demo 1 corollary - class_eval
on an instance:
# No such thing!
cd = ClassDemo.new
cd.class_eval speak_method # NoMethodError: undefined method `class_eval' for #<ClassDemo:0x...>
instance_eval(string)
means that we are eval'ing for a specific instance when instance_eval'ing on a class, that instance is the class's instance!!
class InstanceDemo
class << self
eval(string)
end
end
Demo 2 - instance_eval
on an instance:
speak_method = 'def speak; puts "hi"; end'
class InstanceDemo; end
id1 = InstanceDemo.new
id2 = InstanceDemo.new
id1.instance_eval speak_method
id1.speak # hi
id2.speak # NoMethodError: undefined method `speak' for #<InstanceDemo:0x...>
Demo 2 corollary - instance_eval
on a class:
speak_method = 'def speak; puts "hi"; end'
class InstanceDemo; end
InstanceDemo.instance_eval speak_method
InstanceDemo.speak # hi
InstanceDemo.new.speak # NoMethodError: undefined method `speak' for #<InstanceDemo:0x...>
So hopefully this helps clarify the distinctions between #eval
, #class_eval
, and #instance_eval
. The next time you want to dynamically modify the methods to objects (and classes), you’ll know which of these methods to choose!