require 会按照$LOAD_PATH 中的路径来加载,但是 gems 路径并不在$LOAD_PATH 中,为什么也可以加载的到呢?
load 方法:
$LOAD_PATH:
- $LOAD_PATH 中存储了一组目录的绝对路径,对于 load 和 require 方法来说,如果方法参数只是一个不带路径的文件名的话,这时候就会去$LOAD_PATH 中定义的路径中去查找
默认的 require:
- 与 load 最大的不同是不会加载同一个文件两次,多次 require 同一个文件只会加载一次,所有被加载过的文件,都会记录在一个全局变量$LOADED_FEATURES 中,不论是 load 还是 require,都无法在不加路径(相对路径,绝对路径)的情况下直接加载文件,因为当前路径不在$LOAD_PATH 中
rubygems 中的 require,gems 是如何加载的呢?
- rubygems是安装ruby是会默认一同安装的库,并且在启动ruby时会默认加载,比如启动irb之后,通过查看$LOADED_FEATURES就会发现,已经有很多.rb文件被加载进来了,ruby默认的Kernel#require这个方法已经被rubygems重写了
- 打开该文件会发现,该文件正是重写了默认的Kernel#require方法:
Kernel#gem方法:
- 如果同时安装了一个 gem 的多个版本,比如 rails-6.0.3.7 和 rails-6.0.3.6,那么通过gem方法,可以将指定的gem的路径存入$LOAD_PATH,这样子之后在require该gem的时候,也就能按照指定的版本来加载了,上面的Kernel#require方法实际也是使用了gem方法,来将gem的路径放入$LOAD_PATH
rails 中加载 gems:
- 在 rails 的初始化加载/启动加载文件中 (比如 config/boot.rb),会加载 bundler,我这里看到的是加载了 bundler/setup 这个文件,bundler/setup 的目的就是用来加载 Gemfile 中列出的 gem,执行流程大致是:
- 1.读取 Gemfile.lock 文件,根据 Gemfile.lock 文件中 spec 下的描述,获取该项目所需加载的 gem 的名称以及版本号
- 2.调用 gem 方法,来激活该 gem,也就是将 gem 的相关路径加入到$LOAD_PATH
- 3.最后在 application.rb 中,调用 Bundler.require,这个时候由于$LOAD_PATH 中已经存入了定义好的目录,所以 require 可以顺利的加载