为什么人们在模块定义中使用extend?

时间:2011-07-22 09:10:41

标签: ruby

例如,rubygem Devise lib/devise/controllers/helpers.rb

中包含以下代码段
    module Helpers
      extend ActiveSupport::Concern

为什么在这里使用extendinclude会做同样的事吗?

2 个答案:

答案 0 :(得分:3)

不,include不会这样做。

extendinclude执行类似但不同的角色。 include获取包含模块的实例方法,并使其可用于包含模块的实例。实际上,include将包含的模块作为包含的超类插入(事实上,#ancestors甚至会显示包含的模块。)

另一方面,

extend将命名模块的方法添加到接收器。在模块定义期间调用extend的情况下,这意味着“扩展”模块的实例方法将成为“扩展”模块的类方法。它通常用于将装饰器(实际上只是对类方法的调用)导入到正在定义的类或模块中。

因此,简而言之,上面的代码段将采用ActiveSupport::Concern的实例方法,并使它们成为Helpers的类方法。

答案 1 :(得分:2)

基本上,Object#extend只是:

class Object
  def extend(*ms)
    ms.each do |m|
      class << self
        include m # Obviously, this won't work since m isn't in scope
      end
    end
  end
end

因此,很容易看出它们显然相同,因为这些方法最终会出现在不同的类中。


正在运作,但不太明显的Object#extend版本将是:

class Object
  def extend(*ms)
    ms.each do |m|
      singleton_class.send :include, m # Because Module#include is private
    end
  end
end