Last time I discussed Ruby and metaprogramming, I was trying to stay DRY (Don’t Repeat Yourself) while coding some very similar-looking methods. The solution, then was to use class_eval to dynamically add methods into the current class, the way attr_accessor and it’s peers already do.
Today I was having a similar, yet more difficult problem: the architecture of my app includes two controllers: IncomeController and ExpenseController, two identical twins, each saving, updating and listing it’s associated models (Income/Expense), where Income has_many income_attributes and.. you guessed it, Expense has_many expense_attributes. And the list can go on, since they have some more relationships, all of them being identical but for the names and associations.
I know, perhaps such thing might have been avoided if, in the first place, we would have used single-table inheritance and such. But for various reasons we didn’t, and I was getting tired of keeping in sync all the changes in Income* to Expense* and vice-versa.
So.. what could the solution be? Namely, I wanted both IncomeController and ExpenseController to share the same codebase, the only difference being the names; I wanted a… replace_all to be run on the fly.
Luckily for me, I remembered Camping, a Ruby Microframework for web apps(kinda like Rails, but more simplistic), which uses some intense metaprogramming-kung-fu to keep its code to less than 4kb. For instance, in the homepage example, we see that
A skeletal Camping blog could look like this:
require ‘camping’
Camping.goes :Blog
The .goes method returns a class duplicate of the Camping one, where all occurences of Camping have been changed with Blog.
(more…)