Rails 想了解 require ” xx “, 或者 load "xx"真正的查找路径。

runup · 2017年09月13日 · 最后由 5long 回复于 2017年09月14日 · 1791 次阅读

一直对这个问题比较疑惑,根据 ruby api 的介绍,如果”xx“是绝对路径,则从绝对路径中查找,如果是相对路径,则会去$LOAD_PATH 中查找。我在自己的本地文件建立文件夹 test,test 文件夹的中存在两个文件,分别是 redflag.rb 文件和 test_events.rb 文件,文件内容分别如下:

#redflag.rb
def event(name)
  puts "ALTER: #{name}" if yield
end
Dir.glob("*events.rb").each{ |file| load file}

#test_events.rb
event "an event that always happens" do
  true
end
event "an event that never happens" do
  false
end

#终端执行文件,ruby reflag.rb

ALTER: an event that always happens

如上代码叙述,正确 load 了文件,并且执行了相关的代码。

test 文件夹的目录为:

/Users/jayzen/workshop/dsl

puts $LOAD_PATH 的结果为:

/Users/jayzen/.rvm/gems/ruby-2.4.0@global/gems/did_you_mean-1.1.0/lib
/Users/jayzen/.rvm/rubies/ruby-2.4.0/lib/ruby/site_ruby/2.4.0
/Users/jayzen/.rvm/rubies/ruby-2.4.0/lib/ruby/site_ruby/2.4.0/x86_64-darwin16
/Users/jayzen/.rvm/rubies/ruby-2.4.0/lib/ruby/site_ruby
/Users/jayzen/.rvm/rubies/ruby-2.4.0/lib/ruby/vendor_ruby/2.4.0
/Users/jayzen/.rvm/rubies/ruby-2.4.0/lib/ruby/vendor_ruby/2.4.0/x86_64-darwin16
/Users/jayzen/.rvm/rubies/ruby-2.4.0/lib/ruby/vendor_ruby
/Users/jayzen/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0
/Users/jayzen/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/x86_64-darwin16

从上面可知,load 的文件是相对目录,但是$LOAD_PATH 中并没有包括 test 的文件夹路径,那么 load 的真正加载路径是什么?

因为这两文件在同一文件夹下,所以可以 load 成功吧。

当前文件夹下找不到,再去 load_path 下找吧。

zhuoerri 回复

这样的解释是参考哪里?

不好意思,我解释错了,应该是跟执行 ruby 的进程的文件夹有关。参考如下的 require 例子

https://rubyplus.com/articles/4661-The-require-and-load-path-in-Ruby

zhuoerri 回复
Ruby process's current working directory  #ruby进程的当前工作目录

这句话怎么理解?

runup 回复

就是working directory啊。 https://en.wikipedia.org/wiki/Pwd

我自己也试了一下,目测 require()load() 的查找逻辑是不一样的。

  • require "./foo" 使用句点开头的参数:这只会找 $PWD。考虑到进程的工作目录可能被任意处代码修改,而且我们不能确定进程启动时的工作目录是啥(或者需要自己花时间去确定),我的建议是没有特殊情况不要用。
    • 或者我感觉这应该是 ruby 的未定义行为 / bug / 隐藏 feature,不用太当回事,更不能依赖它。
  • load "foo.rb"具体的路径查找逻辑我也不是太清楚。目前观察到的是:load "kramdown"load "kramdown.rb" 都只会抛出找不到模块的 LoadError,即使 require "kramdown" 是能正常加载的;以及$PWD 是会被查找的。
    • 反正常规的 require 用法加上 require_relative 已经够用了。实在有特殊需求的时候再调查 load 的行为不迟。但看来 load 并不是“可以重复加载的 require”。

当然源码才是 source of truth,直接去读源码最靠谱。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号