В чем разница между отправкой: включить в класс и непосредственно определить метод в определении второго класса?
Недавно мне пришлось добавить метод в основной класс 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 ответ
Есть два отличия:
Когда вы используете миксин, есть четкое место, где могут жить ваши "патч" методы. Если мне интересно "Хм, где это
my_new_method
"Исходя из, и я смотрю, скажем,TimeEntryQuery.ancestors
или жеTimeEntryQuery.instance_method(:my_new_method).owner
, что вернетсяPatches::SomeClassPatch
, Так что я знаю, что я должен искать файл с именемlib/patches/some_class_patch.rb
где-то, чтобы найти, где это, вероятно, определяется. (Я мог бы попробоватьsource_location
как хорошо, но это не всегда надежно.)Смешивание модуля в класс делает модуль суперклассом класса, в который он смешивается. Итак, если уже есть
my_new_method
определяется вTimeEntryQuery
ваш первый вариант перезапишет его, тогда как во втором ваш метод станетsuper
метод этого метода. IOW: с вашим вторым параметром ваш новый метод не будет вызываться, если только существующие методы не вызываютsuper
,