新手问题 对 ActiveSupport::Concern 中 append_features 的疑问

monkeygq · February 25, 2017 · Last by bajiudongfeng replied at March 21, 2017 · 1400 hits

结合《Ruby 元编程》的例子写了如下代码,有几点疑问,感谢解答:

  1. 为什么 Concern 中的 append_features 会执行三次
  2. 链式包含问题如代码这样理解是否正确
module Concern
  def self.extended(base)
    p "extended:self=#{self},base=#{base}"
    base.instance_variable_set(:@_dependencies, []) 
  end 
  def append_features(base)
    if base.instance_variable_defined?(:@_dependencies)
      base.instance_variable_get(:@_dependencies) << self
      p "if:self=#{self},base=#{base},@=#{base.instance_variable_get(:@_dependencies)}"
      return false
    else
      return false if base < self
      p "else:self=#{self},@_dependencies=#{@_dependencies}"
      @_dependencies.each { |dep| base.include(dep) }
      super
      base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
    end 
  end 
end

module Myc2
  extend Concern
  def m3
    p "Myc2 instance method"
  end 
  module ClassMethods
    def m4
      p "Myc2 class method"
    end 
  end 
end

module Myc1
  extend Concern
  include Myc2
  def m1
    p "Myc1 instance method"
  end 
  module ClassMethods
    def m2
      p "Myc1 class method"
    end 
  end 
end

class Mytest
  include Myc1
end

输出如下:

"extended:self=Concern,base=Myc2"
"extended:self=Concern,base=Myc1"
"if:self=Myc2,base=Myc1,@=[Myc2]"
"else:self=Myc1,@_dependencies=[Myc2]"
"else:self=Myc2,@_dependencies=[]"

为什么三次?

Myc1.include Myc2; Mytest.inlcude Myc1; Mytest.include Myc2;

理解是否正确?

哪里有什么理解?

没有执行三次

class Mytest
  include Myc1
end
"else:self=Myc1,@_dependencies=[Myc2]"
"else:self=Myc2,@_dependencies=[]"

这个才是 class 包含的时候的结果。当 include Myc1 的时候调用 Myc1 的 append_features 的 else 部分。 此时 self 是 Myc1,base 是 Mytest.

@_dependencies.each { |dep| base.include(dep) }

这个是一个递归调用,相当于执行了 Mytest.include(Myc2)
因此会调用 Myc2 的 append_features
此时的 self 是 Myc2,base 是 Mytest,所以继续走 else 部分
但是此时数组@_dependencies是空的
因此直接走下边的 super,把 Myc2 放入 Mytest 的继承链中
直到 Myc2 的 append_features 运行结束
然后再回到 Myc1 的 append_features 中执行其 super 方法,把 Myc1 放入 Mytest 的继承链中。直到结束。

3 Floor has deleted
You need to Sign in before reply, if you don't have an account, please Sign up first.