使ってClojureのコードをリロード(require … :reload)
して:reload-all
いる非常に問題:
相互に依存する2つの名前空間を変更する場合は、コンパイルエラーを回避するために、それらを正しい順序で再ロードすることを忘れないでください。
ソースファイルから定義を削除してから再読み込みしても、それらの定義は引き続きメモリで使用できます。他のコードがそれらの定義に依存している場合、そのコードは引き続き機能しますが、JVMを再起動したときに壊れます。
リロードされたネームスペースにが含まれている場合defmulti
は、関連defmethod
するすべての式もリロードする必要があります。
再ロードされた名前空間にが含まれている場合は、defprotocol
そのプロトコルを実装するすべてのレコードまたはタイプを再ロードし、それらのレコード/タイプの既存のインスタンスをすべて新しいインスタンスに置き換える必要があります。
リロードされたネームスペースにマクロが含まれている場合は、それらのマクロを使用するネームスペースもリロードする必要があります。
実行中のプログラムに、再ロードされた名前空間の値を閉じる関数が含まれている場合、それらの閉じられた値は更新されません。(これは、関数の構成として「ハンドラースタック」を構築するWebアプリケーションでは一般的です。)
clojure.tools.namespaceライブラリは状況を大幅に改善します。名前空間の依存関係グラフに基づいてスマートな再読み込みを行う簡単な更新機能を提供します。
myapp.web=> (require '[clojure.tools.namespace.repl :refer [refresh]])
nil
myapp.web=> (refresh)
:reloading (myapp.web)
:ok
残念ながら、refresh
関数を参照した名前空間が変更された場合、2回目の再読み込みは失敗します。これは、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ヘルパー関数がアプリケーションのメイン名前空間ではなくユーザー名前空間で参照されるようになります。そうすれば、先ほど作成したソースファイルを変更しない限り、ファイルが失われることはありません。
お役に立てれば!
(use 'foo.bar :reload-all)
私はいつもうまくいきました。また、(load-file)
クラスパスが正しく設定されている場合は必要ありません。あなたが得ていない「必要な効果」は何ですか?