Rails源码翻阅(13)rails中的autoload和ruby的autoload

Rails源码阅读(13)rails中的autoload和ruby的autoload

Rails源码阅读(13)rails中的autoload和ruby的autoload

 

ruby的autoload

autoload(module, filename) → nilclick to toggle source

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为空的情况下的常量寻找方法。其他的没有变。

    别用混了。

 

 

+

=

-

-

=

+