File.expand_path(“ ../../ Gemfile”,__FILE__)如何工作?文件在哪里?


84

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

我只是想从某个目录访问.rb文件,一个教程告诉我使用此代码,但我看不到它如何找到gem文件。


Answers:


194
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将首先获取value /path/to/file.rb/../../Gemfile,然后对于循环中的每一回合,..将删除第一回合,以及位于其之前的路径组件。首先/file.rb/..被删除,然后在下一轮/to/..被删除,我们得到/path/Gemfile

长话短说,这File.expand_path('../../Gemfile', __FILE__)是一个技巧,当您知道相对于当前文件的路径时,获取文件的绝对路径。..相对路径中的多余项是消除了中的文件名__FILE__

在Ruby 2.0中,有一个Kernel称为的函数__dir__,该函数的实现为File.dirname(File.realpath(__FILE__))


2
除了与Ruby 1.9.2之前的版本不兼容之外,有什么理由不应该只使用'require_relative'吗?
丹尼·安德鲁斯

9
从Ruby 2.0开始,您可以使用File.expand_path('../Gemfile',__dir__)
Phrogz,2016年

File.expand_path assumes a directory尽管__FILE__不是目录,但Theo的这一行终于让我点击了。为了使事情有意义,请使用__dir__实际上是目录。
mbigras

9

两个参考:

  1. File :: expand_path方法文档
  2. __FILE__Ruby中的工作方式

我今天偶然发现了这一点:

boot.rb在Rails Github中提交

如果从目录树中的boot.rb上找到两个目录:

/ railties / lib / rails / generators / rails / app / templates

您会看到Gemfile,这使我相信File.expand_path("../../Gemfile", __FILE__)引用了以下文件:/path/to/this/file/../../Gemfile


感谢您的帖子,但这来自gembundler教程,所以我试图确切地了解他们的
感受
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.