Динамическое расширение модулей в Devise - PullRequest
1 голос
/ 25 мая 2019

Я узнал больше о динамическом включении и расширении модулей с помощью метапрограммирования, и я нашел статью, обсуждающую реализацию #included в геме Devise.Чтобы включить модули разработки, в модель будет добавлена ​​следующая строка:

devise :database_authenticatable, :registerable, :validatable

Это вызывает метод devise:

def devise(*modules)
  options = modules.extract_options!.dup

  selected_modules = modules.map(&:to_sym).uniq.sort_by do |s|
    Devise::ALL.index(s) || -1  # follow Devise::ALL order
  end

  devise_modules_hook! do
    include Devise::Models::Authenticatable

    selected_modules.each do |m|
      mod = Devise::Models.const_get(m.to_s.classify)

      if mod.const_defined?("ClassMethods")
        class_mod = mod.const_get("ClassMethods")
        extend class_mod

        if class_mod.respond_to?(:available_configs)
          available_configs = class_mod.available_configs
          available_configs.each do |config|
            next unless options.key?(config)
            send(:"#{config}=", options.delete(config))
          end
        end
      end

      include mod
    end

    self.devise_modules |= selected_modules
    options.each { |key, value| send(:"#{key}=", value) }
  end
end

Затем пример метода includedиз модуля Validatable:

def self.included(base)
  base.extend ClassMethods
  assert_validations_api!(base)

  base.class_eval do
    validates_presence_of   :email, if: :email_required?
    validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
    validates_format_of     :email, with: email_regexp, allow_blank: true, if: :email_changed?

    validates_presence_of     :password, if: :password_required?
    validates_confirmation_of :password, if: :password_required?
    validates_length_of       :password, within: password_length, allow_blank: true
  end
end

Мой вопрос такой: если модуль ClassMethods уже расширен в методе devise (конкретный блок кода ниже), почему он снова распространяется на базу?в #included?Это просто избыточность или у них другое поведение?

# This is from the `devise` method      
if mod.const_defined?("ClassMethods")
  class_mod = mod.const_get("ClassMethods")
  extend class_mod

# This is the first line of the `self.included(base)` method
base.extend ClassMethods

1 Ответ

1 голос
/ 25 мая 2019

Оба они делают одно и то же, так что это либо избыточность по историческим причинам (они забыли удалить), либо, возможно, они не полагаются на все свои модули, имеющие метод self.included с base.extend ClassMethods

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...