Everyone Should Learn Metaprogramming
A few weeks ago was the first Steel City Ruby conference. It was a great conference and I would highly recommend you attend next year. While there, I had the opportunity to give my first lightning talk.
Now I’m not one for public speaking, in fact it’s terrifying for me. However, the Ruby community is awesome, friendly, and very encouraging. After thinking about it for a while, talking with several people, and reflecting on my time participating in Scrappy Academy, I decided that it was important to speak up about metaprogramming.
I titled my talk: ”Demystifying Metaprogramming.” The intent was to encourage those people who are afraid of “metaprogramming” to give it a try. I strongly believe if you have been programming Ruby (or Rails - this is just Ruby with a fun web framework) for more than two months, you owe it to yourself to learn metaprogramming.
To most people, this included me, they hear about “metaprogramming” as this advanced technique that should be avoided by all but the most wizardly among us. Frankly, this big scary stigma attached to metaprogramming just isn’t warranted.
I’ll let you in on the big secret, “metaprogramming” is just programming. Yep. It’s not scary. It may be a bit complicated, but at the end of the day it is well worth your time to learn. You may even find it to be fun.
To help ease you into the topic, we’ll start with a simple contrived example to demonstrate that you already know everything needed to get started.
1 2 3 |
|
Yep. That’s a really basic method. It simply puts
the object that is
passed in. To use this method in irb
or pry we could simply:
1 2 3 4 5 6 7 |
|
This shouldn’t be anything shocking so far. In fact, all we’ve done is
create a method that calls a method (puts
) and pass it a parameter. In
fact, this concept is at the heart of the “meta” programming.
All you really are doing is writing methods, that call another method, and pass it a parameter. It just so happens that the parameter you pass, tends to be a block that defines a new method.
Write a method, that calls a method, that creates a method.*
So to extend our example and add the “meta” part to it, we’ll just:
- Wrap our method in another method
- Pass our method as the parameter to another method
1 2 3 4 5 6 7 |
|
In this case, we’re using the special class_eval
method. In a nutshell, this will change the value of self
and then
execute the block in this context. In our case, we provide it a block
which contains the method definition we wish to dynmically create. The
trick here is that class definitions and methods are active code. So the
call to def say( phrase )
is run just as if we had typed it directly
in the original class definition.
To be able to use this in a context more familiar, we’ll just wrap this
in a module. We can then extend
that module in our class and
dynamically create our method by using our class method
just_programming
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
I hope this has helped illustrate that “metaprogramming” is only programming. It isn’t anything to be afraid of. Sure, it can get complicated at times, but then, what code concepts beyond the bare basics can’t?
You owe it to yourself to learn these nifty and fun coding techniques. They will demystify manly things you think are “magic”, provide a deeper understanding of the Ruby language, and add tools to your belt enabling you to write better code.
There are many resources on these topics if you do a search. Additionally, The Pragmatic Bookshelf has a good set of resources on Ruby and metaprogramming. I found the videos series on The Ruby Object Model and Metaprogramming very enlightening.
Happy programming!
* Technically, this should really be “Write a method, that sends a message, that creates a method.” However, I wanted to emphasise the progression and went with this version.