Rails Plugins: Metaprogramming vs Generators
0
One of the most powerful features of Rails is plugins; plugins enable developers to make generic extensions to Rails applications that others can benifit from. One can use two different approaches to add new logic/aspects to a Rails application through a plugin: metaprogramming and generators. This entry is not a tutorial about writing Rails plugins; assuming that you know the basics of metaprogramming in Ruby, and using a very basic example, we'll try to conduct a simple comparison between the two approaches that can be generalized.
Assume that your plugin relies on adding some logic as a before_filter to all controllers. You have that logic in a module that you want to mix in ApplicationController, and also you want to declare that filter. Using the first approach, Ruby metaprogramming, you can apply virtually any changes to the existing classes, modules, and even objects. The following two lines can help in our example:
ApplicationController.class_eval "include MyModule" ApplicationController.class_eval "before_filter :my_filter"
Basically, what we have just done is that we told the interpreter to dynamically evaluate those two lines in the context of the ApplicationController. Those two lines are NOT lexically added to the definition of the class. It's like they're added at runtime.
Another approach we could use is a Rails generator. A generator, in a nutshell, lexically adds generated code to the existing files. We could do the same job in the example using a generator as follows:
class MyGenerator < Rails::Generator::Base
def manifest
record do |m|
m.gsub_file 'app/controllers/application.rb', /(#{Regexp.escape("class ApplicationController < ActionController::Base")})/mi do |match|
"#{match}\n include MyModule\n before_filter :my_filter\n"
end
end
end
end
Basically, what we have just done is that we searched for the line class ApplicationController < ActionController::Base and lexically added the two lines next to it. Of course, this generator has to be run to apply its changes.
ruby script/generate my_generator
The tradeoff between generating and metaprogramming is simply the tradeoff between being mixed but explicit and being isolated but subtle. Generation may result in mixing some logic, but has the major advantage of being explicit. The resulting code is explicitly added to the project files and can even be modified by the developer using the plugin. Metaprogramming forces separation of concerns, but is done in a subtle way that could lead to time being wasted by the developer in investigating what happened behind the scenes.
Of course, there are situations where only generation can be used, like adding migrations, routes and other stuff. Take a look at the features Rails generators give.
Rails/Generator/Commands/Base
Rails/Generator/Commands/Create
Rails/Generator/Commands/Destroy
Post a Comment
eSpace podcast Prodcast
Archive
- August 2010
- July 2010
- June 2010
- April 2010
- March 2010
- November 2009
- October 2009
- September 2009
- July 2009
- June 2009
- May 2009
- April 2009
- March 2009
- February 2009
- January 2009
- November 2008
- October 2008
- September 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- January 2008
- April 2007
- March 2007
Latest Comments
- SpectraMind Commented on Egypt Wins UK's National Outsourcing Association Award
- Rofaida Awad Commented on Go Egypt Go!
- Different Mike Commented on Only idiots change their iPhone root password!
- Mike Commented on Only idiots change their iPhone root password!
- smile Commented on Only idiots change their iPhone root password!

