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
?我们可以尝试通过直接在Bar
中包含Foo
来隐藏这些依赖关系,使其对Host
不可见
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
也用于任何依赖关系。
方法
- C
- I
- P
实例公有方法
class_methods(&class_methods_module_definition) 链接
从给定块中定义类方法。您也可以定义私有类方法。
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)
源代码:显示 | 在 GitHub 上查看
# 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) 链接
在基类上下文中评估给定块,以便您可以在此处编写类宏。当您定义多个included
块时,它会引发异常。
源代码:显示 | 在 GitHub 上查看
# 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) 链接
在基类上下文中评估给定块,以便您可以在此处编写类宏。当您定义多个prepended
块时,它会引发异常。
源代码:显示 | 在 GitHub 上查看
# 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