Rails源码阅读(13)rails中的autoload和ruby的autoload
ruby的autoload
Registers filename to be loaded (using Kernel::require
) the first time that module (which may be a String
or a symbol) is accessed in the namespace of mod.
module A end A.autoload(:B, "b") A::B.doit # autoloads "b"
可以看出是在 Kernel中的方法。
rails的autoload
在active_support中
gems/activesupport-3/lib/active_support/dependencies/autoload.rb
def autoload(const_name, path = @@at_path) full = [self.name, @@under_path, const_name.to_s, path].compact.join("::") location = path || Inflector.underscore(full) if @@eager_autoload @@autoloads[const_name] = location end super const_name, location end
rails重写了这个方法。
做了两件事情:
#1 如果path已经被指定了,即代码作者已经指定了load file,则走ruby默认的方法,即代码中的super
#2 如果path麽有指定,则以当前的Module名字为作用域,加上const_name以及其他的一些东西(见文件的其他代码),拼接成一个文件名字。
简而言之,如果没有指定path,则从当前的命名空间内找那个文件。寻找方法其实就是rails通用的方法,从这点上来看,仍然遵守了rails的“一致性”。
第二点是要注意很容易出错,即只有在path没有指定情况下才走rails的机制。如果指定了path就不走这套机制了,一定注意。
比如下面的写法:
class A require "active_support/all" extend ActiveSupport::Autoload autoload :B, "b" end
加载哪个文件呢?
如果认为是加载 a/b 文件就错了。注意这里path不是空。
正确答案是加载”b“文件,和ruby的机制一样。
rails为什么不做成总是在当前的命名空间内找呢?
因为这破坏了默认的ruby的机制。
这样导致很多不用active_support的gem就没法工作了。
比如:
# Captcha-Plugin for Rails module EasyCaptcha autoload :Espeak, 'easy_captcha/espeak' 。。。 end
如果用rails的机制,那就得加载文件”easy_captcha/easy_captcha/espeak“了,这是致命的。
rails只好这样做,如果你指定了path,就走原机制吧。
小姐:
rails的auto_load只是补充了一下path为空的情况下的常量寻找方法。其他的没有变。别用混了。
好处是什么?
懒人原则和默认原则和一致性原则。
如果我不写,大家都知道在哪里(遵循rails的原则)。
如果我写了,那就覆盖默认原则,使用我写的。
其他补充
其实造rails的人更懒,才造就了rails。就像这个autoload一样,源码里还有不少辅助方法,专门给懒人用的,如果写的时候觉得重复代码不少,就可以看看源码了,懒的程序员一般想的都差不多。
+
=
-
-
=
+