Ruby on Steroids: The Magic of MetaProgramming – An Unexpected Journey
We have all been hearing about metaprogramming. Metaprogramming is one of those words that seems to exist purely to scare people. Are we talking about programming beyond programming? Xtreme Programming in the Dojo? Programming made for ruby ninjas use, and that it simply isn’t for common mortals? Programming in the next dimension?. But the truth is that metaprogramming isn’t something scary at all. In fact, metaprogramming—at least as it is practiced in the Ruby world—is a very workman set of coding techniques that allow you to get the results you need with less code.
What is MetaProgramming
Metaprogramming is a technique by which you can write code that writes code by itself dynamically at runtime. This means you can define methods and classes during runtime. Crazy, right? In a nutshell, using metaprogramming you can reopen and modify classes, catch methods that don’t exist and create them on the fly, create code that is DRY by avoiding repetitions, and more.
Magic Spells
Throughout this journey, we are going to be learning a lot of ruby spells that makes it possible to practice magic(metaprogramming). Let’s begin this journey by learning some of the fundamental spells.
1. eval
Evaluates the Ruby expression(s) in string. Ruby’s eval
takes in a string as the argument, which means that it is possible for one to accept user input or read code off of a file and get it evaluated from within your program – essentially re-programming the way your program behaves.
1 2 3 |
eval("5 + 10") #=> 15 eval("def name; 'Ikem Okonkwo'; end;") # creates a method called name name #=> "Ikem Okonkwo" calls the method created by eval |
2. instance_eval
Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (object). What this means is that if you create a method using instance_eval in the body of a class, that method will be a class method. However, if you create a method with instance_eval in the body of an instance method, that method will become a singleton method of the object created from the class as soon as the method that has the instance_eval has been invoked. instance_eval
cannot be used to create normal instance methods in class. It can only be used to create class methods and singleton methods. 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class Person c = %q{def company; "Andela"; end} instance_eval(c) def initialize @name = "Ikem Okonkwo" end def make instance_eval("def name; 'Ikem Okonkwo'; end") end end p = Person.new p.name #=> undefined method error p.make p.name #=> "Ikem Okonkwo" p.company #=> undefined method error Person.company #=> "Andela |
3. class_eval (aka: module_eval)
The module_eval
and class_eval
methods operate on modules and classes rather than on objects. The class_eval
is defined as an alias of module_eval
. They are used to add normal instance methods to a class. class_eval
method is not available in an instance of a class.
1 2 3 4 5 6 7 |
class Person name = %q{def name; "Ikem Okonkwo"; end} class_eval(name) end Person.name #=> undefined method error Person.new.name #=> "Ikem Okonkwo" |
4. class_variable_get & class_variable_set
class_variable_get
method is used to retrieve the value of a class variable while class_variable_set
updates the value of a class variable with a new value. Both method are only available to class objects.
1 2 3 4 5 6 7 8 |
class Person @@name = "codesword" end Person.class_variable_get(:@@name) #=> "codesword" Person.class_variable_set(:@@name, "Ikem") Person.class_variable_get(:@@name) #=> "Ikem" Person.new.class_variable_get("@@name") #=> undefined method |
5. instance_variable_get & instance_variable_set
instance_variable_get
method is used to retrieve the value of an instance variable while instance_variable_set
updates the value of an instance variable with a new value.
1 2 3 4 5 6 7 8 9 |
class Person @book = "Harry Porter" def initialize @book = "The Rails Way" end end Person.instance_variable_get(:@book) #=> "Harry Porter" Person.new.instance_variable_get(:@book) #=> "The Rails Way" |
Conclusion
We have seen some of the few spells you can cast using metaprogramming in this blog post. Why exactly should you care about metaprogramming? Well it is because 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 2 of this journey, we will explore more spells you can cast using metaprogramming in ruby. Subsequent blog posts tagged with Ruby on Steriods
will also be talking about metaprogramming in one form or the other. So expect blog posts on DSL(external & internal), Hooks, Use cases for metaprogramming etc.

- Ruby on Steroids(DSLs): The Powerful Spell Called DSL - March 14, 2016
- Ruby on Steroids: The Magic of MetaProgramming – Method Spells - March 12, 2016
- Ruby on Steroids: The Magic of MetaProgramming – Fellowship of Spells - February 28, 2016
- Ruby on Steroids: The Magic of MetaProgramming – An Unexpected Journey - February 27, 2016
- How to Delegate Like a Boss - February 24, 2016
- Better Routing – Part 4 - January 28, 2016
- Autoloading and Utility Methods – Part 3 - January 11, 2016
- Set up a Basic MVC Framework – Part 2 - December 22, 2015
- Rack Deep Dive – Part 1 - December 17, 2015