Hi all,
I came across a technique for aliasing methods that I have never seen
before [1] and was just too good to pass up. But first, the setup.
If you want to redefine a method of an existing class, the traditional
approach is to alias the method first, then call the alias as needed.
For example, if you want to redefine Hash#[]= so that it stores
multiple values as a list instead of overwriting the existing value you
might do this:
class Hash
alias :old_hset :[]=
def []=(key, value)
if self[key]
self[key] << value
else
self.old_hset(key, [value])
end
end
end
hash = {}
hash[‘a’] = 1
hash[‘a’] = 2
hash[‘a’] # [1,2]
That works well enough. But, it’s not ideal. Why? First, because now
you’ve got an aliased method laying around that we really don’t want
exposed to the public. Second, this could cause a problem if anyone
were to ever define an old_hset method or alias themselves. Unlikely,
but possible.
The solution that Martin came up with is to use an UnboundMethod like
so:
class Hash
hset = self.instance_method(:[]=)
define_method(:[]=) do |key, value|
if self[key]
self[key] << value
else
hset.bind(self).call(key, [value])
end
end
end
So, now our custom Hash#[]= method is bound to an UnboundMethod that no
one else has access to (see the first link below for a better
explanation). Pretty neat, eh? Is there any downside to this approach?
If not, it seems this technique ought to be filed under ‘best
practices’, and perhaps even abstracted somehow in the core itself.
Many thanks to Jay Fields [2], whose blog entry led me back to the
original entry by Martin Traverso.
Regards,
Dan
[1] split-s: Replacing methods
[2]
Jay Fields' Thoughts: Ruby: Alias method alternative