ActiveSupport::应包含或扩展关注点

Raj*_*rma 5 ruby ruby-on-rails

我知道 include 用于将模块方法作为实例方法访问,而extend 用于将模块方法作为类方法访问。

对于 ActiveSupport::Concern 我看到的某处写为,

module Test
  include ActiveSupport::Concern
end
Run Code Online (Sandbox Code Playgroud)

而在某些地方写为,

module Test
  extend ActiveSupport::Concern
end
Run Code Online (Sandbox Code Playgroud)

我的困惑是,ActiveSupport::Concern 应该与 include 还是与extend 一起使用?

max*_*max 2

您需要扩展模块,ActiveSupport::Concern才能使ActiveSupport::Concern#included#class_methods方法正常工作。

毕竟这两种方法几乎是它存在的唯一原因。

module A
  extend ActiveSupport::Concern
  # raises ArgumentError (wrong number of arguments (given 0, expected 1))
  included do
    puts "Hello World"
  end
end
Run Code Online (Sandbox Code Playgroud)
module B
  extend ActiveSupport::Concern
  included do
    puts "Hello World"
  end
end

class C
  include B
end
# Outputs Hello World
Run Code Online (Sandbox Code Playgroud)

看看如果我们检查该included方法会发生什么:

module AB
  include ActiveSupport::Concern
  puts method(:included).source_location # nil
end
Run Code Online (Sandbox Code Playgroud)
module ABC
  extend ActiveSupport::Concern
  puts method(:included).source_location # .../ruby/gems/2.7.0/gems/activesupport-6.0.2.1/lib/active_support/concern.rb
end
Run Code Online (Sandbox Code Playgroud)

当我们扩展模块时,ActiveSupport::Concern我们将其放在 的祖先链上ABC,因此 的方法ActiveSupport::Concern可用作 的模块方法ABCinclude当您使用并且included调用的方法实际上是来自 Ruby 核心的 Module#included 时,不会发生这种情况。