ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
Estou apenas tentando acessar um arquivo .rb de algum diretório e um tutorial está me dizendo para usar este código, mas não vejo como ele encontra o arquivo gem.
ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
Estou apenas tentando acessar um arquivo .rb de algum diretório e um tutorial está me dizendo para usar este código, mas não vejo como ele encontra o arquivo gem.
Respostas:
File.expand_path('../../Gemfile', __FILE__)
é um idioma Ruby um tanto feio para obter o caminho absoluto para um arquivo quando você conhece o caminho relativo ao arquivo atual. Outra maneira de escrever é esta:
File.expand_path('../Gemfile', File.dirname(__FILE__))
ambos são feios, mas a primeira variante é mais curta. A primeira variante, no entanto, também é muito não intuitiva até que você pegue o jeito. Por que o extra ..
? (mas a segunda variante pode dar uma pista de por que é necessário).
Funciona assim: File.expand_path
retorna o caminho absoluto do primeiro argumento, relativo ao segundo argumento (que é padronizado para o diretório de trabalho atual). __FILE__
é o caminho para o arquivo em que o código está. Como o segundo argumento, neste caso, é um caminho para um arquivo e File.expand_path
assume um diretório, temos que inserir um item extra ..
no caminho para obter o caminho correto. É assim que funciona:
File.expand_path
é basicamente implementado assim (no código a seguir path
terá o valor de ../../Gemfile
e relative_to
terá o valor de /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
(há um pouco mais, ele se expande ~
para o diretório inicial e assim por diante - provavelmente também há alguns outros problemas com o código acima)
Percorrer uma chamada para o código acima absolute_path
obterá primeiro o valor e /path/to/file.rb/../../Gemfile
, em seguida, para cada rodada no loop, a primeira ..
será removida, junto com o componente de caminho antes dela. Primeiro /file.rb/..
é removido, então na próxima rodada /to/..
é removido e nós obtemos /path/Gemfile
.
Para encurtar a história, File.expand_path('../../Gemfile', __FILE__)
é um truque para obter o caminho absoluto de um arquivo quando você conhece o caminho relativo ao arquivo atual. O extra ..
no caminho relativo é eliminar o nome do arquivo em __FILE__
.
No Ruby 2.0, existe uma Kernel
função chamada __dir__
que é implementada como File.dirname(File.realpath(__FILE__))
.
File.expand_path('../Gemfile',__dir__)
File.expand_path assumes a directory
, embora __FILE__
não seja um diretório. Para que as coisas façam sentido, use o __dir__
que na verdade é um diretório.
Duas referências:
Me deparei com isso hoje:
boot.rb commit no Rails Github
Se você subir dois diretórios de boot.rb na árvore de diretórios:
/ railties / lib / rails / generators / rails / app / templates
você vê Gemfile, o que me leva a acreditar que faz File.expand_path("../../Gemfile", __FILE__)
referência ao seguinte arquivo:/path/to/this/file/../../Gemfile