2011年9月21日星期三

ActiveSupport中的class_attribute

看rails guide的时候遇到了Class#class_attribute,怎么使用参见guide和下面两篇文章,这里不做介绍
http://blog.obiefernandez.com/content/2010/04/tr3w-highlights-activesupport-class-class-attribute.html
http://ihower.tw/blog/archives/4878

在看源码的时候,发现第79行怎么都不能理解,为什么是
singleton_class.#{name}
而不是
self.class.#{name}
呢?

由于我看的是3.0.7的版本,于是又找到了最新的3.1.0的版本
看完之后更加迷惑,为什么要定义两个reader instance method,一个用singleton_class,一个用self.class呢?

查阅了相关资料,翻看了源码提交记录,我找到了答案。
其实本来在3.0.7版本中用self.class代替singleton_class是可以的,但为了支持在singleton_class上调用writer方法
klass = Class.new { class_attribute :setting }
object = klass.new
object.singleton_class.setting = "foo"
所以用了singleton_class。

由于object的singleton_class的superclass是klass,singleton_class自己又没定义过setting=(),所以singleton_class.setting=()还是会查找到klass里的定义并调用它。

实际使用的时候,大部分情况还是object.setting=()而不是object.singleton_class.setting=(),为每个object创建singleton_class开销较大,所以做了优化:object调用时直接查找self.class,避开了singleton_class。而针对singleton_class另做处理,由于方法查找时singleton_class优先于klass,所以
def #{name}
defined?(@#{name}) ? @#{name} : singleton_class.#{name}
end
会覆盖
def #{name}
defined?(@#{name}) ? @#{name} : self.class.#{name}
end

最后的问题是,谁引入的对singleton_class的支持呢?翻提交记录的时候找到了答案