Как перезагрузить файл 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по причине, то вы можете просто сделать это снова если вы редактировали файл.