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:

  1. Se questo oggetto ha una classe singleton e può rispondere a questo messaggio.
  2. Cerca la classe di questo oggetto e la catena degli antenati di classe.
  3. 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


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow