According to the Wikipedia definition, metaprogramming is the writing of programs that manipulate themselves (or other programs) at runtime, which basically means a program rewriting parts of itself without having to stop or recompile. In this article we’ll be looking at the basics of metaprogramming using the Ruby language which gives full support to metaprogramming as we’ll be seeing throughout the examples. Be sure to have your Ruby IDE or IRB open as you read, it is very important that you see for yourself the output of every bit of code I write here.

Ruby is a completely object-oriented language. Everything, and I mean everything in Ruby is an object, even the native types such as Integer, String and Float, hell, even the null value (which is nil in Ruby) is an object (that happens to represent nothing)! This means that we don’t really have functions, if every single data is an object, then every single action on that data will be a method. To prove that, here’s a bunch of code that you can run in a single file:

#Notice how I'm making a method call on a String
puts "cat".upcase
puts "cat".class

#Here's an iterator method being called on a simple Integer (Fixnum in Ruby)
5.times { puts 'hi'}
puts 5.class

#Even nil is an object!
puts nil.class

#You can even define methods in nil! We'll be looking more at this later.
def nil.hi
	puts 'hi!'
end

nil.hi

To understand metaprogramming we’ll be looking first at the basics of the Ruby Object Model, in other words, how Ruby deals with objects.

First and foremost, let’s understand how objects work in Ruby. When you make a method call on something, Ruby goes to the receiving object (the thing on the left side of the dot) and looks for its class, there, Ruby looks for the method (the thing on the right side of the dot), if Ruby finds it, then it executes that method, if it doesn’t, Ruby goes up the chain of the receiver’s parent classes until it does find it. It’s as simple as that, it never changes, nor gets more complicated.

Now, as you’ve probably seen in other places (if you’ve looked for it), people usually define metaprogramming as being all about the ‘self’. Self is, in fact, a very important part of metaprogramming, and without understanding it you won’t go very far. Self, just like on most OO languages, is the default receiving object, so if you make a method call without an explicit receiver, Ruby will understand that you’re calling a method on self. Self is also the scope of all instance variables, which in Ruby are started with an @ sign, so, basically, every variable that starts with an @ will get stored in self. Let’s see some code to demonstrate this:

#Let's see what the default current object is
puts self

#And its class
puts self.class

#Now let's see self in action inside a defined class

class Example
	puts self
end


#Moving on to instance variables.
class Something
	
	def initialize
		@value = 10
		print
	end
	
	def change
		@value = 20
		print
	end
	
	def print
		puts @value
	end
	
end

example = Something.new

example.change

We can use this last example (class Something) to demonstrate a pretty interesting use of self. Before actually doing a method call, Ruby changes the default receiver (self) to the new receiver that is being called the method upon. For example, when we call the example.change method, the first thing that happens is that the default receiver is changed to example, so from that moment on, self means example (which is an instance of the Something class). Ruby then looks for the change method in self’s class (which, in this case, is Something) and executes it. See how it all evolves around self?

Let’s talk more about self in the context of instance variables using that same Something class. When we declare example as an instance of Something, @value gets stored inside self (which is the example object, remember?) as 10. The print method is then called, and since it doesn’t have an explicit receiver, that means we’ll be using self, so the print method inside Something will be called, printing out the current value of @value. The same happens when we call change, it simply changes the @value variable inside self and then prints it.

Having understood self, let’s take a look at the concept of anonymous classes, or ghost classes, or singleton classes. In Ruby, it’s possible to define methods to any object on runtime, so if you have some random string that you would like to define a method to it, you can. This is better seen as code than as me describing it, so here:

#Let's say I'm too lazy to create a class for myself and just want to dynamically add methods to a string containing my name

name = "Pedro"

def name.age
	19
end

def name.eye_color
	"brown"
end

puts "#{name} is #{name.age} years old and has #{name.eye_color} eyes"

What happens inside the Ruby interpreter so this may run? Ruby creates an anonymous class (which can’t be seen directly) for that specific string. This anonymous class becomes a child class of the object’s class you’ve used (in this case, String) and holds all the methods related to that specific object, so if you called “John”.age the interpreter would return an error message because you’ve defined age for “Pedro” and not “John”. The name ‘singleton classes’ is given because all objects are applied to a single object (the one you’re defining them on).
Here’s almost the same chunk of code that does manually what Ruby does automatically when you assign a method to an object:

# Here we're assigning the variable klass to a new instance of Class. This new class klass will be a parent of the String class, hence the parameter to the Class.new call.
klass = Class.new(String)

#Now we're gonna create a new String object since our homemade class klass is a parent of String. We didn't define a method "new" for our klass,
#so Ruby goes up the chain of inheritance to String and uses its "new" method, taking characters between " "

name = klass.new("Pedro")

#Here's the same code as the last example

def name.age
	19
end

def name.eye_color
	"brown"
end

puts "#{name} is #{name.age} years old and has #{name.eye_color} eyes"

#Let's just make sure name's class is klass and not String
puts name.class

#Now let's assign a constant to our klass called MyName. This is to prove that you can have classes in Ruby without names, because classes are just objects like all others.
MyName = klass

puts klass

#Just to prove the constant assignment worked:
puts MyName.new("Hi =D")

As you can see, the first 2 lines of code of this last example reflect the same behavior as the first line of code written in the example before, but we just made visible what the Ruby interpreter does behind the scenes when you define methods to objects by explicitely creating a Class object and defining methods to it.

Up to this point, I have been proving a point said since the beggining: Ruby is a completely object oriented language, because even classes are objects, they’re not static entities like in most Class Oriented languages (who call themselves Object Oriented languages). Classes in Ruby are only abstractions used to create other objects, sort of like a factory, and that’s all there is to it.

Okay, if classes are only objects, what about class methods? Yes, class methods, well, here’s some news: there’s no such thing! Using the concepts of anonymous classes we just learned, try to follow the code:

#How do we define class methods? Oh, that's easy!
class Something
	def self.hello
		puts "hello"
	end
end

Something.hello

#Let's compare this to what we had last example:
name = "Pedro"

def name.age
	19
end

puts name.age

#Notice anything familiar? Exactly! It's the same method definition syntax, we have object.another_object. And we've learned what Ruby does when this happens, right?
#So, when we say def self.hello, Ruby creates an anonymous class that will have self as its parent class, and who's self? Something!

#The code bellow will do exactly the same thing as the "class" method definition inside Something.
def Something.hi
	puts "hi"
end

Something.hi

#Since the constant Something is assigned to the class that defined method 'hello', then the method 'hi' will be defined to the same anonymous class as 'hello' did.

There actually is a way of manipulating this anonymous class, so that you don’t have to always keep defining methods using def object.method, let’s have a look at that:

#Let's stick to the same example, but use the << syntax instead:
name = "Pedro"

class << name
	def age
		19
	end
	
	def eye_color
		'brown'
	end
end

puts "#{name} is #{name.age} years old and has #{name.eye_color} eyes"

#When you're using class << object, each method you define inside it will get injected into the object's anonymous class. So by using it inside class definitions, you'll be defining 'class' methods.

class Pedro
	class << self
		def age
			19
		end
		
		def eye_color
			'brown'
		end
	end
end

puts "#{Pedro.name} is #{Pedro.age} years old and has #{Pedro.eye_color} eyes"

#Name is a method inside class Class.

Defining methods to an object is such a cool concept that you can actually develop entire programs without using the class abstraction, and this is called prototype-based development. What? Entire programs? Yes, in fact, languages like JavaScript are entirely based on prototypes, it doesn’t distinguish objects from classes, so, if you want to share behavior between objects, you clone them instead of creating a new one. In Ruby this is possible by using the clone method:

#Let's stick to the same example:
name = "Pedro"

def name.age
	19
end

puts name.age

#I said earlier that if we used another string and call 'age', Ruby would return an error, right? But by using the clone method we can share all of "Pedro"'s and not get an error.

another_name = name.clone

puts another_name.age

#This happens because another_name copies the anonymous class from name along with it.

An important thing to note is that the clone method also copies the state of an object, so all instance variables of the base object would also get copied over. You can see how this is even more powerful than class-based development because class inheritance does not share state, but on the other side, class-based development lets us understand better what’s going on. Prototype-based development is an interesting technique that gives us alot more of flexibility in our code. I’m not saying you should write entire programs with it, but it is something worth learning so you can use it on parts of your code.

Back to class-based development, we use inheritance with the intention of only sharing behavior, which is wrong. Inheritance is supposed to be used when the child class IS also the parent class, let’s see some code:

class Hardware
	attr_accessor :price
	
	def initialize(price)
		@price= price
	end
end

#Good use of inheritance: Keyboard IS also a piece of hardware, so it is fine to use inheritance here.

class Keyboard < Hardware
	attr_accessor :number_of_keys
	def initialize(price, number_of_keys)
		super(price)
		@number_of_keys = number_of_keys
	end
end

my_keyboard = Keyboard.new(50, "I'm seriously not going to count")

puts my_keyboard.price 
puts my_keyboard.number_of_keys

#Bad use of inheritance: Book IS NOT a piece of hardware, but we used it to share the price method, so that's fine right? NO!

class Book < Hardware
	attr_accessor :pages
	
	def initialize(price, pages)
		super(price)
		@pages = pages
	end
end

my_book = Book.new(30,500)
puts my_book.price
puts my_book.pages

The problem that most people use inheritance all the time is because most programming languages don’t offer other choices for sharing behavior (what people tend to do is use object composition). But Ruby offers the use of modules! Modules are chunks of active code that can be included anywhere, making that code available to wherever it was included at. Here’s some code to show off Ruby modules:

#You can use it as a namespace!
module Test
SOME_VALUE = 10
end

puts Test::SOME_VALUE

#You can use it to store 'module' methods, but just like class methods, there is no such thing!

module Test
	def self.hello
		puts 'hi'
	end
end

Test.hello

#And you can use it to share behavior by creating instance methods.

module Print	
	def print_something(something)
		puts something
	end
end

class Something
	include Print
end

example = Something.new

example.print_something("hi")	

When running this code, Ruby creates an anonymous class that will act as a parent class for the object (in this case, book), and this parent anonymous class holds a reference to the module, so this way we can insert methods to the module at runtime and all the classes that include it will automatically have those methods available to it as well.

In the example above we used modules to include instance methods, so here’s how modules can deal with class methods:

module Print	
	def print_something(something)
		puts something
	end
end

class Something
	include Print
end

example = Something.new

example.print_something("hi")	

#We use the include method inside class definitions, but we can also use extend on any object we want!
name = "Pedro"

name.extend Print

name.print_something('hi')
		
#Remember class << object? Look what happens when we use that too:
other = "lol"

class << other
	include Print
end

other.print_something('other')

#As you can see, extend is nothing more than a hidden include in the object's anonymous class! This is important to point out so you remember that you should include modules with instance methods, but extend modules with 'class' methods.
#Confusing? Let's take a deeper look, here is another module:

module Capitalize
	def capitalize_string(string)
		string.upcase!
	end
end

#Let's put it to use:

class Something
	#Here we're including Print, so the methods inside the Print module will only work as instance methods.
	include Print
	#And here were extending Capitalize, so its methods will work as class methods because extends applies its methods to the object's anonymous class.
	extend Capitalize
end

#We don't need a Something instance to call capitalize_string
puts Something.capitalize_string("hi")

#But we do need one for print_something
example = Something.new

example.print_something("something")

Making other people that use your code to always have to include instance methods and extend class methods is not cool, so Ruby has a hook method for that. Hook methods are methods that are called at a certain point in the life cycle of your application, so let’s put the hook method ‘included’ to use:

#We call the included as a module method and pass a class to it (the one that is including the module), then we extend Capitalize so we can use its methods as class methods.
module Print	
	def self.included(klass)
		klass.extend Capitalize
	end
		
	def print_something(something)
		puts something
	end
end

module Capitalize
	def capitalize_string(string)
		string.upcase!
	end
end

#So now, all we have to do is include Print, and Capitalize will come as a bonus:
class Something
	include Print
end

puts Something.capitalize_string("hello")

Okay, until now I talked a bit about the Ruby Object Model, which led us to talk about sharing behavior too, it’s time to finally do some metaprogramming! Let’s learn a few ways of writing code that writes code for us. Probably the most basic Ruby method for metaprogramming is called eval. It simply evaluates a string and turns that into Ruby code, and by being a string, you can inject anything you want with it, like parameters, variables, and so on:

#Basic use of eval:
var = "Hello"
eval "puts var +' sir!'"

#More complex use of eval:
def greeting_generator(name)
	eval "def hello_#{name} 
			puts 'Hello #{name}!' 
		end"
end

['John', 'Mary', 'Mike'].each { |name| greeting_generator name}

hello_John
hello_Mary
hello_Mike

Eval has gone out of use, what is instead used are the core 2 methods for Ruby metaprogramming: instance_eval and class_eval. Both function the same way as eval because you throw in a string to be evaluated as code, but they have specific scopes and different ways of dealing with objects and you can also throw in blocks to be evaluated, instead of just strings.

Instance_eval, as the name points out, is responsible for evaluating code in the scope of an object instance, so every code you write with instance_eval with affect only the receiving object instance:

#Some uses of instance_eval
name = "Pedro"

name.instance_eval do
	puts self
end

#Instance_eval is like penetrating an object and acting like him, so you can even access instance variables (which you normally can't) and even protected methods!
class Me
	@name = "Pedro"
	protected
	def you_cant_get_me
		'damn =('
	end
end

pedro = Me.new

pedro.instance_eval do
	@name = "I'm such a hacker lolz"
	puts you_cant_get_me
	puts @name
end

#What happens when we define methods to an object instance?
name = "Pedro"

name.instance_eval %{
	def age
		19
	end
}

puts name.age

#Looks familiar to what we've already seen about anonymous classes, doens't it? How about using instance_eval inside a class:

class Something
	instance_eval %{
		def hello
			'hi'
		end
	}
end

puts Something.hello

We can conclude that instance_eval deals with the object’s anonymous class, so when you’re adding methods to an instance_eval, you’re indirectly injecting methods to that class. This happens because Ruby keeps in memory the concept of a current class, and instance_eval sets the current class to the object’s ghost class. So defining methods with instance_eval on an object is the same as using the syntax def object.method_name, whilst defining methods with instance_eval on a class is the same as defining ‘class’ methods.

Class_eval, on the contrary, can only be used in class objects (not instances!):

#We can do anything we want with a class, such as defining instance methods that will be available to ALL its instances

class Hi
end

Hi.class_eval %Q! 
	def say_hi
		puts 'hello'
	end
!

example = Hi.new
other = Hi.new

example.say_hi
other.say_hi

The difference here is that class_eval sets the current class to its receiver, which is an explicit class, so all methods you add are going to that class. Class_eval is the same as opening the class again and adding methods to it.

Just for fun, let’s mess with an anonymous class and use class_eval on it, then instance_eval on its instance.

name = "Pedro"

class << name
	class_eval do
		def age
			19
		end
	end
end

puts name.age

name.instance_eval do
	def age
		20
	end
end

puts name.age

Is that cool or what? We’re using class_eval inside the object’s anonymous class by doing class <<, so the current class was set to the anonymous class and we were able to overwrite the age method. Using this line of thought we could even go further and write our own instance_eval (in the case of method definition):

class Object
	def custom_instance_eval(str)
		parent = class << self; self ; end
		parent.class_eval str
	end
end

name = "Pedro"

name.custom_instance_eval %Q!
	def age
		19
	end
!

puts name.age

Notice I had to return the anonymous class object instead of using class_eval inside it like we did before because I’m passing a parameter, so the program would blow up because that parameter doesn’t exist in the scope of the anonymous class, so I did a workaround by calling class_eval on an object containing the anonymous class to avoid that.

Let’s do another exercise, this time we’ll write our own attr_accessor, which gives any class the ability to automatically add a getter and a setter to a given variable in it:

#We'll use a module to which we can extend from so we can add our accessor to any class we like.
module Custom
	protected
	def custom_accessor(var)
		class_eval %Q!
			def #{var}
				@#{var}
			end
			
			def #{var}=(value)
				@#{var} = value
			end
		!
	end
end

#There, we defined our getter first by returning the instance variable with the name passed to the accesor, and then the setter with a value parameter that will get set to the instance variable.

#Now we extend our module so its methods will be available to us as class methods. Notice our accessor will be a class method but is protected, so it will not be accessible from outside the class, such as a call like Hi.custom_accessor :var
class Hi
	extend Custom
	custom_accessor :msg
end

hi = Hi.new
hi.msg = "hello"
puts hi.msg

We chose class_eval instead of instance_eval because we’re calling our accessor inside a class so every instance of it will have the methods, and we learned that instance_eval does not go inside class definitions.

To finish up, let’s put some metaprogramming into practice. We’ll be using 2 metaprogramming techniques to achieve the same goal, which will be to grab a method that returns a string and change that method at runtime so it will return an uppercase string.

First, let’s use an object’s ghost class as a support to hold the method redefinition:

# First interface:
# The method should be used in any object, taking that object as a parameter and the method name that should be changed
# Example: transform(object_instance, method_name)
# This way method_name will be altered for object_instance for its lifetime.

def big(obj, meth)
	anon = class << obj; self; end;
	anon.class_eval %Q!
	def #{meth}
		super.upcase
	end
	!
end

class Person
	def name
		"pedro"
	end
end

me = Person.new

puts me.name

big(me, :name)

puts me.name
puts me.name

other = Person.new

puts other.name

This seems quite familiar with what we did by creating our custom instance_eval because we’re using class_eval on an anonymous class object , but things here are different in the sense that we’re using that anonymous class to hold the new ‘name’ method so the object will first ask it when calling ‘name’. As we’ve discussed before, the anonymous class is right in the spot between an object and it’s class, so it comes first than the object’s class in the method invokation chain, therefore being able to respond to a method before the actual class. The consequence of all this is that after we redefine ‘name’, the specific object we passed to the modifying method ‘big’ will no longer ask class Person for the ‘name’ method because the anonymous class is already holding a copy of it. In the terms of the code presented, me.name will always return the uppercase version of whatever string defined in the original name method.

“Aren’t we doing too much for a simple task?” – You ask. In this case, yes, but the problem doesn’t really matter, I decided to keep things simple such as turning a string uppercase to focus on how we’re doing the metaprogramming, but you can apply the same line of thought for way larger problems as well.

Now let’s take a look at another metaprogramming practice called method rewriting. With the help of modules for better encapsulation, we’ll rewrite the method we’re passed with at runtime to do whatever we want instead of creating another version of it somewhere else:

# Second interface:
# The method should be used in any class that extends its module, taking only the method name as a parameter
# Example: transform :method_name
# This way every instance of the class that extends the modifying module and calls the modifying method with a :method_name will have the method named method_name changed permanantly.

module TurnBig
	def big(method)
		alias_method("old_#{method}", method)
		
		define_method(method) { send("old_#{method}").upcase }
	end
end

class Person
	extend TurnBig
	
	def name
		"pedro"
	end
	
	big :name
end

me = Person.new

puts me.name

Alias_method simply gives a method another name, which in our case is the same name with ‘old_’ in front of it. We need that other name because we’re redefining the same method, so if we used the same name then the program would loop forever when we called that method. Notice we used define_method here which is another way of defining methods in a class context, and send, which invokes a method by its name that can be in a string, variable, symbol, etc. In the code, we’re redefining ‘name’ by getting the result of ‘old_name’ and uppercasing it, and since we’re doing it all inside a module that can be extended, it’ll work for any class.

And that about wraps it up! We saw the basics of the Ruby object model along with some techniques on metaprogramming. If you’re still unfamiliar with metaprogramming, I suggest you write down some code using it. There is no better way to learn programming than to program yourself. Feel free to post any questions and I’ll try my best to answer them. Hope you learned something, see ya!