185

REPLを再起動せずにClojureファイルで定義された関数を再ロードする好ましい方法は何ですか? 現在、更新されたファイルを使用するには、次のことを行う必要があります。

  • 編集src/foo/bar.clj
  • REPLを閉じる
  • REPLを開く
  • (load-file "src/foo/bar.clj")
  • (use 'foo.bar)

さらに(use 'foo.bar :reload-all)、ソースがまったく変更されていないため、関数の変更された本体を評価して新しい値を返すという必要な効果が得られません。

ドキュメンテーション:

4

8 に答える 8

217

または (use 'your.namespace :reload)

于 2013-12-02T21:12:26.867 に答える
80

tools.namespaceを使用するような代替手段もあり、非常に効率的です。

user=> (use '[clojure.tools.namespace.repl :only (refresh)])

user=> (refresh)

:reloading (namespace.app)

:ok
于 2013-04-12T12:50:34.710 に答える
69

(require … :reload)andを使用してClojureコードをリロードすること: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 ヘルパー関数が参照されるようになります。そうすれば、作成したばかりのソース ファイルを変更しない限り、それらが失われることはありません。

お役に立てれば!

于 2014-09-22T17:16:54.727 に答える
51

最良の答えは次のとおりです。

(require 'my.namespace :reload-all)

これにより、指定した名前空間だけでなく、すべての依存関係の名前空間も再読み込みされます。

ドキュメンテーション:

必要とする

于 2014-08-03T06:29:35.980 に答える
5

私はこれを Lighttable (および素晴らしい 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))

かなり醜いですが、名前空間全体を再評価するたびに (Lighttable で Cmd-Shift-Enter を押して、各式の新しい instarepl 結果を取得します)、古い定義がすべて吹き飛ばされ、クリーンな環境が得られます。これを始める前は、古い定義に数日おきにつまずいていたのですが、おかげで正気を保つことができました。:)

于 2015-12-02T10:53:03.997 に答える
3

ファイルのロードを再試行しますか?

IDE を使用している場合、通常、コード ブロックを REPL に送信するためのキーボード ショートカットがあり、関連する関数を効果的に再定義します。

于 2011-10-05T12:05:01.633 に答える
1

うまくいくとすぐ(use 'foo.bar)に、CLASSPATH に foo/bar.clj または foo/bar_init.class があることを意味します。bar_init.class は、bar.clj の AOT コンパイル バージョンになります。もしそうなら(use 'foo.bar)、Clojure が clj よりもクラスを好むのか、それともその逆なのか正確にはわかりません。クラス ファイルが優先され、両方のファイルがある場合、clj ファイルを編集して名前空間をリロードしても効果がないことは明らかです。

ところで: CLASSPATH が適切に設定されている場合は、load-file前に行う必要はありません。use

BTW2: 何らかのload-file理由で使用する必要がある場合は、ファイルを編集した場合にもう一度使用することができます。

于 2012-02-02T20:35:26.123 に答える