This page lists metaprogramming techniques in Ruby, how they are used in Rails, and what their equivalent is in JavaScript (if any).
greeting = "Hello" bob = "Bob" def greeting.say_twice puts self puts self end greeting.say_twice # This will print "Hello" twice bob.say_twice # This will throw a NoMethodError
Rails uses this technique in its DRb (Distributed Ruby -- one of the several options for storing session information) server setup for ActionController. With this technique, access to the session_hash is synchronized. They use the alternate syntax of 'class <<obj' since they are adding several methods to the class at once. Here is an excerpt:
session_hash.instance_eval { @mutex = Mutex.new } class <<session_hash def []=(key, value) @mutex.synchronize do super(key, value) end # More methods ommited end end
Eval is the most basic. Also, it is probably the most powerful and the most dangerous. Probably for this reason, it does not seem to be used much in Rails.
The other 3 eval methods are more often used. They differ from the basic eval method in that they can also accept blocks of code, meaning that they can be used with much less risk.
The main purpose for instance_eval() is to gain access to the private members of another class. The class_eval()/module_eval() methods are designed to add to the functionality of a class or module and to include variables from the current scope. Together, all 3 of these serve to allow the programmer to inject functionality into another class.
Ruby has a variety of methods that help in defining methods on the fly. I had already talked about define_method and alias_method. These can be used to create a wrapper around a class. In addition, this seems to be used to change the functionality of a method. For example, ActionController uses this to change which method is really executed when page.render() is called.
Proc, block, and lambda are collectively referred to as 'callable objects'. All three are variations of the same idea -- they are ways to define temporary pieces of executable code. Javascript can already create anonymous functions, so there is little that it is missing.
Ruby has a 'method' method that returns a reference to the specified method. This is mostly needed because of the blurred line between properties and methods. (JavaScript does not have this issue. 'music.method(:play)' in Ruby would translate to just 'music.play' in JS.) Often used along with 'method' are the 'bind' and 'unbind' methods. Together, these can be used to allow method references to be moved around between objects. The need for this is unclear, and Rails seems to make little use of this. In fact, in his discussion of this, David Black suggests that if you are using this, you probably have a design problem. (Ruby for Rails, p. 358).
Ruby has several different points where a programmer can hook in to the application. They are:
Of these, const_missing is used the least. It does not seem to be particularly important.
I've covered method_missing extensively before. It is often used for creating shortcuts -- it seems to be the primary spoon for serving syntactic sugar. Nonetheless, it really does not seem to offer many impressive leaps in what you can do.
The included and inherited methods seem to be the core of Ruby metaprogramming, at least for how it is used in Rails. This is used heavily in ActiveRecord and even more so in ActionController. Here is an example from the base ActionController class:
module Layout def self.included(base) base.extend(ClassMethods) base.class_eval do alias_method :render_with_no_layout, :render alias_method :render, :render_with_a_layout class << self alias_method :inherited_without_layout, :inherited alias_method :inherited, :inherited_with_layout end end end # ... Rest ommited
When the Layout module is included, it rewires the render method of the host object so that it will use the layout. It also changes the behavior of the inherited method.