I bought Metaprogramming Ruby by Paolo Perrotta because although I’ve been writing Ruby code—for fun, not for a living—on and off for about five years, I still feel that I’ve barely scratched the surface in many ways. In particular, in order to feel like I really got Ruby I wanted a deeper understanding of how its object model worked and I wanted to properly learn about some of the metaprogramming techniques I’d seen in others' code. To quote the book’s tag line, I wanted to “program like the Ruby pros”.
The book weighs in at an easily manageable 250 pages and is split into two main parts, plus four appendices. The first part forms the bulk of the text and is itself split into five sections, collectively themed around exploring a different aspect of metaprogramming Ruby on each day with a fictional mentor named Bill. One of the things I like about this book is that for the first time it draws this material together in one place, where previously it has been scattered across various different books and blog posts.
On Monday Bill takes you on a tour of Ruby’s object model, Tuesday is spent looking at methods, Wednesday covers Ruby’s blocks, Thursday looks at class definitions and finally Friday is about code that writes code. Sprinkled throughout are little quizzes designed to test your knowledge of what you’ve just learned.
I first became aware of the Ruby object model and the fact that it’s a rather unusual and interesting study during Dave Thomas’s excellent talk on the subject at Scotland on Rails 2009. Chapter one is devoted to the subject, which is fortunate because mastering it is the key to becoming a Ruby metaprogramming master. The object model is revisited in later chapters, for example, Ruby’s idiosyncratic eigenclasses—literally “one’s own class”—are introduced in Thursday’s lesson on class definitions.
Like the seminal Gang of Four design patterns book, part of the mission for Metaprogramming Ruby is to give canonical names to previously anonymous patterns of code, something I think it succeeds in. The term spells is used instead of idiom or pattern, the spells having names such as “Context Probe”, “Scope Gate” and “String of Code”. Where spells appear in the text they are cross-referenced with Appendix C, this being a spell book that lists all the spells and gives short code samples. I found this format handy.
The second part of the book uses Ruby on Rails as a metaprogramming case study and examines in some detail how apparently magic features such as ActiveRecord’s dynamic attributes and dynamic finders are actually implemented. Using Rails for this section was a smart move given that it’s something that most Ruby programmers are likely to be at least somewhat familiar with and also that it’s the poster child for Ruby metaprogramming. Plus the Rails 2.x source code is pretty impenetrable and intimidating without any sort of orientation or guide. Copious extracts from the Rails source are included, but in abridged form where including the code verbatim would distract from the point being made.
Following a dissection of the design of ActiveRecord, the author presents some lessons he learned during the process. He makes the point that coming from a Java background he was initially horrified when confronted with a single huge logical class consisting of hundreds of methods that are actually implemented as a set of modules that modify their including class. However, I wasn’t entirely convinced by Paolo’s arguments that ActiveRecord 2.x isn’t a tangled mess of (admittedly high-quality) spaghetti code. Clearly the Rails core team felt similarly otherwise Rails 3 wouldn’t have seen such a substantial rewrite of its internals that did away with tricks such as alias_method_chain.
It’s ironic and slightly unfortunate for this book that Rails 3 has a rather more straightforward implementation that’s less reliant on advanced metaprogramming. It would be nice to see a future edition updated with extracts of the more readable later code. However, I don’t think it’s too big a negative, as the second half of Metaprogramming Ruby is really about putting the spells into a real world context and showing how they can be used to solve problems in combination; an aim that’s successfully achieved in spite of the specific examples being largely obsolete already.
All in all I enjoyed my first read through of Metaprogramming Ruby and I learned a lot. Am I now a Ruby metaprogramming master? I don’t think so. I found some of the ideas presented difficult to grasp easily, which is why I need to read it again, but this time with irb and Vim to hand. I don’t think this is a book that you’d read once and then put away, rather it will reward further study. Fortunately its easy reading style and length are just right to make this an enjoyable prospect.