Перегрузочный Clojure код , используя (require … :reload)и :reload-allявляется весьма проблематичным :
Если вы изменяете два пространства имен, которые зависят друг от друга, не забудьте перезагрузить их в правильном порядке, чтобы избежать ошибок компиляции.
Если вы удалите определения из исходного файла, а затем перезагрузите его, эти определения все еще будут доступны в памяти. Если другой код зависит от этих определений, он продолжит работать, но перестанет работать при следующем перезапуске JVM.
Если перезагруженное пространство имен содержит defmulti, вы также должны перезагрузить все связанные defmethodвыражения.
Если перезагруженное пространство имен содержит defprotocol, вы также должны перезагрузить все записи или типы, реализующие этот протокол, и заменить любые существующие экземпляры этих записей / типов новыми экземплярами.
Если перезагруженное пространство имен содержит макросы, необходимо также перезагрузить все пространства имен, которые используют эти макросы.
Если запущенная программа содержит функции, которые закрывают значения в перезагруженном пространстве имен, эти закрытые значения не обновляются. (Это часто встречается в веб-приложениях, которые создают «стек обработчиков» как набор функций.)
Библиотека clojure.tools.namespace значительно улучшает ситуацию. Он предоставляет функцию простого обновления, которая выполняет интеллектуальную перезагрузку на основе графа зависимостей пространств имен.
myapp.web=> (require '[clojure.tools.namespace.repl :refer [refresh]])
nil
myapp.web=> (refresh)
:reloading (myapp.web)
:ok
К сожалению, повторная загрузка не удастся, если пространство имен, в котором вы ссылались на refreshфункцию, изменилось. Это связано с тем, что tools.namespace уничтожает текущую версию пространства имен перед загрузкой нового кода.
myapp.web=> (refresh)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: refresh in this context, compiling:(/private/var/folders/ks/d6qbfg2s6l1bcg6ws_6bq4600000gn/T/form-init819543191440017519.clj:1:1)
Вы можете использовать полное имя var в качестве обходного пути для этой проблемы, но лично я предпочитаю не вводить это при каждом обновлении. Другая проблема, связанная с вышеизложенным, заключается в том, что после перезагрузки основного пространства имен на стандартные вспомогательные функции REPL (например, docи source) больше нет ссылок.
Для решения этих проблем я предпочитаю создать фактический исходный файл для пространства имен пользователя, чтобы его можно было надежно перезагрузить. Я положил исходный файл, ~/.lein/src/user.cljно вы можете разместить в любом месте. Файл должен требовать функцию обновления в объявлении top ns следующим образом:
(ns user
(:require [clojure.tools.namespace.repl :refer [refresh]]))
Вы можете настроить профиль пользователя leiningen~/.lein/profiles.clj таким образом, чтобы местоположение, в которое вы помещаете файл, было добавлено в путь к классам. Профиль должен выглядеть примерно так:
{:user {:dependencies [[org.clojure/tools.namespace "0.2.7"]]
:repl-options { :init-ns user }
:source-paths ["/Users/me/.lein/src"]}}
Обратите внимание, что я установил пространство имен пользователя в качестве точки входа при запуске REPL. Это гарантирует, что на вспомогательные функции REPL будут ссылаться в пространстве имен пользователя вместо основного пространства имен вашего приложения. Таким образом, они не потеряются, если вы не измените исходный файл, который мы только что создали.
Надеюсь это поможет!
(use 'foo.bar :reload-all)всегда работал хорошо для меня. Кроме того,(load-file)никогда не должно быть необходимости, если у вас правильно настроен путь к классам. Какой «требуемый эффект» вы не получаете?