about append_features method

在写上一篇关于concern的deprecated文章时,还发现两个有意思的东西,一并记录下来。

append_features

When this module is included in another, Ruby calls append_features in this module, passing it the receiving module in mod. Ruby’s default implementation is to add the constants, methods, and module variables of this module to mod if this module has not already been added to mod or one of its ancestors. See also Module#include.

我们知道extended和included是ruby的两个hook方法,原来include勾的就是这个append_features方法。

Module,Class的comparation

在`append_features`中有一句代码很简单,但却值得玩味:

def append_features(base)
  ...
  return false if base < self
  ...
end

原来module还可以比较:

mod <=> other_mod → -1, 0, +1, or nil

Comparison—Returns -1 if mod includes other_mod, 0 if mod is the same as other_mod, and +1 if mod is included by other_mod. Returns nil if mod has no relationship with other_mod or if other_mod is not a module.

但是

这里用来判断是否有继承关系,比较巧妙,如果base继承至self,说明方法已经在方法链上了,直接return false。

The InstanceMethods module inside ActiveSupport::Concern will be no longer included automatically

The InstanceMethods module inside ActiveSupport::Concern will be no longer included automatically. Please define instance methods directly in …

今天在一个Rails3.2的项目里发现了这个deprecated,去查看了一下源码,大家可以比较一下:

对比了,发现只是少了这么一句:

base.send :include, const_get("InstanceMethods")

不需要再定义InstanceMethods Module了,直接定义这些方法就行了。#Commit

old

module M
  extend ActiveSupport::Concern

  module ClassMethods
    ...
  end

  module InstanceMethods
    def some_instance_method
      ...
    end
  end
end

new

module M
  extend ActiveSupport::Concern

  module ClassMethods
    ...
  end
 
  # directly define method
  def some_instance_method
    ...
  end

end

Why?

ruby的include行为就是引入instance method,用InstanceMethods确实有点多此一举,不过我想老的版本引入InstanceMethods应该是为了和ClassMethods对应。