Spec-Zone.ru › Ruby on Rails 7.2

модуль Module::Concerning

Разделение забот на небольшие части

Мы часто сталкиваемся со средним куском поведения, который мы хотели бы извлечь, но только смешиваем в один класс.

Извлечение обычного объекта Ruby для его инкапсуляции и сотрудничества или делегирования исходному объекту часто является хорошим выбором, но когда нет дополнительного состояния для инкапсуляции или мы делаем объявления в стиле DSL относительно родительского класса, введение новых коллабораторов может запутать, а не упростить.

Типичный путь — просто выбросить все в монолитный класс, возможно, с комментарием, как наименее плохой альтернативе. Использование модулей в отдельных файлах означает утомительное просеивание, чтобы получить общее представление.

Неудовлетворительные способы разделения небольших забот

Использование комментариев:

class Todo < ApplicationRecord
  # Other todo implementation
  # ...

  ## Event tracking
  has_many :events

  before_create :track_creation

  private
    def track_creation
      # ...
    end
end

С встроенным модулем:

Громкий синтаксис.

class Todo < ApplicationRecord
  # Other todo implementation
  # ...

  module EventTracking
    extend ActiveSupport::Concern

    included do
      has_many :events
      before_create :track_creation
    end

    private
      def track_creation
        # ...
      end
  end
  include EventTracking
end

Шум миксина, сосланный в собственный файл:

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

class Todo < ApplicationRecord
  # Other todo implementation
  # ...

  include TodoEventTracking
end

Представление Module#concerning

Успокаивая шум миксина, мы получаем естественный, простой способ разделить небольшие заботы.

class Todo < ApplicationRecord
  # Other todo implementation
  # ...

  concerning :EventTracking do
    included do
      has_many :events
      before_create :track_creation
    end

    private
      def track_creation
        # ...
      end
  end
end

Todo.ancestors
# => [Todo, Todo::EventTracking, ApplicationRecord, Object]

Этот небольшой шаг имеет некоторые замечательные побочные эффекты. Мы можем

  • понять поведение нашего класса с первого взгляда,

  • очистить монолитные классы-хранилища, разделяя их заботы, и

  • перестать полагаться на protected/private для грубой модульности «это внутренняя информация».

Добавление concerning в начало

concerning поддерживает аргумент prepend: true, который prepend заботу вместо использования include для неё.

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

concern(topic, &module_definition) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/concerning.rb, line 132
def concern(topic, &module_definition)
  const_set topic, Module.new {
    extend ::ActiveSupport::Concern
    module_eval(&module_definition)
  }
end

Короткий способ определения заботы.

concern :EventTracking do
  ...
end

эквивалентно

module EventTracking
  extend ActiveSupport::Concern

  ...
end
concerning(topic, prepend: false, &block) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/concerning.rb, line 114
def concerning(topic, prepend: false, &block)
  method = prepend ? :prepend : :include
  __send__(method, concern(topic, &block))
end

Определение новой заботы и её добавление.

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

Spec-Zone.ru

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