Повторная загрузка кода 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
, но вы можете разместить его где угодно. Файл должен требовать функцию обновления в верхнем объявлении 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 будут ссылаться в пространстве имен пользователя, а не в основном пространстве имен вашего приложения. Таким образом, они не потеряются, если вы не измените только что созданный исходный файл.
Надеюсь это поможет!
person
Dirk Geurs
schedule
22.09.2014
(use 'foo.bar :reload-all)
всегда отлично работал у меня. Кроме того,(load-file)
никогда не понадобится, если ваш путь к классам настроен правильно. Какого желаемого эффекта вы не получаете? - person Dave Ray   schedule 05.10.2011bar.clj
с подробным описанием необходимого эффекта. - person Sridhar Ratnakumar   schedule 05.10.2011(defn f [] 1)
и я изменил ее определение на(defn f [] 2)
, мне казалось, что после того, как я выдаю(use 'foo.bar :reload-all)
и вызываю функциюf
, она должна вернуть 2, а не 1. К сожалению, это не работает. для меня, и каждый раз, когда я меняю тело функции, мне приходится перезапускать REPL. - person pkaleta   schedule 05.10.2011:reload
или:reload-all
должны работать оба. - person Jason   schedule 19.02.2016