module ActiveSupport
module Concern
# 定义了一个异常类,不能多次include
class MultipleIncludedBlocks < StandardError
def initialize
super "Cannot define multiple 'included' blocks for a Concern"
end
end
# self.extended是extend时的钩子方法
def self.extended(base)
# 定义base中的@_dependencies
base.instance_variable_set(:@_dependencies, [])
end
# ruby在include一个module时会调用append_features方法,进行实际的mixin操作,包括增加常量,方法和变量到模块中
def append_features(base)
if base.instance_variable_defined?(:@_dependencies)
# 如果有引入已经定义@_dependencies时,一般是引入一个已经extend这个Concern的module,才会定义@_dependencies
# 将后extend这个Concern的module放入到@_dependencies中
base.instance_variable_get(:@_dependencies) << self
false
else
return false if base < self
# @_dependencies是详见上面定义的self.extended
# 先引入包含在@_dependencies中module
@_dependencies.each { |dep| base.include(dep) }
super
# ClassMethods是详见下面定义的class_methods
# 如果定义ClassMethods,将ClassMethods中的方法extend到base中
base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
# @_included_block是详见下面定义的included方法
# 如果定义@_included_block,在base中执行@_included_block中的代码
base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
end
end
# extend后,将可以使用included这个方法
def included(base = nil, &block)
if base.nil?
# 判断是否多次include
raise MultipleIncludedBlocks if instance_variable_defined?(:@_included_block)
# 定义类实例类变量
@_included_block = block
else
super
end
end
# extend后,将可以使用class_methods这个方法
def class_methods(&class_methods_module_definition)
# extend时判断当前module是否定义了ClassMethods这个常量,不包括父级
# 有的话就使用已经定义好的,没有就Module.new一个
mod = const_defined?(:ClassMethods, false) ?
const_get(:ClassMethods) :
const_set(:ClassMethods, Module.new)
# extend后,调用class_methods方时将块里的定写入到ClassMethods里
mod.module_eval(&class_methods_module_definition)
end
end
end