Ruby’s open classes and modules, along with alias_method
, make it really easy
to add functionality to existing methods. Take this example from my plugin
AttrLocked:
class ActionView::Helpers::InstanceTag
def tag_with_attribute_locking(name, options = nil)
options = (options || {}).update("disabled" => attribute_locked?)
tag_without_attribute_locking(name, options)
end
alias_method(:tag_without_attribute_locking, :tag)
alias_method(:tag, :tag_with_attribute_locking)
end
All that does is intercept any calls to InstanceTag#tag
and add on an option
to disable the form field if required. The original tag
method is copied to
tag_without_attribute_locking
, then tag
is re-aliased to call your
interception.
(If you are using Rails 1.2 or later, you can use alias_method_chain(:tag,
:attribute_locking)
in place of the two alias_method
calls. I use
alias_method
in my plugins for backwards compatibility.)
JavaScript has open objects too, and it allows you to reference methods using strings, and it lets you pass functions around like regular variables. So, you could write this:
function intercept(object, method, chain, interception) {
object[method + '_without_' + chain] = object[method];
object[method] = interception;
}
which then lets you intercept any method on an object. Let’s say I want to log
every call to Event.observe
:
intercept(Event, 'observe', 'logging', function(element, ... ) {
console.log('Event.observe: ' + element);
Event.observe_without_logging(element, ... );
});
This works great for extending third-party libraries you’re using if you can’t/don’t want to modify their source code.