ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)

我只是想访问一个.rb文件来自某个目录,一个教程告诉我如何使用这段代码,但我不知道它是如何找到gem文件的.

推荐答案

File.expand_path('../../Gemfile', __FILE__)

是一个有点难看的Ruby习惯用法,用于在知道相对于当前文件的路径时获取文件的绝对路径.另一种写作方式是:

File.expand_path('../Gemfile', File.dirname(__FILE__))

两者都很难看,但第一种变体较短.然而,在掌握窍门之前,第一种变体也是非常不直观的.为什么要多加..?(但第二种变体可能会给出为什么需要它的线索).

其工作原理如下:File.expand_path返回第一个参数相对于第二个参数(默认为当前工作目录)的绝对路径.__FILE__是代码所在文件的路径.由于本例中的第二个参数是一个文件的路径,File.expand_path假设一个目录,因此我们必须在路径中多加一个..以获得正确的路径.这就是它的工作原理:

File.expand_path基本上是这样实现的(在下面的代码中,path的值为../../Gemfilerelative_to的值为/path/to/file.rb):

def File.expand_path(path, relative_to=Dir.getwd)
  # first the two arguments are concatenated, with the second argument first
  absolute_path = File.join(relative_to, path)
  while absolute_path.include?('..')
    # remove the first occurrence of /<something>/..
    absolute_path = absolute_path.sub(%r{/[^/]+/\.\.}, '')
  end
  absolute_path
end

(还有一点,它将~扩展到主目录,等等——上面的代码可能还有一些其他问题)

单步调用absolute_path以上的代码将首先得到值/path/to/file.rb/../../Gemfile,然后循环中的每一轮都将删除前..,以及之前的路径分量.先go 掉/file.rb/..,然后在下一轮go 掉/to/..,我们得到/path/Gemfile.

长话短说,当你知道一个文件相对于当前文件的路径时,File.expand_path('../../Gemfile', __FILE__)是一个获取文件绝对路径的技巧.相对路径中的额外..用于删除__FILE__中的文件名.

在Ruby 2.0中,有一个名为__dir__Kernel函数被实现为File.dirname(File.realpath(__FILE__)).

Ruby相关问答推荐

Ruby 中使用的-S标志是什么?

如何在 Shopify 脚本编辑器中显示数组值?

如何过滤散列数组以仅获取另一个数组中的键?

Ruby 中有内置的二进制搜索吗?

Ruby 中是否有像 C 中一样的主要方法?

使用 Ruby MiniTest 之前/之后的套件

Ruby 中的排序稳定吗?

符号到字符串问题

class_eval、class_exec、module_eval 和 module_exec 有什么区别?

如何仅从 Gemfile 中查看依赖关系树?

条件子句中的赋值是好的Ruby风格吗?

比较两个数组忽略Ruby中的元素顺序

在 Ruby 中按名称获取一个类?

rbenv、rvm 和 chruby 有什么区别?

在 Ruby 中打开默认浏览器

使用整数作为哈希键

OpenSSL vs GPG 用于加密异地备份?

为什么 __FILE__ 大写而 __dir__ 小写?

Ruby 疯狂:类与对象?

如何重命名 gemset?