Как выбрать метод для вызова, когда есть конфликт имени метода mixin? - PullRequest
5 голосов
/ 01 февраля 2012

Когда вы включаете модуль в класс с конфликтом имени метода, он будет использовать метод, определенный классом.Есть ли способ выбрать тот, который я хочу запустить?

module B
  def self.hello
    "hello B"
  end
end

class A
  include B
  def self.hello
     "hello A"
  end
end

A.hello #=> this prints "hello A", what if I want "hello B"?

Ответы [ 3 ]

12 голосов
/ 02 февраля 2012

Бен, когда вы вызываете метод (скажем, hello) в Ruby, вот что происходит:

  1. Если собственный класс получателя имеет метод с именем hello, он будет вызван. Если нет:
  2. Если у класса получателя есть экземплярный метод с именем hello, он будет вызван. Если нет:
  3. Если какой-либо модуль, включенный в класс получателя, имеет метод экземпляра с именем hello, он будет вызван. Если их несколько, последний включенный модуль победит. В противном случае:
  4. Если суперкласс класса получателя имеет экземплярный метод с именем hello, он будет вызван. Если нет:
  5. Если какой-либо модуль включен в суперкласс класса получателя ...
  6. (и так далее для суперкласса суперкласса, вплоть до BasicObject ...)
  7. Если метод с именем hello не найден, тот же процесс повторяется с method_missing, начиная с собственного класса, затем класса, затем включаемых модулей, затем суперкласса, затем модулей, включенных в суперкласс ... this поиск всегда завершается успешно, потому что Kernel определяет реализацию по умолчанию method_missing.

Итак, чтобы ответить на ваш вопрос, если существует более одного метода с именем hello, вы не можете выбрать, какой из них будет вызываться. Описанные выше правила поиска метода решают, какой из них будет вызван.

ОДНАКО: Ruby - это очень гибкий язык, и если вы опубликуете больше информации о том, что вы хотите сделать и почему, я, вероятно, могу помочь вам придумать способ имитации желаемого эффекта.

Еще один момент: если вы хотите добавить методы класса из модуля в класс, вы можете сделать это:

module B; def hello; "hello B"; end end
A.extend(B)
A.hello
=> "hello B"

Вы видите? Когда класс include s является модулем, методы экземпляра модуля становятся методами экземпляра в классе. Когда класс extend является модулем, методы экземпляра модуля становятся методами класса в классе.

1 голос
/ 02 февраля 2012

Когда вы вызываете A.Hello, все, что происходит, - это сообщение "hello", передаваемое объекту A.Затем объект A должен определить, как обрабатывать это сообщение.Сначала он рассмотрит свои собственные методы, чтобы определить, есть ли у него метод с именем "hello", прежде чем искать своих родителей и включенные модули для метода "hello".

Хотя вы могли бы технически использовать A.ancestors, чтобы увидеть, что B является предком A, и вызвать его метод hello, это нарушило бы абстракцию A как объекта.

Чтобы разрешить вызов обоих методов, можно создать другой метод в A, который вызывает B.hello, или назвать A.hello как-нибудь еще, чтобы он не перекрывал функциональность B.hello.

Редактировать: Поскольку вы включили B в A, создать метод, который вызывает привет B внутри A, так же просто, как добавить метод, который вызывает B.hello

def self.hello2
  B.hello
end
1 голос
/ 02 февраля 2012

То, как он настроен, в любом случае никогда не вызовет метод включенного модуля.Попробуйте опустить метод hello в A и посмотрите, что происходит, когда вы вызываете A.hello.

Это будет включать метод из B. Вероятно, есть более краткий способ сделать это.Я только что извлек его из своей кодовой базы:

module B
  def self.included(base)
    base.extend Greetings
  end

  module Greetings
    def hello
      "hello B"
    end
  end
end

Метод модуля всегда будет переопределять метод включенного модуля.Это способ, которым он должен работать.Тем не менее, вы могли бы условно возвратить приветственное значение А следующим образом:

module A
  include B

  def self.hello
    if show_hello_a?
      "hello A"
    else
      super
    end
  end

 def self.show_hello_a?
   false # insert an actual condition statement here
 end

end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...