class_eval vs. instance_eval in Ruby

class_eval vs. instance_eval in Ruby

January 15, 2023

This post explains the difference between class_eval and instance_eval methods in Ruby. If you keep getting confused between them when reading or writing Ruby code, it should clarify things a little.

Consider the Greeting class, which forms the basis of other examples.

class Greeting
def initialize(text)
@text = text
end
end

class_eval

class_eval evaluates the string or block in the context of the class, allowing you to reopen the class and define additional behavior on it.

Creating a method inside the block defines an instance method on the class. All Greeting instances can call greet.

Greeting.class_eval do
def greet
puts "#{self.object_id}: #{@text}"
end
end

greeting_one = Greeting.new "Hello World"
greeting_one.greet # 80: Hello World

greeting_two = Greeting.new "How are you?"
greeting_two.greet # 100: How are you?

This is the same as explicitly defining the greet method in the Greeting class. The above code is equivalent to:

class Greeting
def greet
puts "#{self.object_id}: #{@text}"
end
end

Benefits

  1. The first benefit of class_eval is that you can call it on a variable pointing to a class, allowing you to add behavior to a class dynamically.
  2. When using class_eval, the code will fail immediately, if the class doesn’t exist (or if you misspelled the class name). So you can’t accidentally add code to a class that doesn’t exist.

The class_eval method is only available on classes (modules, to be precise). You can’t call it on instances, i.e. instance_name.class_eval doesn’t exist. Ruby throws the error undefined_method class_eval.

greeting_one = Greeting.new "Hello World"

# undefined method 'class_eval'
greeting_one.class_eval do
puts "Error: Method doesn't exist"
end

instance_eval

instance_eval evaluates the code in the context of the receiving object. When you call it on a class, e.g. ClassName.instance_eval, the receiving object is the class, which is an instance of Class. For example, Greeting is an instance of Class.

irb(main):043:0> Greeting.class
=> Class

If you create a method inside the block, it defines a class method. It’s associated with the class object but not visible to instances of that class.

Greeting.instance_eval do
def welcome
puts "#{self.object_id}: This is greeting"
end
end

greeting_one = Greeting.new "Hello World"
greeting_one.welcome # Error: undefined method 'welcome'

Greeting.welcome # 120: This is a greeting
When the code is executing, the variable self is set to the receiving object to set the context, giving the code access to the object’s instance variables and private methods.

Similarly, calling instance_eval on an instance, e.g. instance_name.instance_eval defines a method on that specific instance. No other instances of the class can access that method.

greeting_one.instance_eval do
def personal_greeting
puts "Specific to greeting one"
end
end

# Specific to greeting one
greeting_one.personal_greeting

greeting_two = Greeting.new "Hello"

# undefined method 'personal_greeting' for greeting_two
greeting_two.personal_greeting

Summary

  1. class_eval evaluates the string or block in the context of the class, allowing you to reopen the class and define additional behavior on it.
  2. instance_eval evaluates the string or block in the context of the receiver object, allowing you to run code as if we were inside a method of this object, giving access to its private methods.

Sign up for my newsletter

Let's learn to become better developers.

Comments

No comments yet. Be the first to leave one.

Sign in to leave a comment.