/ ruby

Ruby Metaprogramming: class_eval & instance_eval

When I am looking into experimentation for trying new things, it tends to help if I code it out into a breakable toy so to speak. Follow along if you will, while we look at instance_eval and class_eval.

Let's start with instance_eval. According to the Ruby documentation instance_eval is defined as -

"Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj). In order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj’s instance variables. In the version of instance_eval that takes a String, the optional second and third parameters supply a filename and starting line number that are used when reporting compilation errors."

So what does this actually mean? Let's look at it in code.

  johndoe = "john"
  johndoe.instance_eval do
    def uppercase
      self.capitalize
    end
  end
 
  puts johndoe.uppercase
  # => John
 
  "john".uppercase
  # => NoMethodError: undefined method ‘uppercase’ for "john":String

With instance_eval we see that the method is only defined on the single instance of the string.

By definition, according to Ruby, class_eval is defined as -

"Evaluates the string or block in the context of mod. This can be used to add methods to a class. module_eval returns the result of evaluating its argument. The optional filename and lineno parameters set the text for error messages."

Let's take a look at some more code!

  class String
    def uppercase
      self.capitalize
    end
  end
   
  String.class_eval do
    def uppercase
      self.capitalize
    end
  end
   
  puts "john".uppercase
  # => John
  puts "jane".uppercase
  # => Jane

In the code example above both instances of class String behave the exact same way. What is awesome about the method being defined inside those classes, is that the method will now be available to all instances of that class.