Active Support Concern¶ ↑
一个典型的模块看起来是这样的
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 呢?我们可以尝试直接将 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
Prepending concerns¶ ↑
就像 include 一样,concerns 也支持 prepend,并有相应的 prepended do 回调。module ClassMethods 或 class_methods do 也会被 prepended。
prepend 也用于任何依赖项。
方法
- C
- I
- P
实例公共方法
class_methods(&class_methods_module_definition) Link
从给定的块定义类方法。你也可以定义私有的类方法。
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)
# 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
included(base = nil, &block) Link
在 base 类的上下文中求值给定的块,这样你就可以在这里编写类宏。当你定义多个 included 块时,它会引发一个异常。
# 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
prepended(base = nil, &block) Link
在 base 类的上下文中求值给定的块,这样你就可以在这里编写类宏。当你定义多个 prepended 块时,它会引发一个异常。
# 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