为什么Ruby'不需要'允许相对路径?

时间:2015-07-06 23:53:45

标签: ruby

This SO post通过声称require只会相对于运行脚本的路径进行搜索来回答问题。但这确实不会出现真正。我会详细说明。

我创建了一个快速C扩展并将其编译为mytest.so。然后,在同一目录中,我启动了irb

irb(main):009:0> require 'mytest.so'
LoadError: cannot load such file -- mytest.so

这是预期的,因为另一个答案中的声明是require正在搜索相对于irb的运行位置。在我的情况下,这将是/usr/bin/irb。所以我尝试了另一个问题的required_relative解决方案:

irb(main):006:0> require_relative './mytest.so'
LoadError: cannot infer basepath

没有运气。而且,仅供参考 - mytest.so在此填写标签,因此irb清楚地知道它位于当前工作目录中。此外,我可以很容易地证明这一点:

irb(main):004:0> system("pwd")
/home/mike/Documents/ruby_test
# => true
irb(main):005:0> File.expand_path("./")
# => "/home/mike/Documents/ruby_test"

好的最后一次测试,我会假设irb正在/usr/bin 中执行,尽管指出了相反的证据。

irb(main):011:0> require '../../home/mike/Documents/ruby_test/mytest.so'
LoadError: cannot load such file -- ../../home/mike/Documents/ruby_test/mytest.so

如果有人能对require发生的事情有所了解,我将不胜感激。

顺便说一句,我知道我可以通过提供确切的文件路径来解决这个问题。这个问题是关于尝试理解表面下发生的事情。

require '/home/mike/Documents/ruby_test/mytest.so' # this works

2 个答案:

答案 0 :(得分:3)

tl;博士:IRB很特别,有一些奇怪的规则。 Ruby通常可以很好地处理相对路径。

require将搜索加载路径(您可以通过检查$:$LOAD_PATH来查看)。这不包括您从以下位置启动IRB的目录:

> $:
 => ["/usr/local/rvm/rubies/jruby-head/lib/ruby/2.2/site_ruby", "/usr/local/rvm/rubies/jruby-head/lib/ruby/stdlib"]

除非你明确地将你的目录添加到加载路径,否则没有任何乐趣。这就是Rubygems和Bundler花费大部分时间做的事情 - 他们管理宝石的负载路径,因此您不必担心它。但是,这对单个文件没有帮助。

此外,require_relative将从__FILE__所在的目录中进行搜索,但在IRB中,这是一个非目录(irb)值!这就是为什么你得到了"无法推断出基本路径"从IRB尝试require_relative时出现问题;由于当前正在执行的文件__FILE__不是正确的路径,require_relative无法确定从哪里开始。

当你没有从IRB运行时,这不是一个真正的问题;当您在脚本中执行它时,require_relative 'mytest.so'应该可以正常工作,因为当前正在执行的脚本将填充__FILE__。也就是说,如果您有loader.rbmytest.so并通过ruby loader.rb执行加载,那么require_relative应该可以正常工作。

如果您想在IRB中运行此功能,请考虑以下内容:

require "#{__dir__}/mytest.so"

将扩展到当前工作目录,默认情况下应该是您从中启动它的目录。我建议您不要在脚本中执行此操作,因为它取决于__dir__未被更改,并且可能难以保证。

答案 1 :(得分:0)

来自documentation

  

加载给定名称,成功时返回true,如果成功则返回false   功能已加载。

     

如果文件名没有解析为绝对路径,那么它就是   在$ LOAD_PATH($:)。

中列出的目录中搜索      

如果文件名的扩展名为“.rb”,则将其作为源加载   文件;如果扩展名为“.so”,“。o”或“.dll”,则为默认值   在当前平台上共享库扩展,Ruby加载   共享库作为Ruby扩展。否则,Ruby会尝试添加   “.rb”,“。so”等等,直到找到名称。如果文件名为   无法找到,将引发LoadError。

     

对于Ruby扩展,给定的文件名可以使用任何共享库   延期。例如,在Linux上,套接字扩展名为“socket.so”   并要求'socket.dll'将加载套接字扩展。

     

加载文件的绝对路径将添加到$ LOADED_FEATURES   ($“)。如果文件的路径已经出现,则不会再次加载文件   $“。例如,要求'a';要求'./a'不会再次加载a.rb。

你的问题的答案是,它根本不适合。

如果您想要相对于文件路径的文件,可以使用require_relative

您可以将项目库文件夹添加到$LOAD_PATH以获取您要求的功能,即require 'my_library'

在IRB中加载本地文件,您可能希望使用load,因为它使您能够多次加载文件/库,其中require只会加载文件/库一次。 __FILE__变量在IRB中工作就像它应该的那样。它是调用变量的文件的标识(在本例中是打开过程)。