Copyright © 2004–2010 OpenSourcery, LLC. This work is licensed under a Creative Commons Attribution 3.0 United States License.
In a Rails project we're currently developing, I ran into an odd failure while running rake:
$ rake gems:unpack (in /home/hobson/railsproject) rake aborted! undefined method `[]' for :sourdough:Symbol /home/hobson/railsproject/lib/tasks/import.rake:113:in `method_missing' ...
Why does this trace end in a totally unrelated rakefile? A look at the source of this file provided a simple explanation: in order to break up the logic of a complicated Rake task, someone had defined a large number of constants and utility methods (including method_missing!) without a surrounding class or module namespace. Other Rake tasks were accidentally triggering this method_missing implementation because it was defined at the top level. This is why it's never a good idea to define methods in the top level of any Ruby file that might be included as part of a larger system. The solution is to wrap the methods in a module, and include that module in the task namespace:
module ImportUtil # you can define any method you want here, including method_missing. end namespace :import do include ImportUtil task :something do # you can now call everything defined in ImportUtil as a top level method end end
This avoids poisoning the top level of your Ruby environment with Rake utility methods. The lesson here is that since Ruby makes it so easy to include modules at any level, it's almost never necessary to define a method at the top level. Especially not method_missing.
UPDATE: Whoops, it turns out the solution I proposed above does not work. Since rake "namespaces" are really just blocks executed at the same level at which they're declared, the module include causes the methods to be included into the top level anyway. While the final lesson of this post remains true, the only solution I'd recommend (and the one we eventually took with the code above) is to remove the offending code completely, and don't ever define method_missing (or any other method, if you can help it) at the top level.
Tagged as: Rake, Ruby, Ruby on Rails