Advanced Rails - Building Industrial-Strength Web Apps in Record Time

(Tuis.) #1
Metaprogramming Techniques | 31

def age
Time.now - self[:initialized_at]
end
end

settings = Settings.new :use_foo_bar => true

# Method calls are delegated to the object
settings[:use_foo_bar] # => true
settings.age # => 5.000301

TheSettingsconstructor callssuperto set the delegated object to a new hash. Note
the difference between composition and inheritance: if we had inherited fromHash,
thenSettingswouldbea hash; in this case,Settingshasa hash and delegates to it.
This composition relationship offers increased flexibility, especially when the object
to be delegated to may change (a function provided bySimpleDelegator).


The Ruby standard library also includesForwardable, which provides a simple inter-
face by which individual methods, rather than all undefined methods, can be dele-
gated to another object. ActiveSupport in Rails provides similar functionality with a
cleaner API throughModule#delegate:


class User < ActiveRecord::Base
belongs_to :person

delegate :first_name, :last_name, :phone, :to => :person
end

Monkeypatching


In Ruby, all classes are open. Any object or class is fair game to be modified at any
time. This gives many opportunities for extending or overriding existing functionality.
This extension can be done very cleanly, without modifying the original definitions.


Rails takes advantage of Ruby’s open class system extensively. Opening classes and
adding code is referred to asmonkeypatching(a term from the Python community).
Though it sounds derogatory, this term is used in a decidedly positive light; monkey-
patching is, on the whole, seen as an incredibly useful technique. Almost all Rails
plugins monkeypatch the Rails core in some way or another.


Disadvantages of monkeypatching


There are two primary disadvantages to monkeypatching. First, the code for one
method call may be spread over several files. The foremost example of this is in
ActionController’sprocessmethod. This method is intercepted by methods in up to
five different files during the course of a request. Each of these methods adds another
feature: filters, exception rescue, components, and session management. The end
result is a net gain: the benefit gained by separating each functional component into
a separate file outweighs the inflated call stack.

Free download pdf