Warum entfernt Ruby 1.9.2 "." von LOAD_PATH, und was ist die Alternative?

154

Die neuesten Änderungssätze für Ruby 1.9.2 machen das aktuelle Verzeichnis nicht mehr zu einem .Teil Ihres Verzeichnisses LOAD_PATH. Ich habe eine nicht triviale Anzahl von Rakefiles, die davon ausgehen, dass dies .Teil von ist LOAD_PATH, sodass diese beschädigt wurden (sie meldeten "keine solche Datei zum Laden" für alle erforderlichen Anweisungen, die auf dem Projektpfad basieren). Gab es dafür eine besondere Rechtfertigung?

Was das $: << "."Problem angeht , funktioniert das Hinzufügen überall, aber es scheint unglaublich hackig zu sein, und das möchte ich nicht. Was ist der bevorzugte Weg, um meine Rakefiles 1.9.2+ kompatibel zu machen?

John Feminella
quelle

Antworten:

141

Es wurde als "Sicherheitsrisiko" eingestuft.

Sie können es umgehen, indem Sie absolute Pfade verwenden

File.expand_path(__FILE__) et al

oder tun

require './filename' (ironically).

oder mit

require_relative 'filename'

oder Hinzufügen eines "Include" -Verzeichnisses

ruby -I . ...

oder dasselbe mit irb;

$irb -I .
Rogerdpack
quelle
27
Ich habe mit beendet require_relative. Vielen Dank.
John Feminella
11
Entspricht dies den meisten Unixen, die das aktuelle Verzeichnis nicht im Pfad zum Ausführen ausführbarer Dateien enthalten?
Andrew Grimm
5
require './filename'Funktioniert nur, wenn Ihr Skript mit dem Arbeitsverzeichnis ausgeführt wird, das auf dasselbe Verzeichnis eingestellt ist, in dem sich das Skript befindet. Dies ist bei Projekten mit mehreren Verzeichnissen häufig nicht der Fall.
mxcl
34

Es gibt zwei Gründe:

  • Robustheit und
  • Sicherheit

Beide basieren auf demselben Prinzip: Im Allgemeinen können Sie einfach nicht wissen, wie das aktuelle Verzeichnis lautet, wenn Ihr Code ausgeführt wird. Das heißt, wenn Sie eine Datei benötigen und davon abhängig sind, dass sie sich im aktuellen Verzeichnis befindet, können Sie nicht steuern, ob diese Datei überhaupt vorhanden ist oder ob es sich um die Datei handelt, von der Sie tatsächlich erwarten, dass sie vorhanden ist.

Jörg W Mittag
quelle
5
Ich denke nicht, dass die Durchsetzung, dass sich zwei Dateien relativ zueinander am selben Speicherort befinden, notwendigerweise eine schlechte Anforderung ist. Wenn das wahr wäre, hätten wir keine Verwendung für Verzeichnisse.
John Feminella
4
@ John Feminella: Was hat das damit zu tun, dass Dateien relativ zueinander in Pfade gestellt werden? Bei der Frage geht es darum, sie relativ zum .aktuellen Arbeitsverzeichnis zu platzieren. Wenn sich der Benutzer cdin einem anderen Verzeichnis befindet, ändert sich das aktuelle Arbeitsverzeichnis, und Sie haben jetzt require völlig unterschiedliche Dateien, je nachdem, in welchem ​​Verzeichnis sich der Benutzer gerade befand, als er Ihr Skript aufrief. Ich denke nicht, dass das eine gute Idee ist.
Jörg W Mittag
Um eine anständige Benutzeroberfläche zu erhalten, sollten Sie dies tun? $: << File.dirname(__FILE__)
Joshua Cheek
4
@ Joshua Cheek: Ich persönlich mag das nicht. (Aber bitte schau dir meinen älteren Code nicht an, weil er mit solchen Sachen übersät ist :-)). Ich tue einfach so , als ob sich das libVerzeichnis in der $LOAD_PATHund dann in requireallen Dateien relativ zu befindet lib. Mit anderen Worten: Ich überlasse es dem Administrator, herauszufinden, wie das $LOAD_PATHrichtig eingerichtet wird. Wenn Sie RubyGems verwenden, ist dies trivial, da RubyGems dies automatisch für Sie erledigt. Wenn Sie Debian-Pakete verwenden, ist dies die Aufgabe des Paketverwalters. Alles in allem scheint es ganz gut zu funktionieren.
Jörg W Mittag
8
@Joshua Cheek: Als eine Art Gegengewicht zum Entfernen .von $LOAD_PATHRuby 1.9.2 wird außerdem eingeführt, require_relativewelche ... Überraschung ... eine requireDatei relativ zum Speicherort der aktuell ausgeführten Datei (dh relativ zu File.dirname(__FILE__)) ist.
Jörg W Mittag
16

Wie andere Antworten hervorheben, handelt es sich um ein Sicherheitsrisiko, da sich .Ihr Ladepfad auf das aktuelle Arbeitsverzeichnis bezieht Dir.pwdund nicht auf das Verzeichnis der aktuell geladenen Datei. Wer also Ihr Skript ausführt, kann dies einfach ändern, indem er cdin ein anderes Verzeichnis wechselt. Nicht gut!

Ich habe vollständige Pfade __FILE__als Alternative verwendet.

require File.expand_path(File.join(File.dirname(__FILE__), 'filename'))

Im Gegensatz require_relativedazu ist dies abwärtskompatibel mit Ruby 1.8.7.

Jonathan Tran
quelle
4
Es gibt auch diese Variation (die ich persönlich besser lesbar finde): require Pathname.new(__FILE__).dirname + 'filename'
Tyler Rick
8

Verwenden require_relative 'file_to_require'

Fügen Sie dies in Ihren Code ein, damit require_relative in 1.8.7 funktioniert:

unless Kernel.respond_to?(:require_relative)
  module Kernel
    def require_relative(path)
      require File.join(File.dirname(caller.first), path.to_str)
    end
  end
end
Tyler Brock
quelle
3

Ich fand das eine verwirrende Veränderung, bis ich ein paar Dinge realisierte.

Sie können RUBYLIB in Ihrem .profile (Unix) festlegen und das Leben wie zuvor fortsetzen:

export RUBYLIB="."

Aber wie oben erwähnt, wurde dies lange Zeit als unsicher angesehen.

In den allermeisten Fällen können Sie Probleme vermeiden, indem Sie einfach Ihre Ruby-Skripte mit einem vorangestellten 'aufrufen.' zB ./scripts/server.

Dylan
quelle
3

Wie Jörg W. Mittag betonte, möchten Sie meiner Meinung nach die von require_relativeIhnen benötigte Datei relativ zur Quelldatei der requireDeklaration und nicht zum aktuellen Arbeitsverzeichnis verwenden.

Ihre Abhängigkeiten sollten relativ zu Ihrer Rake-Build-Datei sein.

Martin
quelle