Ruby Meta - Method Madness

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!

by Arild Shirazi