Как перезагрузить файл clojure в REPL
каков предпочтительный способ перезагрузки функций, определенных в файле Clojure, без перезапуска REPL. Прямо сейчас, чтобы использовать обновленный файл, я должен:
- edit
src/foo/bar.clj
- закройте REPL
- откройте REPL
(load-file "src/foo/bar.clj")
(use 'foo.bar)
кроме того, (use 'foo.bar :reload-all)
не приводит к требуемому эффекту, который оценивает измененные тела функций и возвращает новые значения, вместо того чтобы вести себя как источник не изменился.
8 ответов:
существует также альтернатива, как с помощью инструменты.пространство имен, Это довольно эффективный:
user=> (use '[clojure.tools.namespace.repl :only (refresh)]) user=> (refresh) :reloading (namespace.app) :ok
перезагрузка кода Clojure с помощью
(require … :reload)
и:reload-all
и весьма проблематично:
если вы измените два пространства имен, которые зависят друг от друга, вы должны не забудьте перезагрузить их в правильном порядке, чтобы избежать компиляции ошибки.
если вы удалите определения из исходного файла, а затем перезагрузите его, эти определения все еще доступны в памяти. Если другой код зависит от этих определений, это будет продолжать работать, но будет сломать следующей перезагрузке виртуальной машины.
если перезагруженное пространство имен содержит
defmulti
, вы также должны перезагрузить все связанныеdefmethod
выражения.если перезагруженное пространство имен содержит
defprotocol
, вы должны также перезагрузите все записи или типы, реализующие этот протокол, и замените любые существующие экземпляры этих записей / типов с новыми экземплярами.если перезагруженное пространство имен содержит макросы, вы также должны перезагрузить любой пространства, которые используют эти макросы.
если запущенная программа содержит функции, которые закрываются над значениями в перегруженное пространство имен, эти закрытые значения не обновляются. (Это часто встречается в веб-приложениях, которые строят " обработчик стек " как состав функций.)
clojure.инструменты.библиотека пространств имен улучшает ситуацию значительно. Он обеспечивает простую функцию обновления, которая выполняет интеллектуальную перезагрузку на основе графика зависимостей пространств имен.
myapp.web=> (require '[clojure.tools.namespace.repl :refer [refresh]]) nil myapp.web=> (refresh) :reloading (myapp.web) :ok
к сожалению перезагрузка во второй раз не удастся, если пространство имен, в котором вы ссылались на
лучший ответ:
(require 'my.namespace :reload-all)
Это не только перезагрузит указанное пространство имен, но и перезагрузит все пространства имен зависимостей.
Я использую это в Lighttable (и awesome instarepl), но он должен использоваться в других инструментах разработки. У меня была такая же проблема со старыми определениями функций и мультиметодов, висящих после перезагрузки, поэтому теперь во время разработки вместо объявления пространств имен с помощью:
(ns my.namespace)
Я объявляю свои пространства имен следующим образом:
(clojure.core/let [s 'my.namespace] (clojure.core/remove-ns s) (clojure.core/in-ns s) (clojure.core/require '[clojure.core]) (clojure.core/refer 'clojure.core))
довольно некрасиво, но всякий раз, когда я переоцениваю все пространство имен (Cmd-Shift-Enter в Lighttable, чтобы получить новый instarepl результаты каждого выражения), он сдувает все старые определения и дает мне чистую среду. Я спотыкался каждые несколько дней по старым определениям, прежде чем начал это делать, и это спасло мое здравомыслие. :)
попробуйте загрузить файл еще раз?
Если вы используете IDE, обычно есть сочетание клавиш для отправки блока кода в REPL, что эффективно переопределяет связанные функции.
как только
(use 'foo.bar)
работает для вас, это означает, что у вас есть foo/bar.clj или foo / bar_init.класс на вашем пути к классам. В bar_init.класс будет AOT-скомпилированной версией bar.clj по. Если вы это сделаете(use 'foo.bar)
, Я не совсем уверен, если Clojure предпочитает класс над clj или наоборот. Если он предпочел бы файлы классов, и у вас есть оба файла, то ясно, что редактирование файла clj, а затем перезагрузка пространства имен не имеет никакого эффекта.кстати: вам не нужно
load-file
передuse
Если ваш путь к классу установлен правильно.BTW2: Если вам нужно использовать
load-file
по причине, то вы можете просто сделать это снова если вы редактировали файл.