Подтвердить что ты не робот

Ruby mixins и вызов супер методов

Хорошо, поэтому я реорганизовал свой код в своем маленьком приложении Rails, пытаясь удалить дублирование, и в целом упростил свою жизнь (как мне нравится простая жизнь). Часть этого рефакторинга заключалась в том, чтобы переместить код, общий для двух моих моделей, в модуль, который я могу включить туда, где он мне нужен.

До сих пор так хорошо. Похоже, что это сработает, но я просто попал в проблему, и я не уверен, как обойти. Модуль (который я назвал sendable), будет просто кодом, который обрабатывает факсы, электронную почту или печать PDF документа. Так, например, у меня есть заказ на поставку, и у меня есть внутренние заказы на продажу (по образцу сокращенно ISO).

Проблема, с которой я столкнулся, заключается в том, что я хочу, чтобы некоторые переменные были инициализированы (инициализированы для людей, которые неправильно написаны: P) после того, как объект загружен, поэтому я использовал after_initialize крючок. Нет проблем... пока я не начну добавлять еще несколько миксинов.

У меня есть проблема: я могу иметь after_initialize в любом из моих миксинов, поэтому мне нужно включить вызов super в начале убедитесь, что вызываются другие вызовы mixin after_initialize. Это здорово, пока я не позвоню супер, и я получаю сообщение об ошибке, потому что супер не звонит.

Вот небольшой пример, если я недостаточно запутался:

class Iso < ActiveRecord::Base
  include Shared::TracksSerialNumberExtension
  include Shared::OrderLines
  extend  Shared::Filtered
  include Sendable::Model

  validates_presence_of   :customer
  validates_associated    :lines

  owned_by                :customer
  order_lines             :despatched # Mixin

  tracks_serial_numbers   :items  # Mixin

  sendable :customer                      # Mixin

  attr_accessor :address

  def initialize( params = nil )
    super
    self.created_at ||= Time.now.to_date
  end
end

Итак, если каждый из миксинов имеет вызов after_initialize с вызовом super, как я могу остановить этот последний вызов super из-за повышения ошибки? Как я могу проверить, существует ли метод супер до того, как я его назову?

4b9b3361

Ответ 1

Вы можете использовать это:

super if defined?(super)

Вот пример:

class A
end

class B < A
  def t
    super if defined?(super)
    puts "Hi from B"
  end
end

B.new.t

Ответ 2

Вы пробовали alias_method_chain? Вы можете в основном связать все ваши звонки after_initialize. Он действует как декоратор: каждый новый метод добавляет новый уровень функциональности и передает управление на "переопределенный" метод, чтобы сделать все остальное.

Ответ 3

Входящий класс (вещь, которая наследует от ActiveRecord::Base, которая в этом случае Iso) может определить свой собственный after_initialize, поэтому любое решение, отличное от alias_method_chain (или другое наложение, которое сохраняет исходный текст ) рискует переписать код. Решение @Orion Edwards - лучшее, что я могу придумать. Есть и другие, но они далеко более хаки.

alias_method_chain также имеет преимущество создания именованных версий метода after_initialize, то есть вы можете настроить порядок вызовов в тех редких случаях, которые имеют значение. В противном случае вы будете во власти любого порядка включительного класса включите mixins.

позже:

Я разместил вопрос в списке рассылки ruby-on-rails о создании стандартных пустых реализаций всех обратных вызовов. Процесс сохранения все равно проверяет их, поэтому я не понимаю, почему их не должно быть. Единственным недостатком является создание дополнительных пустых кадров стека, но это довольно дешево для каждой известной реализации.

Ответ 4

Вы можете просто бросить быструю условность:

super if respond_to?('super')

и вы должны быть в порядке - не добавлять бесполезные методы; приятный и чистый.

Ответ 5

Вместо того, чтобы проверять, существует ли супер-метод, вы можете просто определить его

class ActiveRecord::Base
    def after_initialize
    end
end

Это работает в моем тестировании и не должно разорвать какой-либо из вашего существующего кода, потому что все ваши другие классы, которые его определяют, просто будут молча отменять этот метод в любом случае