La Búsqueda por Métodos de Instancia

Cuando Ruby evalúa una expresión de invocación de un método (este proceso es conocido como method lookup o method resolution), por ejemplo o.m ocurren los siguientes pasos:

  1. Primero comprueba en la singleton class o eigenclass de o la existencia de un método m

  2. Si no, busca en la clase de o por un método m

  3. Si no, busca en los módulos incluídos por la clase de o. Si la clase incluye mas de un módulo se buscan en orden inverso al orden en el que fueron incluídos

  4. Si no, se mueve hacia arriba en la clase de herencia a la superclase. Los pasos 2 y 3 se repiten para cada clase en la jerarquía de herencia hasta que todos los antecesores y módulos incluídos han sido buscados.

  5. Si no, se invoca a un método con nombre method_missing. Para encontrar dicho método se empieza en el paso 1.

    El módulo Kernel provee una implementación por defecto de method_missing por lo que queda garantizado el éxito de esta segunda pasada.

Let’s consider a concrete example of this algorithm. Suppose we have the following code:

  message = "hello" 
  message.world
We want to invoke a method named world on the String instance "hello".
[1] pry(main)> String.ancestors
=> [String, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]
Name resolution proceeds as follows:
  1. Check the eigenclass for singleton methods. There aren’t any in this case.
  2. Check the String class. There is no instance method named world.
  3. Check the Comparable module of the String class for an instance method named world.
  4. Check the superclass of String, which is Object. The Object class does not define a method named world, either.
  5. Check the Kernel module included by Object. The world method is not found here either, so we now switch to looking for a method named method_missing.
  6. Look for method_missing in each of the spots above:
    1. the eigenclass of the String object,
    2. the String class,
    3. the Comparable module,
    4. the Object class, and the Kernel module
    The first definition of method_missing we find is in the Kernel module, so this is the method we invoke. What it does is raise an exception:
    NoMethodError: undefined method `world' for "hello":String
    
This may seem like it requires Ruby to perform an exhaustive search every time it invokes a method.

In typical implementations, however, successful method lookups will be cached so that subsequent lookups of the same name (with no intervening method definitions) will be very quick.

Casiano Rodriguez León 2015-06-18