87 votes

File.expand_path("../../Gemfile", __FILE__) Comment cela fonctionne-t-il ? Où se trouve le fichier ?

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

J'essaie simplement d'accéder à un fichier .rb depuis le répertoire some et un tutoriel me dit d'utiliser ce code mais je ne vois pas comment il trouve le fichier gem.

2 votes

Voir aussi la question stackoverflow.com/questions/4333286

197voto

Theo Points 60103
File.expand_path('../../Gemfile', __FILE__)

est un idiome Ruby quelque peu laid pour obtenir le chemin absolu d'un fichier lorsque vous connaissez le chemin relatif au fichier actuel. Une autre façon de l'écrire est la suivante :

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

Les deux sont moches, mais la première variante est plus courte. Cependant, la première variante est également très peu intuitive, jusqu'à ce que l'on s'y habitue. Pourquoi le supplément .. ? (mais la deuxième variante peut donner une idée de la raison pour laquelle elle est nécessaire).

Voici comment cela fonctionne : File.expand_path renvoie le chemin absolu du premier argument, relatif au deuxième argument (qui est par défaut le répertoire de travail actuel). __FILE__ est le chemin d'accès au fichier dans lequel se trouve le code. Puisque le deuxième argument dans ce cas est un chemin vers un fichier, et que File.expand_path suppose un répertoire, nous devons coller un supplément de .. dans le chemin pour obtenir le bon chemin. Voici comment cela fonctionne :

File.expand_path est implémenté de la manière suivante (dans le code suivant) path aura la valeur de ../../Gemfile y relative_to aura la valeur 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

(il y a un peu plus que ça, ça s'étend ~ dans le répertoire personnel et ainsi de suite -- il y a probablement d'autres problèmes avec le code ci-dessus)

En passant par un appel au code ci-dessus absolute_path obtiendra d'abord la valeur /path/to/file.rb/../../Gemfile puis, pour chaque tour de la boucle, le premier .. sera supprimé, ainsi que le composant de chemin qui le précède. Premier site /file.rb/.. est retiré, puis au tour suivant /to/.. est supprimé, et nous obtenons /path/Gemfile .

Pour faire une longue histoire courte, File.expand_path('../../Gemfile', __FILE__) est une astuce pour obtenir le chemin absolu d'un fichier lorsque vous connaissez le chemin relatif au fichier actuel. L'extra .. dans le chemin d'accès relatif est d'éliminer le nom du fichier en __FILE__ .

Dans Ruby 2.0, il existe un Kernel fonction appelée __dir__ qui est mis en œuvre comme File.dirname(File.realpath(__FILE__)) .

2 votes

Y a-t-il une raison pour laquelle vous ne pouvez pas simplement utiliser "require_relative", si ce n'est l'incompatibilité avec la version 1.9.2 de Ruby ?

9 votes

A partir de Ruby 2.0, vous pouvez utiliser File.expand_path('../Gemfile',__dir__)

0 votes

Cette phrase de Theo a finalement fait tilt pour moi. File.expand_path assumes a directory même si __FILE__ n'est pas un répertoire. Pour que les choses aient un sens, utilisez __dir__ qui est en fait un répertoire.

9voto

Patrick Klingemann Points 4560

Deux références :

  1. Documentation de la méthode File::expand_path
  2. Comment __FILE__ travailler en Ruby

Je suis tombée sur ça aujourd'hui :

boot.rb commit dans le Github Rails

Si vous montez de deux répertoires à partir de boot.rb dans l'arborescence des répertoires :

/railties/lib/rails/générateurs/rails/app/templates

vous voyez Gemfile, ce qui me pousse à croire que File.expand_path("../../Gemfile", __FILE__) référence le fichier suivant : /path/to/this/file/../../Gemfile

0 votes

Merci pour le post, mais cela vient du tutoriel gembundler donc j'essayais de comprendre exactement comment ils l'ont fait :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X