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
前置 concerns
就像 include
一樣,concerns 也支援 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