web-dev-qa-db-de.com

Hinzufügen eines Verzeichnisses zu $ ​​LOAD_PATH (Ruby)

Ich habe zwei häufig verwendete Techniken zum Hinzufügen des Verzeichnisses der gerade ausgeführten Datei zu $ ​​LOAD_PATH (oder $ :) gesehen. Ich sehe die Vorteile, wenn Sie nicht mit einem Edelstein arbeiten. Offensichtlich ist einer offener als der andere, aber gibt es einen Grund, den einen über den anderen zu gehen?

Die erste, verbose Methode (könnte übertrieben sein):

$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))

und das einfacher, schneller und schmutziger:

$:.unshift File.dirname(__FILE__)

Gibt es einen Grund, mit einem über das andere zu gehen?

84
Mark W

Ich würde sagen, gehen Sie mit $:.unshift File.dirname(__FILE__) über die andere, einfach weil ich viel mehr Verwendung als Code gesehen habe als der $LOAD_PATH, und es ist auch kürzer!

47
Ryan Bigg

Der Ruby-Ladepfad wird häufig als $: geschrieben, aber nur weil er kurz ist, wird er nicht besser. Wenn Sie Klarheit der Klugheit vorziehen, oder wenn Sie der Kürze halber juckt, müssen Sie es nicht tun, nur weil alle anderen es sind. Sag Hallo zu ...

$LOAD_PATH

... und verabschiede mich von ...

# I don't quite understand what this is doing...
$:
143
user176788

Ich bin nicht so begeistert von der "schnellen und schmutzigen" Art ... _. Wer Ruby neu ist, wird darüber nachdenken, was $:. ist.

Ich finde das offensichtlicher.

libdir = File.dirname(__FILE__)
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)

Oder wenn es mir wichtig ist, den vollen Weg zu haben ...

libdir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)

UPDATE2009/09/10

In letzter Zeit habe ich Folgendes getan:

$:.unshift(File.expand_path(File.dirname(__FILE__))) unless
    $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))

Ich habe es in einer Reihe von verschiedenen Ruby-Projekten gesehen, als ich GitHub durchstöberte.

Scheint die Konvention zu sein?

21
Luke Antins

Wenn Sie in Ihrem Rails-Projekt script/console eingeben und $: eingeben, erhalten Sie ein Array, das alle zum Laden von Ruby erforderlichen Verzeichnisse enthält. Diese kleine Übung macht es mit sich, dass $: ein Array ist. Wenn Sie dies tun, können Sie Funktionen wie das Voranstellen anderer Verzeichnisse mit der Methode unshift oder dem Operator << ausführen. Wie Sie in Ihrer Aussage impliziert haben, sind $: und $LOAD_PATH gleich.

Der Nachteil bei der schnellen und schmutzigen Vorgehensweise, die Sie erwähnt haben, ist folgender: Wenn Sie das Verzeichnis bereits in Ihrem Startpfad haben, wird es sich von selbst wiederholen.

Beispiel:

Ich habe ein Plugin namens todo erstellt. Mein Verzeichnis ist wie folgt aufgebaut:

/---Verkäufer
 | 
 | ---/plugins 
 | 
 | ---/todo 
 | 
 | ---/lib 
 | 
 | ---/app 
 | 
 | ---/models 
 | ---/Steuerungen 
 | 
 | ---/Schienen 
 | 
 | --- init.rb 

In der init.rb-Datei habe ich folgenden Code eingegeben:

## In vendor/plugins/todo/Rails/init.rb
    %w{ models controllers models }.each do |dir|
      path = File.expand_path(File.join(File.dirname(__FILE__), '../lib', 'app', dir))
      $LOAD_PATH << path
      ActiveSupport::Dependencies.load_paths << path
      ActiveSupport::Dependencies.load_once_paths.delete(path)
    end 

Beachten Sie, wie ich dem Codeblock sage, die Aktionen innerhalb des Blocks auf die Zeichenfolgen 'models', 'controller' und 'models' auszuführen, wo ich 'models' wiederhole. (FYI, %w{ ... } ist nur eine weitere Möglichkeit, um Ruby anzuweisen, ein Array von Strings zu enthalten). Beim Ausführen von script/console gebe ich Folgendes ein:

>> puts $:

Und ich tippe das so ein, dass es einfacher ist, den Inhalt des Strings zu lesen. Die Ausgabe, die ich bekomme, ist:

...
...
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models 
./Users/Me/mySites/myRailsApp/vendor /plugins/todo/lib/app/controllers
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models

Wie Sie sehen, ist dies ein einfaches Beispiel, das ich erstellen könnte, während ich ein Projekt verwende, an dem ich gerade arbeite. Wenn Sie nicht aufpassen, führt der schnelle und schmutzige Weg zu wiederholten Pfaden. Der längere Weg wird nach wiederholten Pfaden suchen und sicherstellen, dass sie nicht auftreten.

Wenn Sie ein erfahrener Rails-Programmierer sind, haben Sie wahrscheinlich eine sehr gute Vorstellung davon, was Sie tun, und machen wahrscheinlich nicht den Fehler, Pfade zu wiederholen. Wenn Sie ein Neuling sind, würde ich den längeren Weg gehen, bis Sie wirklich verstehen, was Sie tun.

8
Dyba

Am besten bin ich dazu gekommen, ein Verzeichnis über den relativen Pfad hinzuzufügen, wenn Sie Rspec verwenden. Ich finde es wortreich genug aber auch noch ein Nice-Liner.

$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
Dave Robertson

Es gibt einen Edelstein, mit dem Sie Ihren Ladepfad mit schönerem und saubererem Code einrichten können. Überprüfen Sie dies: https://github.com/nayyara-samuel/load-path .

Es hat auch eine gute Dokumentation

1
Rubyist

Ich weiß, es ist lange her, seit diese Frage zum ersten Mal gestellt wurde, aber ich habe eine zusätzliche Antwort, die ich teilen möchte.

Ich habe mehrere Ruby-Anwendungen, die über mehrere Jahre von einem anderen Programmierer entwickelt wurden, und sie verwenden dieselben Klassen in den verschiedenen Anwendungen erneut, obwohl sie möglicherweise auf dieselbe Datenbank zugreifen. Da dies gegen die DRY - Regel verstößt, habe ich mich entschlossen, eine Klassenbibliothek zu erstellen, die von allen Ruby-Anwendungen gemeinsam genutzt werden kann. Ich hätte es in die Ruby-Hauptbibliothek aufnehmen können, aber das würde benutzerdefinierten Code in der allgemeinen Codebase verbergen, was ich nicht wollte.

Ich hatte ein Problem mit einem Namenskonflikt zwischen einem bereits definierten Namen "profile.rb" und einer Klasse, die ich verwendete. Dieser Konflikt war kein Problem, bis ich versuchte, die allgemeine Code-Bibliothek zu erstellen. Normalerweise durchsucht Ruby zuerst die Anwendungspositionen und wechselt dann zu den $ LOAD_PATH-Speicherorten.

Der application_controller.rb konnte die von mir erstellte Klasse nicht finden und hat einen Fehler in der ursprünglichen Definition ausgegeben, da es sich nicht um eine Klasse handelt. Da ich die Klassendefinition aus dem App-/Models-Abschnitt der Anwendung entfernt habe, konnte Ruby sie dort nicht finden und suchte sie in den Ruby-Pfaden.

Also habe ich die Variable $ LOAD_PATH so geändert, dass sie einen Pfad zum Bibliotheksverzeichnis enthält, das ich verwendete. Dies kann zum Zeitpunkt der Initialisierung in der Datei environment.rb erfolgen.

Selbst wenn das neue Verzeichnis dem Suchpfad hinzugefügt wurde, gab Ruby einen Fehler aus, da die vom System definierte Datei bevorzugt zuerst übernommen wurde. Der Suchpfad in der Variablen $ LOAD_PATH durchsucht bevorzugt zuerst die Ruby-Pfade.

Also musste ich die Suchreihenfolge ändern, damit Ruby die Klasse in meiner allgemeinen Bibliothek fand, bevor die integrierten Bibliotheken durchsucht wurden.

Dieser Code hat es in der Datei environment.rb gemacht:

Rails::Initializer.run do |config|

* * * * *

path = []
path.concat($LOAD_PATH)
$LOAD_PATH.clear
$LOAD_PATH << 'C:\web\common\lib'
$LOAD_PATH << 'C:\web\common'
$LOAD_PATH.concat(path)

* * * * *

end

Ich glaube nicht, dass Sie eines der fortgeschrittenen Codierungskonstrukte auf dieser Ebene verwenden können, aber es funktioniert gut, wenn Sie etwas zum Initialisierungszeitpunkt in Ihrer App einrichten möchten. Sie müssen die ursprüngliche Reihenfolge der ursprünglichen $ LOAD_PATH-Variablen beibehalten, wenn sie der neuen Variablen wieder hinzugefügt wird. Andernfalls gehen einige der wichtigsten Ruby-Klassen verloren.

In der Datei application_controller.rb verwende ich einfach eine

require 'profile'
require 'etc' #etc

und dies lädt die benutzerdefinierten Bibliotheksdateien für die gesamte Anwendung, d. h. ich muss nicht in jedem Controller Anforderungsbefehle verwenden.

Für mich war dies die Lösung, nach der ich suchte, und ich dachte, ich würde sie zu dieser Antwort hinzufügen, um die Informationen weiterzugeben.

0
Timothy Dooling