Ruby supports overloading the [] operator but not (). Here is a little hack to get “parenthesis operator overloading” on modules and classes.
class Object
alias_method :orig_method_missing, :method_missing
def method_missing(m, *a, &b)
klass = begin
(self.is_a?(Module) ? self : self.class).const_get(m)
rescue NameError
end
return klass.send(:parens, *a, &b) if klass.respond_to? :parens
orig_method_missing m, *a, &b
end
end
Now you can do fun and crazy things like default initialization arguments for a class
class X
def initialize(arg1, arg2, arg3); ... ; end
def self.parens(*args)
Class.new(self).class_eval do
define_method :initialize do
super(*args)
end
self
end
end
end
class Y < X(1, 2, 3)
end
But since we use const_get to resolve the constant, lexical scope won’t be taken into account. Meaning the following example wouldn’t work where you might expect it to.
module M
class X
def self.parens(); ...; end
end
class Y
# would raise NoMethodError
class Z < X(); ... ;end
# but this would work
class Z < X; ...; end
end
end
This is because when trying to resolve the method X() we call Y.const_get(:X). This only looks through Y’s ancestors’ constants. M is not an ancestor of Y. But when we try to resolve the constant X from the same location we find it in the lexically enclosing module M. See this post for more info on constant lookup.
For more info you can check out the tests here. For even nastier hax, check out calling a lambda with parenthesis

[...] Overloading the parenthesis operator in Ruby – One of those things I hope never to have a need to do. I’m a full-time Rails developer and contributor, available for long- or short-term consulting, with solid experience in working as part of a distributed team. If you’d like to hire me, drop me a line. Links [...]
Pingback by Double Shot #342 « A Fresh Cup — December 1, 2008 @ 11:53 am