<- Back

Using class_eval in Ruby

Understanding Ruby's class_eval method and how it enables runtime code evaluation and metaprogramming techniques.

Ruby has a facility for executing code stored in the form of strings at runtime. One of the methods in the cluster of eval methods is the class_eval method.

class_eval evaluates/executes a block of code in the context of the specified Class or module. For example,

class String
  def lowercase
    self.downcase
  end
end

String.class_eval do
  def lowercase
    self.downcase
  end
end

In each of the above cases, the String class is reopened to add a new method.

Let's look at some things which we can do with class_eval that we cannot do with the regular class keyword:

  • Evaluate a string in the class-definition context
  • Use existing local variables inside a class-definition body

Example of evaluating a string of code

x = 1
String.class_eval "x + 1" # => 2

Example of usage of a local variable in regular class-definition body and block given to class_eval

# Out of scope
name = 'John'
class Human
  puts name
end
# NameError (undefined local variable or method)
# inside the scope
name = 'John'
Human.class_eval { puts name } # => 'John'

But the same variable which we just defined is no longer visible when we define a method inside the class_eval block:

Human.class_eval { def speak; puts name; end } # => nil
Human.new.speak # => NameError (undefined local variable or method)

The def inside the block starts a new scope, hence the variable name is not accessible. But there is a way to access the name variable using the method define_method.

Human.class_eval { define_method(:speak) { puts name} } # => :speak
Human.new.speak # => 'John'

The way we do this is by passing the name of the method we want to create either as a string or a symbol and providing a code block, the code block serves as the body of the method. ( See example 👆)

define_method is an instance method of the class Module, so you can call it on any instance of Module or Class.

Read more on the class_eval and define_method: