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.
é 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:
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_pathretorna 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_pathassume 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 pathterá o valor de ../../Gemfilee relative_toterá 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_pathobterá 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 Kernelfunção chamada __dir__que é implementada como File.dirname(File.realpath(__FILE__)).
Existe alguma razão pela qual você não deve apenas usar 'require_relative' diferente de incompatibilidade com Ruby 1.9.2 anterior?
Danny Andrews
9
A partir do Ruby 2.0, você pode usarFile.expand_path('../Gemfile',__dir__)
Phrogz
Esta linha de Theo finalmente conseguiu clicar para mim 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.
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
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 eFile.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 seguirpath
terá o valor de../../Gemfile
erelative_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 comoFile.dirname(File.realpath(__FILE__))
.fonte
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:
__FILE__
funciona em RubyMe 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
fonte