【发布时间】:2010-12-17 21:31:47
【问题描述】:
ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
我只是想从某个目录访问 .rb 文件,教程告诉我使用此代码,但我看不到它是如何找到 gem 文件的。
【问题讨论】:
标签: ruby
ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
我只是想从某个目录访问 .rb 文件,教程告诉我使用此代码,但我看不到它是如何找到 gem 文件的。
【问题讨论】:
标签: ruby
File.expand_path('../../Gemfile', __FILE__)
是一个有点难看的 Ruby 习惯用法,用于在您知道相对于当前文件的路径时获取文件的绝对路径。另一种写法是这样的:
File.expand_path('../Gemfile', File.dirname(__FILE__))
两者都很丑,但第一个变体更短。然而,第一个变体在你掌握它之前也是非常不直观的。为什么要多出..? (但第二个变体可能会为为什么需要它提供线索)。
它是这样工作的:File.expand_path 返回第一个参数的绝对路径,相对于第二个参数(默认为当前工作目录)。 __FILE__ 是代码所在文件的路径。由于本例中的第二个参数是文件路径,而 File.expand_path 假定为目录,因此我们必须在路径中添加一个额外的 .. 才能获取正确的路径。它是这样工作的:
File.expand_path基本上是这样实现的(在下面的代码中path的值为../../Gemfile,relative_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__))。
【讨论】:
File.expand_path('../Gemfile',__dir__)
File.expand_path assumes a directory,尽管__FILE__ 不是目录。为了有意义,请使用__dir__,它实际上是一个目录。
两个参考:
我今天偶然发现了这个:
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
【讨论】: