Ruby prepend не работает для метода класса - PullRequest
0 голосов
/ 28 мая 2018

Я пытаюсь использовать метод prepend в ruby ​​для перезаписи методов класса, вот как работает мой код:

module PrependedModule
  def self.klass_method
    puts 'PrependedModule klass_method'
  end

  def instance_method_a
    puts 'PrepenedModule instance method'
  end
end

class SomeClass
  prepend PrependedModule

  def self.klass_method
    puts 'SomeClass klass_method'
  end

  def instance_method_a
    puts 'SomeClass instance_method'
  end
end

SomeClass.klass_method
SomeClass.new.instance_method_a

#output:
#SomeClass klass_method
#PrependedModule instance method

#expected:
#PrependedModule klass_method
#PrependedModule instance method

Вывод этого скрипта показан выше, как мы можем видеть,метод экземпляра instance_method_a был перезаписан модулем PrependedModule, но не методом класса klass_method, когда я вызвал klass_method для SomeClass, он по-прежнему выполняет свой метод источника вместо метода, определенного в PrependedModule.

Я запутался в этом и не знаю, что произошло с методами класса при использовании prepend.Было бы очень полезно, если бы кто-нибудь мог решить этот вопрос для меня.

Ответы [ 2 ]

0 голосов
/ 28 мая 2018

С include или prepend вы можете получить доступ только к методам экземпляра модуля 1 .Поэтому вы можете спросить, есть ли какая-либо причина для определения методов модуля в модуле.Ответ звучит "да".Вы можете захотеть сделать это по двум причинам.

Первая не имеет ничего общего с включением или добавлением модуля.Вам нужно только взглянуть на модуль Math , чтобы понять, почему вы можете захотеть это сделать.Все методы, определенные в Math, являются модульными методами.Они составляют библиотеку полезных функций.Это, конечно, методы, но, поскольку все они имеют Math в качестве получателя, они ведут себя как функции в не-ООП-языках.

Вторая причина заключается в том, что вам может потребоваться определить метод обратного вызова (он же hook метод) для модуля, который должен быть включен или добавлен другим модулем.Основными из них являются Модуль # включен , Модуль # с добавлением , Модуль # расширен , Класс # наследуется и BasicObject # method_missing.Последний из них является методом экземпляра;остальные являются модульными методами.Ниже приведен пример Module#prepended.

@ mudasoba показал, как ограничить методы экземпляра подмодулем Sub из Mod, чтобы Mod::Sub можно было добавить (или включить) вкласс (или модуль) синглтон-класс.Обычно используемый шаблон для выполнения этого обратного вызова Module#prepended.Это следует.

module PrependedModule
  module ClassMethods
    def klass_method
      puts 'PrependedModule klass_method'
    end
  end

  def instance_method_a
    puts 'PrepenedModule instance method'
  end

  def self.prepended(mod)
    mod.singleton_class.prepend(ClassMethods)
  end
end

class SomeClass
  def self.klass_method
    puts 'SomeClass klass_method'
  end

  def instance_method_a
    puts 'SomeClass instance_method'
  end

  prepend PrependedModule
end

SomeClass.klass_method
  # PrependedModule klass_method
SomeClass.new.instance_method_a
  # PrepenedModule instance method

1 Мне всегда было любопытно, что методы экземпляра могут быть определены для модулей (которые не являются классами), учитывая, что такие модули не могут иметьэкземпляров.Правда, эти методы становятся методами экземпляров в классах, которые включают или дополняют модуль, но имейте в виду, что эти модули могут быть включены или дополнены другими модулями (которые не являются классами).Поэтому можно ожидать, что такие методы будут иметь имя, отличное от «метода экземпляра».Однако найти подходящую альтернативу было бы непросто, что, возможно, является одной из причин сохранения этой номенклатуры.

0 голосов
/ 28 мая 2018

Синглтон-классы не работают таким образом.Вам необходимо явно prepend методы для собственного класса SomeClass:

module PrependedModule
  module ClassMethods
    def klass_method
      puts 'PrependedModule klass_method'
    end
  end

  def instance_method_a
    puts 'PrepenedModule instance method'
  end
end

class SomeClass
  # prepending to the class
  prepend PrependedModule
  class << self
    # prepending to the eigenclass
    prepend PrependedModule::ClassMethods
  end

  def self.klass_method
    puts 'SomeClass klass_method'
  end

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