Buscar..


Introducción

En el diseño orientado a objetos, los objetos reciben mensajes y responden a ellos. En Ruby, enviar un mensaje está llamando a un método y el resultado de ese método es la respuesta.

En Ruby el paso de mensajes es dinámico. Cuando llega un mensaje en lugar de saber exactamente cómo responder, Ruby usa un conjunto predefinido de reglas para encontrar un método que pueda responderle. Podemos usar estas reglas para interrumpir y responder el mensaje, enviarlo a otro objeto o modificarlo entre otras acciones.

Cada vez que un objeto recibe un mensaje Ruby comprueba:

  1. Si este objeto tiene una clase singleton y puede responder a este mensaje.
  2. Busca la clase de este objeto y luego la cadena de ancestros de la clase.
  3. Uno por uno comprueba si un método está disponible en este antepasado y sube la cadena.

Mensaje que pasa a través de la cadena de herencia

class Example
  def example_method
    :example
  end

  def subexample_method
    :example
  end

  def not_missed_method
    :example
  end

  def method_missing name
    return :example if name == :missing_example_method
    return :example if name == :missing_subexample_method
    return :subexample if name == :not_missed_method
    super
  end
end

class SubExample < Example
  def subexample_method
    :subexample
  end

  def method_missing name
    return :subexample if name == :missing_subexample_method
    return :subexample if name == :not_missed_method
    super
  end
end

s = Subexample.new

Para encontrar un método adecuado para el SubExample#subexample_method Ruby primero mira la cadena de antepasados ​​del SubExample

SubExample.ancestors # => [SubExample, Example, Object, Kernel, BasicObject]

Se inicia desde el SubExample . Si enviamos el mensaje subexample_method , Ruby elige el que está disponible, un SubExample e ignora el Example#subexample_method .

s.subexample_method # => :subexample

Después del SubExample verifica Example . Si enviamos example_method Ruby verifica si SubExample puede responderle o no, y como no puede, Ruby sube la cadena y mira en Example .

s.example_method # => :example

Después de que Ruby comprueba todos los métodos definidos, ejecuta method_missing para ver si puede responder o no. Si enviamos missing_subexample_method Ruby no podrá encontrar un método definido en el SubExample por lo que se mueve hacia el Example . Tampoco puede encontrar un método definido en Example o cualquier otra clase superior en cadena. Ruby comienza de nuevo y ejecuta method_missing . method_missing of SubExample puede responder a missing_subexample_method .

s.missing_subexample_method # => :subexample

Sin embargo, si se define un método, Ruby usa una versión definida aunque sea más alta en la cadena. Por ejemplo, si enviamos not_missed_method a pesar de que method_missing de SubExample puede responder, Ruby aparece en SubExample porque no tiene un método definido con ese nombre y busca en Example que tiene uno.

s.not_missed_method # => :example

Mensaje que pasa a través de la composición del módulo

Ruby se mueve hacia arriba en la cadena de antepasados ​​de un objeto. Esta cadena puede contener tanto módulos como clases. Las mismas reglas sobre el ascenso de la cadena también se aplican a los módulos.

class Example
end

module Prepended
  def initialize *args
    return super :default if args.empty?
    super
  end
end

module FirstIncluded
  def foo
    :first
  end
end

module SecondIncluded
  def foo
    :second
  end
end

class SubExample < Example
  prepend Prepended
  include FirstIncluded
  include SecondIncluded

  def initialize data = :subexample
    puts data
  end
end

SubExample.ancestors # => [Prepended, SubExample, SecondIncluded, FirstIncluded, Example, Object, Kernel, BasicObject]

s = SubExample.new # => :default
s.foo # => :second

Mensajes de interrupcion

Hay dos formas de interrumpir los mensajes.

  • Use method_missing para interrumpir cualquier mensaje no definido.
  • Defina un método en medio de una cadena para interceptar el mensaje

Después de interrumpir los mensajes, es posible:

  • Responder a ellos.
  • Envíalos a otro lugar.
  • Modificar el mensaje o su resultado.

Interrupción a través de method_missing y respuesta al mensaje:

class Example
  def foo
    @foo
  end

  def method_missing name, data
    return super unless name.to_s =~ /=$/
    name = name.to_s.sub(/=$/, "")
    instance_variable_set "@#{name}", data
  end
end

e = Example.new

e.foo = :foo
e.foo # => :foo

Interceptando mensaje y modificándolo:

class Example
  def initialize title, body
  end
end

class SubExample < Example
end

Ahora imaginemos que nuestros datos son "título: cuerpo" y tenemos que dividirlos antes de llamar a Example . Podemos definir initialize en el SubExample .

class SubExample < Example
  def initialize raw_data
    processed_data = raw_data.split ":"

    super processed_data[0], processed_data[1]
  end
end

Interceptando mensaje y enviándolo a otro objeto:

class ObscureLogicProcessor
  def process data
    :ok
  end
end

class NormalLogicProcessor
  def process data
    :not_ok
  end
end

class WrapperProcessor < NormalLogicProcessor
  def process data
    return ObscureLogicProcessor.new.process data if data.obscure?

    super
  end
end


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow