Ruby Language
Messaggio in corso
Ricerca…
introduzione
In Object Oriented Design , gli oggetti ricevono messaggi e rispondono a loro. In Ruby, l'invio di un messaggio chiama un metodo e il risultato di tale metodo è la risposta.
In Ruby il passaggio dei messaggi è dinamico. Quando arriva un messaggio invece di sapere esattamente come rispondere ad esso Ruby usa un insieme predefinito di regole per trovare un metodo che possa rispondere ad esso. Possiamo usare queste regole per interrompere e rispondere al messaggio, inviarlo a un altro oggetto o modificarlo tra le altre azioni.
Ogni volta che un oggetto riceve un messaggio, Ruby controlla:
- Se questo oggetto ha una classe singleton e può rispondere a questo messaggio.
- Cerca la classe di questo oggetto e la catena degli antenati di classe.
- Uno ad uno controlla se un metodo è disponibile su questo antenato e si sposta verso l'alto della catena.
Messaggio che passa attraverso la catena di ereditarietà
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
Per trovare un metodo adatto per SubExample#subexample_method
Ruby guarda prima alla catena di antenati di SubExample
SubExample.ancestors # => [SubExample, Example, Object, Kernel, BasicObject]
Inizia da SubExample
. Se inviamo il messaggio subexample_method
, Ruby sceglie quello disponibile SubExample e ignora Example#subexample_method
.
s.subexample_method # => :subexample
Dopo SubExample
verifica Example
. Se inviamo example_method
Ruby controlla se SubExample
può rispondere o no e poiché non può Ruby risalire la catena e guarda in Example
.
s.example_method # => :example
Dopo che Ruby ha verificato tutti i metodi definiti, esegue method_missing
per vedere se può rispondere o meno. Se inviamo missing_subexample_method
Ruby non sarà in grado di trovare un metodo definito su SubExample
quindi passa a Example
. Non è possibile trovare un metodo definito su Example
o qualsiasi altra classe più alta in catena. Ruby ricomincia ed esegue method_missing
. method_missing
di SubExample
può rispondere a missing_subexample_method
.
s.missing_subexample_method # => :subexample
Tuttavia, se viene definito un metodo, Ruby utilizza la versione definita anche se è più alta nella catena. Ad esempio, se inviamo not_missed_method
anche se method_missing
di SubExample
può rispondere ad esso, Ruby si SubExample
su SubExample
perché non ha un metodo definito con quel nome e guarda in Example
che ne ha uno.
s.not_missed_method # => :example
Messaggio che passa attraverso la composizione del modulo
Ruby si sposta sulla catena di antenati di un oggetto. Questa catena può contenere sia moduli che classi. Le stesse regole su come spostare la catena si applicano anche ai moduli.
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
Interruzione dei messaggi
Esistono due modi per interrompere i messaggi.
- Utilizzare
method_missing
per interrompere qualsiasi messaggio non definito. - Definire un metodo nel mezzo di una catena per intercettare il messaggio
Dopo aver interrotto i messaggi, è possibile:
- Rispondi a loro.
- Mandali da qualche altra parte.
- Modifica il messaggio o il suo risultato.
Interrompere tramite method_missing
e rispondere al messaggio:
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
Intercettare il messaggio e modificarlo:
class Example
def initialize title, body
end
end
class SubExample < Example
end
Ora immaginiamo che i nostri dati siano "title: body" e dobbiamo suddividerli prima di chiamare Example
. Possiamo definire l' initialize
su SubExample
.
class SubExample < Example
def initialize raw_data
processed_data = raw_data.split ":"
super processed_data[0], processed_data[1]
end
end
Intercettazione del messaggio e invio a un altro oggetto:
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