ActiveSupport源代码研究之 ActiveSupport::Concern

本文深入研究了ActiveSupport库中的Concern模块,探讨了如何简化self.included方法,实现模块间方法的互相调用,并确保代码正确运行。接下来将继续分析Concern的更多源代码细节。
摘要由CSDN通过智能技术生成
ActiveSupport::Concern 用于模块的引用,具体有两个应用:
  1.   简化 self.included 方法
  2.   用于模块之间方法的相互调用

1, 简化 self.included 方法
module M
  def self.included(base)
    base.class_eval do  
      def self.method_m 
        puts "method_m calling----------"
      end 
    end 
  end 
end

使用concern的代码
require 'active_support/concern'

module M
  extend ActiveSupport::Concern

  included do
    class_eval do     
      def self.method_m
        puts "method_m calling----------"
      end
    end
  end

end


2, 有两个module:A 和 B, A定义了一个方法: method_a,  B引用了method_a , 然后  class C 需要应用 B ,该如何做?
module A
  def self.included(base)
    base.extend ClassMethods
  end 

  module ClassMethods
    def method_a 
      puts "method_a calling -------------"
    end 
  end 
end

module B
  include A

  def self.included(base)
    base.method_a
  end 
end

class C
  include B
end

如上代码是与错误的,提示如下:
concern2.rb:17:in `included': undefined method `method_a' for C:Class (NoMethodError)
原因是 base 是  class c , 而 C 根本没有定义 method_a , 修改 C 的代码
class C
  include A
  include B
end

在C中需要 先引入 A,才能引入 B,因为B依赖 A,显然这种方式不是很合适。不应该由调用对象C来关注这些因素。 引入 ActiveSupport::Concern的代码如下:

require 'active_support/concern'

module A
  extend ActiveSupport::Concern

  module ClassMethods
    def method_a 
      puts "method_a calling -------------"
    end 
  end 
end

module B
  extend ActiveSupport::Concern
  include A

  included do  
    self.method_a
  end
end

class C
  include B
end

运行正确!

接着应该分析 concern的源码。。。


module ActiveSupport
  module Concern
    def self.extended(base)
      base.instance_variable_set("@_dependencies", [])
    end

    def append_features(base)
      if base.instance_variable_defined?("@_dependencies")
        base.instance_variable_get("@_dependencies") << self
        return false
      else
        return false if base < self
        @_dependencies.each { |dep| base.send(:include, dep) }
        super
        base.extend const_get("ClassMethods") if const_defined?("ClassMethods")
        base.class_eval(&@_included_block) if instance_variable_defined?("@_included_block")
      end
    end

    def included(base = nil, &block)
      if base.nil?
        @_included_block = block
      else
        super
      end
    end
  end
end

用test_unit来测试一下吧

require 'test/unit'
require 'active_support/concern'

class ConcernTest < Test::Unit::TestCase

  def test_dependencies
    dependencies = Bar.instance_variable_get("@_dependencies")
    assert dependencies 
	assert dependencies.is_a?Array
	assert_equal 1, dependencies.size
	assert_equal Foo, dependencies.first
	assert A.respond_to? :method_foo
  end

end

module Foo
  extend ActiveSupport::Concern

  included do 
    def self.method_foo; puts "method_foo"; true;end
  end
end

module Bar
  extend ::ActiveSupport::Concern

  include Foo

  included do 
    self.method_foo
  end
end

class A
  include Bar
end


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值