coderrr

November 30, 2008

Overloading the parenthesis operator in Ruby

Filed under: ruby — Tags: — coderrr @ 5:31 pm

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

1 Comment »

  1. [...] 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


RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.