【问题标题】:Why doesn't Ruby 'require' allow relative paths?为什么 Ruby 'require' 不允许相对路径?
【发布时间】:2015-07-06 23:53:45
【问题描述】:

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

【问题讨论】:

  • 我在猜测,但我认为您获得了接近投票,因为声明和意见“如此令人困惑”,但如果您删除它或将其更改为令人困惑,而不是一般莫名其妙,那么它不再是一个意见...... :)
  • @vgoff 感谢您的建议,我删除了那部分
  • 我很好奇require './mytest.so 是否有效?这通常适用于 irb。

标签: ruby


【解决方案1】:

tl;dr: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 大部分时间都在做的事情——他们管理 gem 的加载路径,因此您不必担心。但是,这对单个文件没有帮助。

另外,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__ 未被更改,这可能很难保证。

【讨论】:

    【解决方案2】:

    来自documentation

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

    如果文件名不能解析为绝对路径,它将是 在 $LOAD_PATH ($:) 中列出的目录中搜索。

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

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

    加载文件的绝对路径添加到$LOADED_FEATURES ($"). 如果文件的路径已经出现在 $"。例如 require 'a';require './a' 不会再次加载 a.rb。


    你的问题的答案是它根本不是设计的。

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

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

    在加载本地文件的 IRB 中,您可能希望使用 load,因为它使您能够多次加载文件/库,而 require 将只加载文件/库一次。 __FILE__ 变量在 IRB 中正常工作。它是调用变量的文件(在本例中为打开进程)的标识。

    【讨论】:

      猜你喜欢
      • 2016-05-01
      • 2012-01-28
      • 2014-10-08
      • 2011-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多