Миксины Ruby и вызов супер методов

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

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

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

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

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

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

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

Ответов (5)

Решение

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

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

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

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

class ActiveRecord::Base
    def after_initialize
    end
end

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

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

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

позже :

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

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

super if respond_to?('super')

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