Sök…


Introduktion

I Objektorienterad design, föremål ta emot meddelanden och svara på dem. I Ruby kallar man en metod och att resultatet av den metoden är svaret.

I Ruby är meddelandet vidarebefordran dynamiskt. När ett meddelande kommer snarare än att veta exakt hur man svarar på det använder Ruby en fördefinierad uppsättning regler för att hitta en metod som kan svara på den. Vi kan använda dessa regler för att avbryta och svara på meddelandet, skicka det till ett annat objekt eller ändra det bland andra åtgärder.

Varje gång ett objekt får ett meddelande kontrollerar Ruby:

  1. Om detta objekt har en singleton-klass och det kan svara på det här meddelandet.
  2. Slå upp objektets klass sedan klassens förfäder kedja.
  3. En efter en kontrollerar om en metod är tillgänglig på denna förfader och flyttar uppåt kedjan.

Meddelande som passerar genom arvkedjan

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

För att hitta en lämplig metod för SubExample#subexample_method Ruby tittar först på förfädernas kedja till SubExample

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

Det börjar från SubExample . Om vi skickar meddelandet subexample_method väljer Ruby det tillgängliga underexemplet och ignorerar Example#subexample_method .

s.subexample_method # => :subexample

Efter SubExample kontrollerar det Example . Om vi skickar example_method Ruby kontrollerar om SubExample kan svara på det eller inte och eftersom det inte kan Ruby går upp kedjan och tittar i Example .

s.example_method # => :example

Efter att Ruby har kontrollerat alla definierade metoder körs method_missing att se om den kan svara eller inte. Om vi skickar missing_subexample_method Ruby inte hitta en definierad metod på SubExample så att den går upp till Example . Den kan inte hitta en definierad metod i Example eller någon annan klass högre i kedjan heller. Ruby börjar om och kör method_missing . method_missing of SubExample kan svara på missing_subexample_method .

s.missing_subexample_method # => :subexample

Men om en metod är definierad använder Ruby en definierad version även om den är högre i kedjan. Om vi till exempel skickar not_missed_method även om method_missing av SubExample kan svara på det Ruby går upp på SubExample eftersom det inte har en definierad metod med det namnet och tittar på Example som har en.

s.not_missed_method # => :example

Meddelande som passerar modulens sammansättning

Ruby rör sig upp på förfädernas kedja av ett objekt. Denna kedja kan innehålla både moduler och klasser. Samma regler för att flytta upp kedjan gäller också för moduler.

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

Avbryta meddelanden

Det finns två sätt att avbryta meddelanden.

  • Använd method_missing att avbryta alla icke definierade meddelanden.
  • Definiera en metod i mitten av en kedja för att fånga meddelandet

Efter avbrott i meddelanden är det möjligt att:

  • Svara på dem.
  • Skicka dem någon annanstans.
  • Ändra meddelandet eller resultatet.

method_missing via method_missing och svara på meddelande:

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

Avlyssna meddelandet och ändra det:

class Example
  def initialize title, body
  end
end

class SubExample < Example
end

Låt oss nu föreställa oss att våra data är "titel: body" och vi måste dela dem innan vi kallar Example . Vi kan definiera initializeSubExample .

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

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

Avlyssna meddelandet och skicka det till ett annat objekt:

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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow