Spec-Zone.ru › Ruby on Rails 8.1

module ActiveSupport::Concern

Concern в Active Support

Типичный модуль выглядит так:

module M
  def self.included(base)
    base.extend ClassMethods
    base.class_eval do
      scope :disabled, -> { where(disabled: true) }
    end
  end

  module ClassMethods
    ...
  end
end

Используя ActiveSupport::Concern, приведённый выше модуль можно записать так:

require "active_support/concern"

module M
  extend ActiveSupport::Concern

  included do
    scope :disabled, -> { where(disabled: true) }
  end

  class_methods do
    ...
  end
end

Кроме того, этот механизм корректно обрабатывает зависимости модулей. Для модуля Foo и модуля Bar, зависящего от первого, мы обычно написали бы следующее:

module Foo
  def self.included(base)
    base.class_eval do
      def self.method_injected_by_foo
        ...
      end
    end
  end
end

module Bar
  def self.included(base)
    base.method_injected_by_foo
  end
end

class Host
  include Foo # We need to include this dependency for Bar
  include Bar # Bar is the module that Host really needs
end

Но почему Host должен заботиться о зависимостях Bar, а именно Foo? Мы могли бы попытаться скрыть их от Host, напрямую подключив Foo в Bar:

module Bar
  include Foo
  def self.included(base)
    base.method_injected_by_foo
  end
end

class Host
  include Bar
end

К сожалению, это не сработает, поскольку при подключении Foo его base — это модуль Bar, а не класс Host. С помощью ActiveSupport::Concern зависимости модулей разрешаются корректно:

require "active_support/concern"

module Foo
  extend ActiveSupport::Concern
  included do
    def self.method_injected_by_foo
      ...
    end
  end
end

module Bar
  extend ActiveSupport::Concern
  include Foo

  included do
    self.method_injected_by_foo
  end
end

class Host
  include Bar # It works, now Bar takes care of its dependencies
end

Добавление примесей в начало

Как и include, примеси также поддерживают prepend с соответствующим обратным вызовом prepended do. Кроме того, в начало добавляются module ClassMethods или class_methods do.

prepend также используется для любых зависимостей.

Общедоступные методы экземпляра

class_methods (&class_methods_module_definition) Показать исходный код
# File activesupport/lib/active_support/concern.rb, line 209
def class_methods(&class_methods_module_definition)
  mod = const_defined?(:ClassMethods, false) ?
    const_get(:ClassMethods) :
    const_set(:ClassMethods, Module.new)

  mod.module_eval(&class_methods_module_definition)
end

Определяет методы класса из указанного блока. Также можно определять закрытые методы класса.

module Example
  extend ActiveSupport::Concern

  class_methods do
    def foo; puts 'foo'; end

    private
      def bar; puts 'bar'; end
  end
end

class Buzz
  include Example
end

Buzz.foo # => "foo"
Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
included (base = nil, &block) Показать исходный код
# File activesupport/lib/active_support/concern.rb, line 158
def included(base = nil, &block)
  if base.nil?
    if instance_variable_defined?(:@_included_block)
      if @_included_block.source_location != block.source_location
        raise MultipleIncludedBlocks
      end
    else
      @_included_block = block
    end
  else
    super
  end
end

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

Вызывает метод суперкласса
prepended (base = nil, &block) Показать исходный код
# File activesupport/lib/active_support/concern.rb, line 175
def prepended(base = nil, &block)
  if base.nil?
    if instance_variable_defined?(:@_prepended_block)
      if @_prepended_block.source_location != block.source_location
        raise MultiplePrependBlocks
      end
    else
      @_prepended_block = block
    end
  else
    super
  end
end

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

Вызывает метод суперкласса

© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API