Was ist die bevorzugte Methode zum erneuten Laden von Funktionen, die in einer Clojure-Datei definiert sind, ohne dass die REPL neu gestartet werden muss? Um die aktualisierte Datei verwenden zu können, muss ich Folgendes tun:
- bearbeiten
src/foo/bar.clj
- Schließen Sie die REPL
- Öffnen Sie die REPL
(load-file "src/foo/bar.clj")
(use 'foo.bar)
Darüber hinaus führt (use 'foo.bar :reload-all)
dies nicht zu einem erforderlichen Effekt, bei dem die geänderten Funktionskörper ausgewertet und neue Werte zurückgegeben werden, anstatt sich so zu verhalten, als hätte sich die Quelle überhaupt nicht geändert.
Dokumentation:
clojure
reload
read-eval-print-loop
leiningen
pkaleta
quelle
quelle
(use 'foo.bar :reload-all)
hat bei mir immer gut funktioniert. Auch(load-file)
sollte niemals erforderlich sein , wenn Sie Ihren Classpath richtig konfiguriert haben. Was ist der "erforderliche Effekt", den Sie nicht erhalten?bar.clj
Details zum "erforderlichen Effekt".(defn f [] 1)
und ihre Definition in änderte(defn f [] 2)
, schien es mir, dass nach dem Ausgeben(use 'foo.bar :reload-all)
und Aufrufen derf
Funktion 2 und nicht 1 zurückgegeben werden sollte. Leider funktioniert dies für mich und alle nicht so Wenn ich den Funktionskörper ändere, muss ich die REPL neu starten.:reload
oder:reload-all
sollten beide funktionieren.Antworten:
Oder
(use 'your.namespace :reload)
quelle
:reload-all
sollte auch funktionieren. Das OP sagt ausdrücklich, dass dies nicht der Fall ist, aber ich denke, dass in der Entwicklungsumgebung des OP etwas anderes nicht stimmte, da für eine einzelne Datei die beiden (:reload
und:reload-all
) den gleichen Effekt haben sollten. Hier ist der vollständige Befehl für:reload-all
:(use 'your.namespace :reload-all)
Dadurch werden auch alle Abhängigkeiten neu geladen.Es gibt auch eine Alternative wie die Verwendung von tools.namespace , die ziemlich effizient ist:
quelle
(refresh)
scheint die REPL auch zu vergessen, dass Sie sie benötigt habenclojure.tools.namespace.repl
. Bei nachfolgenden Aufrufen von erhalten(refresh)
Sie eine RuntimeException: "Symbol kann nicht aufgelöst werden: Aktualisierung in diesem Kontext." Wahrscheinlich ist es das Beste, entweder(require 'your.namespace :reload-all)
oder, wenn Sie wissen, dass Sie Ihre REPL für ein bestimmtes Projekt häufig aktualisieren möchten , ein:dev
Profil[clojure.tools.namespace.repl :refer (refresh refresh-all)]
zu erstellen und zu ergänzendev/user.clj
.Das Neuladen von Clojure-Code mit
(require … :reload)
und:reload-all
ist sehr problematisch :Die Bibliothek clojure.tools.namespace verbessert die Situation erheblich. Es bietet eine einfache Aktualisierungsfunktion, die das intelligente Neuladen basierend auf einem Abhängigkeitsdiagramm der Namespaces ermöglicht.
Leider schlägt das erneute Laden ein zweites Mal fehl, wenn sich der Namespace, in dem Sie auf die
refresh
Funktion verwiesen haben , geändert hat. Dies liegt daran, dass tools.namespace die aktuelle Version des Namespace zerstört, bevor der neue Code geladen wird.Sie könnten den vollständig qualifizierten Variablennamen als Problemumgehung für dieses Problem verwenden, aber ich persönlich bevorzuge es, dies nicht bei jeder Aktualisierung eingeben zu müssen. Ein weiteres Problem besteht darin, dass nach dem erneuten Laden des Hauptnamespace die Standard-REPL-Hilfsfunktionen (wie
doc
undsource
) dort nicht mehr referenziert werden.Um diese Probleme zu lösen, bevorzuge ich es, eine tatsächliche Quelldatei für den Benutzernamensraum zu erstellen, damit diese zuverlässig neu geladen werden kann. Ich habe die Quelldatei eingefügt,
~/.lein/src/user.clj
aber Sie können sie überall ablegen. Die Datei sollte die Aktualisierungsfunktion in der Top-ns-Deklaration wie folgt erfordern:Sie können Setup ein Leiningen Benutzerprofil in
~/.lein/profiles.clj
so dass Speicherort der Datei setzen in dem Klassenpfad hinzugefügt wird. Das Profil sollte ungefähr so aussehen:Beachten Sie, dass ich beim Starten der REPL den Benutzernamensraum als Einstiegspunkt festgelegt habe. Dadurch wird sichergestellt, dass die REPL-Hilfsfunktionen im Benutzernamensraum anstelle des Hauptnamensraums Ihrer Anwendung referenziert werden. Auf diese Weise gehen sie nur verloren, wenn Sie die gerade erstellte Quelldatei ändern.
Hoffe das hilft!
quelle
:source-paths
ich bekomme#<FileNotFoundException java.io.FileNotFoundException: Could not locate user__init.class or user.clj on classpath: >
, während mit:resource-paths
allem alles in Ordnung ist.:resource-paths
normal und alles funktioniert einwandfrei. Ich bin in meinem Benutzernamensraum in repl.reload
Problems angelogen hat. Dann stellte sich heraus, dass alles, was ich für funktionierend hielt, nicht mehr funktionierte. Vielleicht sollte jemand diese Situation beheben?Die beste Antwort ist:
Dadurch wird nicht nur der angegebene Namespace neu geladen, sondern auch alle Abhängigkeitsnamespaces neu geladen.
Dokumentation:
benötigen
quelle
lein repl
Coljure 1.7.0 und nREPL 0.3.5 funktioniert hat. Wenn Sie neu in Clojure sind: Der Namespace ('my.namespace
) wird beispielsweise mit(ns ...)
insrc/
... definiert/core.clj
.proj.stuff.core
die Dateistruktur auf der Festplatte wie spiegeltsrc/proj/stuff/core.clj
, kann die REPL die richtige Datei finden und Sie benötigen sie nichtload-file
.Ein Liner basierend auf Papachans Antwort:
quelle
Ich verwende dies in Lighttable (und dem fantastischen Instarepl), aber es sollte in anderen Entwicklungstools von Nutzen sein. Ich hatte das gleiche Problem mit alten Definitionen von Funktionen und Multimethoden, die nach dem Neuladen herumhängen, also jetzt während der Entwicklung, anstatt Namespaces zu deklarieren mit:
Ich deklariere meine Namespaces wie folgt:
Ziemlich hässlich, aber wenn ich den gesamten Namespace neu bewerte (Cmd-Shift-Enter in Lighttable, um die neuen instarepl-Ergebnisse jedes Ausdrucks zu erhalten), werden alle alten Definitionen weggeblasen und ich bekomme eine saubere Umgebung. Ich wurde alle paar Tage von alten Definitionen gestolpert, bevor ich damit anfing, und es hat meine geistige Gesundheit gerettet. :) :)
quelle
Versuchen Sie erneut, die Datei zu laden?
Wenn Sie eine IDE verwenden, gibt es normalerweise eine Tastenkombination, um einen Codeblock an die REPL zu senden und so die zugehörigen Funktionen effektiv neu zu definieren.
quelle
Sobald dies
(use 'foo.bar)
für Sie funktioniert, bedeutet dies, dass Sie foo / bar.clj oder foo / bar_init.class auf Ihrem CLASSPATH haben. Die bar_init.class wäre eine AOT-kompilierte Version von bar.clj. Wenn Sie das tun(use 'foo.bar)
, bin ich mir nicht ganz sicher, ob Clojure den Unterricht gegenüber clj bevorzugt oder umgekehrt. Wenn es Klassendateien bevorzugen würde und Sie beide Dateien haben, ist es klar, dass das Bearbeiten der clj-Datei und das anschließende Neuladen des Namespace keine Auswirkungen hat.Übrigens: Sie müssen nicht
load-file
vor dem,use
wenn Ihr CLASSPATH richtig eingestellt ist.Übrigens: Wenn Sie es
load-file
aus einem bestimmten Grund verwenden müssen, können Sie es einfach erneut ausführen , wenn Sie die Datei bearbeitet haben.quelle