为啥 Ruby 1.9.2 删除“。”来自 LOAD_PATH,还有啥替代方案?

Posted

技术标签:

【中文标题】为啥 Ruby 1.9.2 删除“。”来自 LOAD_PATH,还有啥替代方案?【英文标题】:Why does Ruby 1.9.2 remove "." from LOAD_PATH, and what's the alternative?为什么 Ruby 1.9.2 删除“。”来自 LOAD_PATH,还有什么替代方案? 【发布时间】:2011-02-23 10:18:15 【问题描述】:

Ruby 1.9.2 的最新变更集不再使当前目录 . 成为您的 LOAD_PATH 的一部分。我有很多 Rakefiles 假设.LOAD_PATH 的一部分,所以这破坏了它们(他们报告“没有这样的文件要加载”对于基于项目路径的所有要求语句)。这样做有什么特别的理由吗?

至于修复,在任何地方添加$: << "." 都可以,但看起来非常老套,我不想这样做。使我的 Rakefiles 1.9.2+ 兼容的首选方法是什么?

【问题讨论】:

【参考方案1】:

这被视为“安全”风险。

你可以通过使用绝对路径来绕过它

File.expand_path(__FILE__) et al

或正在做

require './filename' (ironically).

或使用

require_relative 'filename'

或添加“包含”目录

ruby -I . ...

或相同,使用 irb;

$irb -I .

【讨论】:

我最终使用了require_relative。谢谢。 这是否类似于大多数 unix 不包括运行可执行文件路径中的当前目录? require './filename' 仅在您的脚本在工作目录设置为与脚本所在目录相同的情况下执行时才有效。在多目录项目中通常不是这种情况。【参考方案2】:

正如 Jörg W Mittag 指出的那样,我认为您想要使用的是 require_relative,因此您需要的文件是相对于 require 声明的源文件而不是当前工作目录。

您的依赖项应该与您的 rake 构建文件相关。

【讨论】:

【参考方案3】:

使用require_relative 'file_to_require'

在你的代码中添加这个以使 require_relative 在 1.8.7 中工作:

unless Kernel.respond_to?(:require_relative)
  module Kernel
    def require_relative(path)
      require File.join(File.dirname(caller.first), path.to_str)
    end
  end
end

【讨论】:

【参考方案4】:

在我意识到一些事情之前,我发现这是一个令人困惑的变化。

您可以在 .profile (Unix) 中设置 RUBYLIB 并像以前一样继续生活:

export RUBYLIB="."

但如上所述,这样做一直被认为是不安全的。

对于绝大多数情况,您可以通过简单地调用您的 Ruby 脚本并在前面加上 '.' 来避免问题。例如./scripts/server.

【讨论】:

【参考方案5】:

正如其他答案指出的那样,这是一个安全风险,因为您的加载路径中的. 指的是当前工作目录Dir.pwd,而不是当前正在加载的文件的目录。因此,无论谁正在执行您的脚本,都可以通过 cding 将其更改为另一个目录。不好!

我一直在使用从 __FILE__ 构建的完整路径作为替代方案。

require File.expand_path(File.join(File.dirname(__FILE__), 'filename'))

require_relative 不同,它向后兼容 Ruby 1.8.7。

【讨论】:

还有这个变体(我个人觉得更易读):require Pathname.new(__FILE__).dirname + 'filename'【参考方案6】:

'.'在 Unix 世界中,你的路径长期以来一直被认为是一件坏事(例如,参见 http://www.faqs.org/faqs/unix-faq/faq/part2/section-13.html)。我认为 Ruby 的人已经被说服不这样做是明智的。

【讨论】:

【参考方案7】:

有两个原因:

稳健性和 安全

两者都基于相同的基本原理:通常,当您的代码运行时,您根本无法知道当前目录是什么。这意味着,当您需要一个文件并依赖它位于当前目录中时,您无法控制该文件是否会存在,或者它是否是您实际希望存在的文件。

【讨论】:

我不认为强制两个文件相对于彼此位于同一位置是一个不好的要求。如果这是真的,那么我们就没有目录了。 @John Feminella:这与将文件放在相对于彼此的路径中有什么关系?问题是关于将它们相对于.,即当前工作目录。如果用户 cd 进入不同的目录,则当前工作目录会更改,并且您现在 require 完全 不同的文件取决于用户在调用您的脚本时碰巧所在的目录。我认为这不是一个好主意。 那么为了保持一个像样的界面,你应该这样做吗? $: << File.dirname(__FILE__) @Joshua Cheek:就个人而言,我不喜欢那样。 (但请不要看我的旧代码,因为它到处都是 :-))。我只是假装lib 目录位于$LOAD_PATH 上,然后是require 所有与lib 相关的文件。换句话说:我让管理员弄清楚如何正确设置$LOAD_PATH。如果你使用 RubyGems,这很简单,因为 RubyGems 会自动你,如果你使用 Debian 包,那么这是包维护者的工作。总而言之,它似乎工作得很好。 @Joshua Cheek:另外,作为从$LOAD_PATH 中删除. 的一种平衡,Ruby 1.9.2 引入了require_relative,这...令人惊讶...require sa文件相对于当前执行文件的位置(即相对于File.dirname(__FILE__))。

以上是关于为啥 Ruby 1.9.2 删除“。”来自 LOAD_PATH,还有啥替代方案?的主要内容,如果未能解决你的问题,请参考以下文章

restclient为啥加不上heads

如何从 Ruby 1.9.2 降级到 Ruby 1.8.7 以运行 Rails 2.0.2

如何在 1.9.2 中分析 Ruby 代码?

来自 C# 的 mingw DLL:为啥我必须覆盖新/删除?

Ruby:mysql2-Gem 不工作(Mac OS X Snow Leopard,Ruby 1.9.2)

有没有办法使用内存分配报告来分析 ruby​​ 1.9.2 脚本?