Ruby Language
Message passant
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:
- Si cet objet a une classe singleton et qu'il peut répondre à ce message.
- Recherche la classe de cet objet puis la chaîne des ancêtres de la classe.
- 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