File.expand_path ("../../ Gemfile", __FILE__) Come funziona? Dov'è il file?


84

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

Sto solo cercando di accedere a un file .rb dalla directory some e un tutorial mi dice di usare questo codice ma non vedo come sta trovando il file gem.


1
Vedi anche la domanda stackoverflow.com/questions/4333286
Theo

Risposte:


195
File.expand_path('../../Gemfile', __FILE__)

è un idioma Ruby un po 'brutto per ottenere il percorso assoluto di un file quando si conosce il percorso relativo al file corrente. Un altro modo per scriverlo è questo:

File.expand_path('../Gemfile', File.dirname(__FILE__))

entrambi sono brutti, ma la prima variante è più corta. La prima variante è, tuttavia, anche molto non intuitiva finché non ci si prende la mano. Perché l'extra ..? (ma la seconda variante può dare un indizio sul motivo per cui è necessaria).

Funziona così: File.expand_pathrestituisce il percorso assoluto del primo argomento, relativo al secondo argomento (che per impostazione predefinita è la directory di lavoro corrente). __FILE__è il percorso del file in cui si trova il codice. Poiché il secondo argomento in questo caso è un percorso di un file e File.expand_pathpresuppone una directory, dobbiamo inserire un extra ..nel percorso per ottenere il percorso corretto. È così che funziona:

File.expand_pathè fondamentalmente implementato in questo modo (nel codice seguente pathavrà il valore di ../../Gemfilee relative_toavrà il valore di /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

(c'è qualcosa in più, si espande ~nella directory home e così via - probabilmente ci sono anche altri problemi con il codice sopra)

Passando attraverso una chiamata al codice sopra absolute_pathsi otterrà prima il valore /path/to/file.rb/../../Gemfile, quindi per ogni round nel ciclo il primo ..verrà rimosso, insieme al componente percorso prima di esso. Il primo /file.rb/..viene rimosso, quindi il round successivo /to/..viene rimosso e otteniamo /path/Gemfile.

Per farla breve, File.expand_path('../../Gemfile', __FILE__)è un trucco per ottenere il percorso assoluto di un file quando si conosce il percorso relativo al file corrente. L'extra ..nel percorso relativo è eliminare il nome del file in __FILE__.

In Ruby 2.0 c'è una Kernelfunzione chiamata __dir__che è implementata come File.dirname(File.realpath(__FILE__)).


2
C'è qualche motivo per cui non dovresti usare solo "require_relative" a parte l'incompatibilità con le versioni precedenti a Ruby 1.9.2?
Danny Andrews

9
A partire da Ruby 2.0 puoi usareFile.expand_path('../Gemfile',__dir__)
Phrogz

Questa linea di Theo finalmente è riuscita a farmi clic File.expand_path assumes a directory, anche se __FILE__non è una directory. Affinché le cose abbiano un senso usa __dir__che in realtà è una directory.
mbigras

9

Due riferimenti:

  1. File :: documentazione del metodo expand_path
  2. Come __FILE__funziona in Ruby

Mi sono imbattuto in questo oggi:

boot.rb commit in Rails Github

Se salite due directory da boot.rb nell'albero delle directory:

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

vedi Gemfile, il che mi porta a crederci File.expand_path("../../Gemfile", __FILE__) riferimento al seguente file:/path/to/this/file/../../Gemfile


Grazie per il post, ma questo è venuto dal tutorial di Gembundler quindi stavo cercando di capire esattamente come l'avevano :)
thenengah
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.