Ruby模块的included方法是什么?

4

我正在努力理解Ruby中的元编程,并且对于Module.included是什么感到困惑? 我目前的理解是,每当模块被包含到另一个模块或类中时,Ruby都会调用此回调函数。 除此之外,这些(元)编程构造在哪些方面使用? 有例子吗?


2
当询问一个非常广泛、开放式的问题,比如“什么是x?”时,表达你的理解有助于提供一个起点。 - anothermh
谢谢!我已经更新了问题以反映我的最新理解。 - yesyouken
1个回答

12

Module#included 允许模块在单个 include 中注入类方法和实例方法,并执行相关代码。

ActiveSupport::Concern 的文档说明了一个典型的用例。它将类方法注入到调用类中,并执行代码。在这种情况下,添加了一个scope

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

included是一个类,它将模块包含进去。这使得模块可以成为一个整体:实例方法、类方法和设置代码。

class Thing
  # Class and instance methods are injected, and the new scope is added.
  include M
end

如果没有included,一个模块只能注入实例方法。类方法必须单独添加,以及执行任何设置代码。

module M
  def some_instance_method
    ...
  end

  module ClassMethods
    def setup
      scope :disabled, -> { where(disabled: true) }
    end
  end
end
class Thing
  # Inject the instance methods
  include M

  # Inject the class methods
  extend M::ClassMethods

  # Run any setup code.
  setup
end

其他示例可能包括注册类,例如作为可用插件。

module Plugin
  def self.included(base)
    base.extend ClassMethods
    base.class_eval do
      register_as_plugin(base)
    end
  end

  module ClassMethods
    def register_as_plugin(klass)
      ...
    end
  end
end

class Thing
  include Plugin
end

或者添加必要的访问器。

module HasLogger
  def self.included(base)
    base.class_eval do
      attr_writer :logger
    end
  end

  def logger
    @logger ||= Rails.logger
  end
end

class Thing
  include HasLogger
end

为什么我们需要使用base.base.class_eval - TPR
1
@TPR 因为included是在模块上调用的,所以包含它的类被传递为base。在HasLogger示例中,在self.included内部,selfHasLogger,而baseThing。如果没有base.class_eval,它会在HasLogger中添加属性。我们想要将属性添加到Thing中。base.class_eval让我们做到了这一点;在base.class_eval内部,selfThing。我们也可以写成base.attr_writter :logger - Schwern

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接