File.expand_path ("../../ Gemfile", __FILE__) Wie funktioniert das? Wo ist die Datei?

84

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

Ich versuche nur, aus einem Verzeichnis auf eine .rb-Datei zuzugreifen, und ein Tutorial fordert mich auf, diesen Code zu verwenden, aber ich sehe nicht, wie die Gem-Datei gefunden wird.

thenengah
quelle
1
Siehe auch Frage stackoverflow.com/questions/4333286
Theo

Antworten:

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

ist eine etwas hässliche Ruby-Redewendung, um den absoluten Pfad zu einer Datei zu erhalten, wenn Sie den Pfad relativ zur aktuellen Datei kennen. Eine andere Art zu schreiben ist folgende:

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

beide sind hässlich, aber die erste Variante ist kürzer. Die erste Variante ist jedoch auch sehr unintuitiv, bis Sie den Dreh raus haben. Warum das Extra ..? (aber die zweite Variante kann einen Hinweis darauf geben, warum es benötigt wird).

So funktioniert es: File.expand_pathGibt den absoluten Pfad des ersten Arguments relativ zum zweiten Argument zurück (standardmäßig das aktuelle Arbeitsverzeichnis). __FILE__ist der Pfad zu der Datei, in der sich der Code befindet. Da das zweite Argument in diesem Fall ein Pfad zu einer Datei ist und File.expand_pathein Verzeichnis annimmt, müssen wir ein zusätzliches ..in den Pfad einfügen, um den Pfad richtig zu machen. So funktioniert es:

File.expand_pathwird im Grunde so implementiert (im folgenden Code pathwird der Wert von ../../Gemfileund relative_towird den Wert von haben /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

(Es steckt ein bisschen mehr dahinter, es wird ~in das Home-Verzeichnis erweitert und so weiter - es gibt wahrscheinlich auch einige andere Probleme mit dem obigen Code)

Wenn Sie einen Aufruf des obigen Codes durchlaufen, absolute_pathwird zuerst der Wert abgerufen /path/to/file.rb/../../Gemfile, und für jede Runde in der Schleife wird die erste ..zusammen mit der Pfadkomponente davor entfernt. Zuerst /file.rb/..wird entfernt, dann wird in der nächsten Runde /to/..entfernt, und wir bekommen /path/Gemfile.

Um es kurz zu machen, es File.expand_path('../../Gemfile', __FILE__)ist ein Trick, den absoluten Pfad einer Datei zu ermitteln, wenn Sie den Pfad relativ zur aktuellen Datei kennen. Das Extra ..im relativen Pfad besteht darin, den Namen der Datei in zu entfernen __FILE__.

In Ruby 2.0 gibt es eine KernelFunktion namens __dir__, die als implementiert ist File.dirname(File.realpath(__FILE__)).

Das Ö
quelle
2
Gibt es einen Grund, warum Sie nicht nur 'require_relative' verwenden sollten, außer Inkompatibilität mit vor Ruby 1.9.2?
Danny Andrews
9
Ab Ruby 2.0 können SieFile.expand_path('../Gemfile',__dir__)
Phrogz
Diese Zeile von Theo hat es endlich geschafft, für mich zu klicken File.expand_path assumes a directory, obwohl __FILE__es kein Verzeichnis ist. Verwenden Sie für sinnvolle Dinge __dir__ein Verzeichnis.
Mbigras
9

Zwei Referenzen:

  1. Dokumentation der File :: expand_path-Methode
  2. Wie funktioniert das __FILE__in Ruby?

Ich bin heute darauf gestoßen:

boot.rb-Commit im Rails Github

Wenn Sie zwei Verzeichnisse von boot.rb in der Verzeichnisstruktur aufrufen:

/ railties / lib / Rails / Generatoren / Rails / App / Vorlagen

Sie sehen Gemfile, was mich glauben lässt, dass File.expand_path("../../Gemfile", __FILE__)Verweise auf folgende Datei:/path/to/this/file/../../Gemfile

Patrick Klingemann
quelle
Danke für den Beitrag, aber dieser kam aus dem gembundler Tutorial, also habe ich versucht, es genau zu verstehen, wie sie es hatten :)
thenengah