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
Get NeverBlock Enabled in Your Application!
Are your applications memory starved? Are many of your visitors waiting in line while the servers are busy serving others? It doesn't have to be that way if you are running a Ruby application - eSpace's NeverBlock can give you the boost you need!.Archive
Latest Comments
- johnstevens Commented on PostgreSQL: An ultimate strategy for full text search
- Lucian Commented on Redmine: A Software Project Management Solution
- Dete Ctive Commented on FCKEditor and Radiant: Adjusting the Link Target According to Link Type
- chimere Commented on Thinking Sphinx on Windows
- Tamer Salama Commented on eSpace is One of the ASTF's 10 Startups Ready For Investment

