수색…


소개

객체 지향 디자인 에서 객체 메시지를 받고 그에 응답 합니다. Ruby에서 메시지를 보내는 것은 메서드를 호출하고 해당 메서드의 결과가 응답입니다.

Ruby에서 메시지 전달은 동적입니다. 메시지가 도착할 때 회신하는 방법을 정확하게 알기보다는 루비는 사전 정의 된 규칙 집합을 사용하여 회신 할 수있는 방법을 찾습니다. 이러한 규칙을 사용하여 메시지에 끼어 들거나 회신하거나 다른 개체로 보내거나 다른 작업 중에서 수정할 수 있습니다.

객체가 메시지를받을 때마다 Ruby는 다음을 검사합니다.

  1. 이 객체가 싱글 톤 클래스를 가지며이 메시지에 응답 할 수 있습니다.
  2. 이 객체의 클래스를 찾은 다음 클래스의 조상 체인을 찾습니다.
  3. 하나씩이 조상에 메서드를 사용할 수 있는지 확인하고 체인을 위로 이동합니다.

상속 체인을 통해 전달되는 메시지

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

SubExample#subexample_method 적합한 메소드를 찾으려면 먼저 Ruby는 SubExample 조상 체인을 SubExample

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

SubExample 부터 시작합니다. subexample_method 메시지를 보내면 Ruby는 사용 가능한 하나의 SubExample을 선택하고 Example#subexample_method 무시합니다.

s.subexample_method # => :subexample

SubExample 후에는 Example 을 확인합니다. example_method 를 보내면 Ruby는 SubExample 이 회신 할 수 있는지 여부를 확인합니다. 루비는 사슬을 따라 올라갈 수 없으므로 Example 합니다.

s.example_method # => :example

루비가 정의 된 모든 메소드를 검사 한 후 method_missing 을 실행하여 응답 여부를 확인합니다. missing_subexample_method 를 보내면 Ruby는 SubExample 정의 된 메소드를 찾을 수 없으므로 Example 이동합니다. Example 또는 체인 중 상위에있는 다른 클래스에서 정의 된 메소드를 찾을 수 없습니다. 루비는 다시 시작하여 method_missing 실행합니다. SubExample method_missingmissing_subexample_method 응답 할 수 있습니다.

s.missing_subexample_method # => :subexample

그러나 메소드가 정의되면 루비는 정의 된 버전을 사슬에서 더 높더라도 사용합니다. 예를 들어, not_missed_method method_missingSubExample 응답 할 수 있다고하더라도 not_missed_method 를 보내면, Ruby는 그 이름을 가진 정의 된 메소드가 없기 때문에 SubExample 을 따라 SubExample Example 를 찾습니다.

s.not_missed_method # => :example

모듈 구성을 통과하는 메시지

루비는 객체의 조상 체인 위로 이동합니다. 이 체인에는 모듈과 클래스가 모두 포함될 수 있습니다. 체인을 위로 이동하는 것과 같은 규칙이 모듈에도 적용됩니다.

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

메시지 인터럽트

메시지를 중단하는 데는 두 가지 방법이 있습니다.

  • 정의되지 않은 메시지를 중단하려면 method_missing 을 사용하십시오.
  • 체인 중간에서 메시지를 가로 채기위한 메소드를 정의하십시오.

메시지를 중단 한 후에는 다음을 수행 할 수 있습니다.

  • 그들에게 대답하십시오.
  • 다른 곳으로 보냅니다.
  • 메시지 또는 그 결과를 수정하십시오.

method_missing 통한 인터럽트 및 메시지에 대한 답장 :

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

메시지 가로 채기 및 수정 :

class Example
  def initialize title, body
  end
end

class SubExample < Example
end

이제 우리의 데이터가 "title : body"라고 상상해 봅시다. Example 을 호출하기 전에 데이터를 분할해야합니다. SubExample initialize 를 정의 할 수 있습니다.

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

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

메시지 가로 채기 및 다른 개체로 보내기 :

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
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow