Recherche…


introduction

Dans la conception orientée objet , les objets reçoivent des messages et y répondent . En Ruby, l'envoi d'un message appelle une méthode et le résultat de cette méthode est la réponse.

Dans Ruby, le passage de messages est dynamique. Lorsqu'un message arrive plutôt que de savoir exactement comment y répondre, Ruby utilise un ensemble de règles prédéfini pour trouver une méthode capable d'y répondre. Nous pouvons utiliser ces règles pour interrompre et répondre au message, l'envoyer à un autre objet ou le modifier parmi d'autres actions.

Chaque fois qu'un objet reçoit un message, Ruby vérifie:

  1. Si cet objet a une classe singleton et qu'il peut répondre à ce message.
  2. Recherche la classe de cet objet puis la chaîne des ancêtres de la classe.
  3. Un par un vérifie si une méthode est disponible sur cet ancêtre et remonte la chaîne.

Message passant par la chaîne d'héritage

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

Pour trouver une méthode adaptée à SubExample#subexample_method Ruby examine d'abord la chaîne d'ancêtres de SubExample

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

Cela commence par SubExample . Si nous envoyons subexample_method message sous- subexample_method , Ruby choisit celui qui est disponible sous SubExample et ignore Example#subexample_method .

s.subexample_method # => :subexample

Après SubExample il vérifie Example . Si nous envoyons example_method Ruby vérifie si SubExample peut y répondre ou non, et comme Ruby ne peut pas monter la chaîne et examine Example .

s.example_method # => :example

Après que Ruby ait vérifié toutes les méthodes définies, il exécute method_missing pour voir s'il peut répondre ou non. Si nous envoyons missing_subexample_method Ruby ne sera pas en mesure de trouver une méthode définie dans SubExample afin de passer à Example . Il ne peut pas non plus trouver une méthode définie sur Example ou toute autre classe supérieure dans la chaîne. Ruby recommence et exécute method_missing . method_missing de SubExample peut répondre à missing_subexample_method .

s.missing_subexample_method # => :subexample

Cependant, si une méthode est définie, Ruby utilise une version définie même si elle est plus élevée dans la chaîne. Par exemple, si nous envoyons not_missed_method même si method_missing de SubExample peut y répondre, Ruby se place sur SubExample car il ne possède pas de méthode définie avec ce nom et examine Example qui en a un.

s.not_missed_method # => :example

Message passant par la composition du module

Ruby monte sur la chaîne des ancêtres d'un objet. Cette chaîne peut contenir à la fois des modules et des classes. Les mêmes règles concernant le déplacement de la chaîne s’appliquent également aux modules.

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

Interruption des messages

Il existe deux manières d’interrompre les messages.

  • Utilisez method_missing pour interrompre tout message non défini.
  • Définir une méthode en milieu de chaîne pour intercepter le message

Après avoir interrompu les messages, il est possible de:

  • Leur réponds.
  • Envoyez-les ailleurs.
  • Modifier le message ou son résultat.

Interrompre via method_missing et répondre au message:

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

Interception du message et modification:

class Example
  def initialize title, body
  end
end

class SubExample < Example
end

Imaginons maintenant que nos données sont "title: body" et que nous devons les séparer avant d'appeler Example . Nous pouvons définir l' initialize sur SubExample .

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

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

Intercepter un message et l'envoyer à un autre objet:

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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow