How do I use Ruby metaprogramming to refactor this common code?
Posted
by James Wenton
on Stack Overflow
See other posts from Stack Overflow
or by James Wenton
Published on 2010-04-23T05:57:58Z
Indexed on
2010/04/23
6:03 UTC
Read the original article
Hit count: 221
I inherited a project with a lot of badly-written Rake tasks that I need to clean up a bit. Because the Rakefiles are enormous and often prone to bizarre nonsensical dependencies, I'm simplifying and isolating things a bit by refactoring everything to classes.
Specifically, that pattern is the following:
namespace :foobar do
desc "Frozz the foobar."
task :frozzify do
unless Rake.application.lookup('_frozzify')
require 'tasks/foobar'
Foobar.new.frozzify
end
Rake.application['_frozzify'].invoke
end
# Above pattern repeats many times.
end
# Several namespaces, each with tasks that follow this pattern.
In tasks/foobar.rb
, I have something that looks like this:
class Foobar
def frozzify()
# The real work happens here.
end
# ... Other tasks also in the :foobar namespace.
end
For me, this is great, because it allows me to separate the task dependencies from each other and to move them to another location entirely, and I've been able to drastically simplify things and isolate the dependencies. The Rakefile doesn't hit a require
until you actually try to run a task. Previously this was causing serious issues because you couldn't even list the tasks without it blowing up.
My problem is that I'm repeating this idiom very frequently. Notice the following patterns:
For every namespace
:xyz_abc
, there is a corresponding class intasks/...
in the filetasks/[namespace].rb
, with a class name that looks likeXyzAbc
.For every task in a particular namespace, there is an identically named method in the associated namespace class. For example, if namespace
:foo_bar
has a task:apples
, you would expect to seedef apples() ...
inside theFooBar
class, which itself is intasks/foo_bar.rb
.Every task
:t
defines a "meta-task"_t
(that is, the task name prefixed with an underscore) which is used to do the actual work.
I still want to be able to specify a desc
-description for the tasks I define, and that will be different for each task. And, of course, I have a small number of tasks that don't follow the above pattern at all, so I'll be specifying those manually in my Rakefile.
I'm sure that this can be refactored in some way so that I don't have to keep repeating the same idiom over and over, but I lack the experience to see how it could be done. Can someone give me an assist?
© Stack Overflow or respective owner