Search code examples
rubymetaprogrammingmethod-missing

Metaprogramming: method_missing and __send__


I've found an oddness in Ruby. Using method_missing/respond_to_missing? to dynamically handle method calls initiated via __send__ fails when Kernel defines the same method:

class Testerize

  def method_missing(method, *args, &block)
    if method == :system
      puts 'yay'
    else
      super
    end
  end

  def respond_to_missing?(method, internal)
    return true if method == :system
  end

end

t = Testerize.new
puts t.respond_to?(:system)
# Prints true
t.system
# Prints 'yay'
t.__send__(:system)
# Exception: wrong number of arguments (ArgumentError)

Kernel.system is somehow getting in the mix. Does anyone know what's going on here? I would have expected the :system "message" to get posted to the Testerize instance, hit method_missing, and voila. Why isn't my method_missing getting called when using __send__ when it is with direct invocation?

I'm using Ruby 1.9.3, if that is relevant.


Solution

  • with '__send__' or 'send' we can even call private methods of the object.
    

    In your script do:

    t.private_methods.grep /system/
    

    You will see system method, while with

    t.methods.grep /system/
    

    you will see an empty array.

    __send__ tries to call the private method inherited from Kernel in the inheritance chain, hence instead of using __send__ use Ruby's public_send method.