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

Недавно мне пришлось добавить метод в основной класс 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)

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


person yeputons    schedule 24.09.2013    source источник
comment
второй пример поведения динамического программирования Ruby.   -  person Arup Rakshit    schedule 25.09.2013


Ответы (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.

person Jörg W Mittag    schedule 24.09.2013