Ruby Metaprogramming: Part I

Share this article

If you’re working with Ruby, chances are by now you’ve heard the word “metaprogramming” thrown around quite a lot. You may have even used metaprogramming, but not fully understood the true power or usefulness of what it can do. By the end of this article, you should have a firm grasp not only of what it is, but also what it capable of, and how you can harness one of Ruby’s “killer features” in your projects.

What is “metaprogramming”?

Metaprogramming is best explained as programming of programming. Don’t let this abstract definition scare you away though, because Ruby makes metaprogramming as easy to understand as it is to work with.

Metaprogramming can be used a way to add, edit or modify the code of your program while it’s running. Using it, you can make new or delete existing methods on objects, reopen or modify existing classes, catch methods that don’t exist, and avoid repetitious coding to keep your program DRY.

Understanding how Ruby calls methods

Before you can understand the full scope of metaprogramming, it’s imperative that you grasp how Ruby finds a method when it is called. When you call a method in Ruby, it must locate that method (if it exists) within all the code that is within the inheritance chain.

class Person
  def say

john_smith =
john_smith.say # => "hello"

When the say() method is called in the example above, Ruby first looks for the parent of the john_smith object; because this object is an instance of the Person class, and it has available a method called say(), this method is called.

Things get more complicated however when the object is an instance of a class which has inherited from another class:

class Animal
  def eats

  def lives_in
    "the wild"

class Pig < Animal
  def lives_in

babe =
babe.lives_in # => "farm"
babe.eats # => "food"
babe.thisdoesnotexist # => NoMethodError: undefined method `thisdoesnotexist' for #<Pig:0x16a53c8>

When we introduce inheritance into the mix, Ruby needs to consider methods defined higher in the inheritance chain. When we call babe.lives_in(), Ruby first checks the Pig class for the method lives_in(); because it exists, it’s called.

It’s a slightly different story when we call the babe.eats() method, though. Ruby checks for that method by asking the Pig class if it can respond to eats(), and in the absence of that method existing on Pig, it will continue by asking the parent class Animal if it can respond; it can in our case, so it will be called.

When we call babe.thisdoesnotexist(), because the method does not exist, we get a NoMethodError exception. You can think of this as a sort of cascade: whatever method is defined lowest in the inheritance chain will be the method that ends up being called; if the method doesn’t exist at all, an exception is raised.

Based on what we have discovered so far, we can summarise the way Ruby looks up each method as a pattern something like the following:

  • Ask the object’s parent class if it can respond to the method, calling it if found.
  • Ask the next parent class up if it can respond to the method and call it if found, continuing this step towards the top of the inheritance chain for as long as necessary.
  • If nothing in the inheritance chain can respond to the method being called, the method does not exist and an Exception should be raised.

Note that because every object inherits from Object (or BasicObject in Ruby 1.9) at the very top level, that class will always be the last to be asked, but only if it makes it that far up the inheritance chain without finding a method that can respond.

Introducing the Singleton class

Ruby gives you the full power of Object Oriented programming and allows you to create objects that inherit from other classes and call their methods; but what if only a single object requires an addition, alteration, or deletion?

The “singleton class” (sometimes known as the “Eigenclass”), is designed exactly for this and allows you to do all that and more. A simple example is in order:

greeting = "Hello World"

def greeting.greet

greeting.greet # => "Hello World"

Let’s digest what’s just happened here line by line. On the first line, we create a new variable called greeting that represents a simple String value. On the second line, we create a new method called greeting.greet, and give it a very simple content. Ruby allows you to choose what object to attach a method definition to by using the format some_object.method_name, which you may recognize as the same syntax for adding class methods to classes (ie. def self.something). In this case, as we had greeting first, the method has been attached to our greeting variable. On the final line, we call the new greeting.greet method we just defined.

The greeting.greet method has access to the entire object it has been attached to; in Ruby, we always refer to that object as self. In this case, self refers to the String value we attached it to. If we had attached it to a Array, self would have returned that Array object.

As you’re about to see, adding methods using some_object.method_name is not always the best way to do such tasks. That’s why Ruby provides another far more useful way of working with objects and their methods in a dynamic way. Meet the Singleton class:

greeting = "i like cheese"

class << greeting
  def greet
    "hello! " + self

greeting.greet # => "hello! i like cheese"

The syntax is very strange, but the outcome is the same as our some_object.method_name way of adding methods. This singleton class method allows you to add many methods at once without having to prefix all of your method names. This syntax also allows you to add anything you would normally add during the declaration of a class, including attr_writer, attr_reader, and attr_accessor methods.

How does it work?

So how does it actually work? The name “singleton class” might have given this away slightly, but Ruby is sneaky and adds another class into our inheritance chain. When you try to operate on the singleton class, Ruby needs a way to add methods to the object we’re adding to, something that the language does not allow. To get around this it creates a secret new class, which we call the “singleton class”. This class is given the methods and changes instead, is made the parent of the object we’re working on. This singleton class is also made an instance of the previous parent of our object so that the inheritance chain remains mostly unchanged:

some object instance > singleton class > parent class > ... > Object/BasicObject

Returning to what we know about Ruby method lookup, we previously decided that there was three simple steps that the Ruby interpreter followed when looking up a method. Singleton classes add one extra step to this lookup process:

  • Ask the object if its singleton class can respond to the method, calling it if found.
  • Ask the object’s parent class if it can respond to the method, calling it if found.
  • Ask the next parent class up if it can respond to the method and call it if found, continuing this step towards the top of the inheritance chain for as long as necessary.
  • If nothing in the inheritance chain can respond to the method being called, the method does not exist and an Exception should be raised.

As we previously discussed, you can think of this as a cascade, and that has a very important impact on our idea of objects in Ruby: not only can Objects gain methods from their inherited classes, but now they can gain individually unique methods as the program is running.

Putting metaprogramming to work with instance_eval and class_eval

Having singleton classes is all good and well, but to truly work with objects dynamically you need to be able to re-open them at runtime within other functions. Unfortunately, Ruby does not syntactically allow you to have any class statements within a function. This is where instance_eval comes into the picture.

The instance_eval method is defined in Ruby’s standard Kernel module and allows you to add instance methods to an object just like our singleton class syntax.

foo = "bar"
foo.instance_eval do
  def hi
    "you smell"

foo.hi # => "you smell"

The instance_eval method can take a block (which has self set to that of the object you’re operating on), or a string of code to be evaluated. Inside the block, you can define new methods as if you were writing a class, and these will be added to the singleton class of the object.

Methods defined by instance_eval will be instance methods. It’s important to note that the scope is that of instance methods, because it means you can’t do things like attr_accessor as a result. If you find yourself needing this, you’ll want to operate on the Class of the object instead using class_eval:

bar = "foo"
bar.class.class_eval do
  def hello
    "i can smell you from here"

bar.hello # => "i can smell you from here"

As you can see, instance_eval and class_eval are very similar, but their scope and application differs ever so slightly. You can remember what to use in each situation by remembering that you use instance_eval to make instance methods, and use class_eval to make class methods.

Why do I care?

As this point you’re probably thinking “that’s great, but why should I care? What real world value does any of this have?” The simple answer is “yes you should” and “a lot”.

Metaprograming allows you to create more flexible code, be it through beautiful APIs or easily testable code. More than that though, it allows you to do that using powerful and elegant programming techniques and syntax. Metaprogramming allows you to create code that is DRY, highly reusable, and extremely concise.

In part two of this series we’ll look at how to apply Metaprogramming to everyday problems, and see how the elegance and power of it can change the way you develop solutions forever.

Frequently Asked Questions about Ruby Metaprogramming

What is the basic concept of metaprogramming in Ruby?

Metaprogramming in Ruby is a coding technique that allows developers to write code that writes other codes. It’s a way of programming in which code can be generated, inspected, and modified at runtime. This technique is used to reduce repetitive code and make it more dynamic and flexible. It’s a powerful tool in Ruby, but it should be used with caution as it can make code more complex and harder to debug.

How does metaprogramming differ in Ruby compared to other languages?

Ruby is known for its powerful metaprogramming capabilities. Unlike many other languages, Ruby allows for a high degree of flexibility and dynamism in its code. This is because Ruby treats everything, including classes and methods, as objects. This allows developers to modify and manipulate these objects at runtime, which is the essence of metaprogramming.

What are some practical applications of metaprogramming in Ruby?

Metaprogramming in Ruby can be used in a variety of ways. For example, it can be used to create domain-specific languages (DSLs), which are mini languages tailored to a specific application domain. It can also be used to add new methods to existing classes, or to change the behavior of existing methods. Additionally, metaprogramming can be used to automate repetitive tasks, making your code more DRY (Don’t Repeat Yourself).

What are the risks or downsides of using metaprogramming in Ruby?

While metaprogramming in Ruby can be powerful, it also comes with risks. It can make code more complex and harder to understand, especially for developers who are not familiar with metaprogramming techniques. It can also make debugging more difficult, as errors can be harder to trace. Therefore, it’s important to use metaprogramming judiciously and to always keep your code as clear and simple as possible.

How can I start learning metaprogramming in Ruby?

The best way to start learning metaprogramming in Ruby is to first have a solid understanding of Ruby itself. Once you’re comfortable with the basics of Ruby, you can start exploring metaprogramming by reading tutorials, books, and articles on the topic. Practice is also key – try to write your own metaprogramming code and experiment with different techniques.

Can you provide an example of metaprogramming in Ruby?

Sure, here’s a simple example of metaprogramming in Ruby. Let’s say you have a class called Book, and you want to add a method to this class at runtime. You can do this using the define_method method, like so:

class Book

Book.define_method(:title) do
"The Great Gatsby"

book =
puts book.title # Outputs: "The Great Gatsby"

In this example, we’re defining a new method called title on the Book class at runtime. This is a basic example of metaprogramming in Ruby.

What is the role of the method_missing method in Ruby metaprogramming?

The method_missing method in Ruby is a key part of metaprogramming. It’s a method that gets called whenever you try to call a method that doesn’t exist on an object. By defining your own method_missing method, you can control what happens when a non-existent method is called, allowing you to create dynamic methods on the fly.

What is a singleton method in Ruby metaprogramming?

A singleton method in Ruby is a method that is defined on a single object, rather than on a class. This means that the method is only available to that specific object, and not to any other instances of the class. Singleton methods are a key part of Ruby’s metaprogramming capabilities, as they allow you to modify the behavior of individual objects.

What is the send method used for in Ruby metaprogramming?

The send method in Ruby is used to call a method dynamically, or at runtime. It takes the name of the method you want to call as a symbol or string, and any arguments that the method requires. This allows you to call methods dynamically, which is a key part of metaprogramming.

Can you provide an example of using the send method in Ruby metaprogramming?

Sure, here’s an example of using the send method in Ruby:

class Book
def title
"The Great Gatsby"

book =
puts book.send(:title) # Outputs: "The Great Gatsby"

In this example, we’re using the send method to call the title method on the book object. This is a basic example of how the send method can be used in metaprogramming.

Nathan KleynNathan Kleyn
View Author

Hi! I currently work for Intent HQ as Director of Engineering, writing functional Scala by day and Rust by night. I write for SitePoint about Ruby, and I’m on Twitter and on GitHub. You can get in touch with me at mail/at/

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week