ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
我只是想访问一个.rb文件来自某个目录,一个教程告诉我如何使用这段代码,但我不知道它是如何找到gem文件的.
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
的值为../../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
,然后循环中的每一轮都将删除前..
,以及之前的路径分量.先go 掉/file.rb/..
,然后在下一轮go 掉/to/..
,我们得到/path/Gemfile
.
长话短说,当你知道一个文件相对于当前文件的路径时,File.expand_path('../../Gemfile', __FILE__)
是一个获取文件绝对路径的技巧.相对路径中的额外..
用于删除__FILE__
中的文件名.
在Ruby 2.0中,有一个名为__dir__
的Kernel
函数被实现为File.dirname(File.realpath(__FILE__))
.