В чем разница между отправкой: включить в класс и непосредственно определить метод в определении второго класса?

Недавно мне пришлось добавить метод в основной класс Redmine. Мне не удалось использовать наследование, поэтому я сделал что-то вроде этого:

require_dependency 'time_entry_query'
class TimeEntryQuery < Query
    def my_new_method(foo, bar)
    end
end

и это работает отлично - мой метод добавляется ко всем новым объектам. Тем не менее, я видел, как кто-то объявлял новый метод в своем собственном модуле, а затем отправлял: include в класс, чтобы он стал миксином. Вот пример:

module Patches
  module SomeClassPatch
    def my_new_method
    end
end

и где-то в инициализации приложения:

SomeClass.send(:include, Patches::SomeClassPatch) unless SomeClass.include? (Patches::SomeClassPatch)

В чем разница между этими двумя методами и какой мне следует использовать?

1 ответ

Решение

Есть два отличия:

  1. Когда вы используете миксин, есть четкое место, где могут жить ваши "патч" методы. Если мне интересно "Хм, где это my_new_method"Исходя из, и я смотрю, скажем, TimeEntryQuery.ancestors или же TimeEntryQuery.instance_method(:my_new_method).owner, что вернется Patches::SomeClassPatch, Так что я знаю, что я должен искать файл с именем lib/patches/some_class_patch.rb где-то, чтобы найти, где это, вероятно, определяется. (Я мог бы попробовать source_location как хорошо, но это не всегда надежно.)

  2. Смешивание модуля в класс делает модуль суперклассом класса, в который он смешивается. Итак, если уже есть my_new_method определяется в TimeEntryQueryваш первый вариант перезапишет его, тогда как во втором ваш метод станет super метод этого метода. IOW: с вашим вторым параметром ваш новый метод не будет вызываться, если только существующие методы не вызывают super,

Другие вопросы по тегам