File.expand_path("../../ Gemfile",__ FILE__)这是如何工作的?文件在哪里?

the*_*gah 81 ruby

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

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

The*_*heo 190

File.expand_path('../../Gemfile', __FILE__)
Run Code Online (Sandbox Code Playgroud)

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

File.expand_path('../Gemfile', File.dirname(__FILE__))
Run Code Online (Sandbox Code Playgroud)

两者都很难看,但第一个变种更短.然而,第一个变体在你掌握它之前也是非常不直观的.额外的原因..?(但第二个变体可能提供了为什么需要它的线索).

这是它的工作原理: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
Run Code Online (Sandbox Code Playgroud)

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

单步调用上面的代码absolute_path将首先获取值/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__)).

  • 从Ruby 2.0开始,你可以使用`File.expand_path('../ Gemfile',__ dir __)` (9认同)
  • +1表示这是多么丑陋 - 对Ruby来说非常罕见 (4认同)
  • 除了与Ruby 1.9.2之前的不兼容之外,你有什么理由不应该只使用'require_relative'吗? (2认同)

Pat*_*ann 9

两个参考:

  1. File :: expand_path方法文档
  2. 如何__FILE__在Ruby 中工作

我今天偶然发现了这个:

在Rails Github中提交boot.rb

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

/ railties/lib目录/导轨/发电机/导轨/应用/模板

你看到Gemfile,这让我相信File.expand_path("../../Gemfile", __FILE__)文件后面的引用:/path/to/this/file/../../Gemfile