【问题标题】:File.expand_path("../../Gemfile", __FILE__) How does this work? Where is the file?File.expand_path("../../Gemfile", __FILE__) 这是如何工作的?文件在哪里?
【发布时间】:2010-12-17 21:31:47
【问题描述】:

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

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

【问题讨论】:

标签: ruby


【解决方案1】:
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,然后对于循环中的每一轮,第一个.. 将与它之前的路径组件一起被删除。首先/file.rb/..被删除,然后在下一轮/to/..被删除,我们得到/path/Gemfile

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

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

【讨论】:

  • 除了与 Ruby 1.9.2 之前的不兼容之外,还有什么理由不应该只使用“require_relative”?
  • 从 Ruby 2.0 开始,您可以使用 File.expand_path('../Gemfile',__dir__)
  • Theo 的这句话终于让我点击了File.expand_path assumes a directory,尽管__FILE__ 不是目录。为了有意义,请使用__dir__,它实际上是一个目录。
【解决方案2】:

两个参考:

  1. File::expand_path method documentation
  2. How does __FILE__ work in Ruby

我今天偶然发现了这个:

boot.rb commit in the Rails Github

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

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

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

【讨论】:

  • 感谢您的帖子,但这来自 gembundler 教程,所以我试图准确地理解它是如何获得它的 :)
猜你喜欢
  • 1970-01-01
  • 2011-05-18
  • 1970-01-01
  • 2011-03-23
  • 2016-09-28
  • 2021-01-10
  • 1970-01-01
  • 1970-01-01
  • 2019-03-24
相关资源
最近更新 更多