Apa cara yang disukai untuk memuat ulang fungsi yang didefinisikan dalam file Clojure tanpa harus me-restart REPL. Saat ini, untuk menggunakan file yang diperbarui saya harus:
- sunting
src/foo/bar.clj
- tutup REPL
- buka REPL
(load-file "src/foo/bar.clj")
(use 'foo.bar)
Selain itu, (use 'foo.bar :reload-all)
tidak menghasilkan efek yang diperlukan, yang mengevaluasi tubuh fungsi yang dimodifikasi dan mengembalikan nilai baru, alih-alih berperilaku sebagai sumber tidak berubah sama sekali.
Dokumentasi:
clojure
reload
read-eval-print-loop
leiningen
pkaleta
sumber
sumber
(use 'foo.bar :reload-all)
selalu bekerja dengan baik untuk saya. Juga,(load-file)
seharusnya tidak perlu jika Anda mengatur classpath Anda dengan benar. Apa "efek yang diperlukan" yang tidak Anda dapatkan?bar.clj
merinci "efek yang diperlukan".(defn f [] 1)
dan saya mengubah definisi(defn f [] 2)
, sepertinya bagi saya setelah saya mengeluarkan(use 'foo.bar :reload-all)
dan memanggilf
fungsi itu harus mengembalikan 2, bukan 1. Sayangnya itu tidak bekerja seperti itu untuk saya dan setiap waktu saya mengubah tubuh fungsi saya harus me-restart REPL.:reload
atau:reload-all
keduanya harus bekerja.Jawaban:
Atau
(use 'your.namespace :reload)
sumber
:reload-all
juga harus bekerja. OP secara khusus mengatakan tidak, tapi saya pikir ada sesuatu yang salah di lingkungan dev OP karena untuk satu file keduanya (:reload
dan:reload-all
) harus memiliki efek yang sama. Inilah perintah lengkap untuk:reload-all
:(use 'your.namespace :reload-all)
Ini memuat ulang semua dependensi juga.Ada juga alternatif seperti menggunakan tools.namespace , ini cukup efisien:
sumber
(refresh)
tampaknya juga menyebabkan REPL lupa bahwa Anda telah dimintaclojure.tools.namespace.repl
. Panggilan berikutnya untuk(refresh)
akan memberi Anda RuntimeException, "Tidak dapat menyelesaikan simbol: menyegarkan dalam konteks ini." Mungkin hal terbaik untuk dilakukan adalah baik(require 'your.namespace :reload-all)
, atau, jika Anda tahu Anda akan ingin menyegarkan repl Anda banyak untuk proyek tertentu, membuat:dev
profil dan menambahkan[clojure.tools.namespace.repl :refer (refresh refresh-all)]
kedev/user.clj
.Reload kode Clojure menggunakan
(require … :reload)
dan:reload-all
adalah sangat bermasalah :Pustaka clojure.tools.namespace meningkatkan situasi secara signifikan. Ini menyediakan fungsi refresh yang mudah yang melakukan reload cerdas berdasarkan grafik dependensi namespaces.
Sayangnya memuat ulang waktu kedua akan gagal jika namespace tempat Anda mereferensikan
refresh
fungsi berubah. Ini karena fakta bahwa tools.namespace menghancurkan versi namespace saat ini sebelum memuat kode baru.Anda bisa menggunakan nama var yang sepenuhnya memenuhi syarat sebagai solusi untuk masalah ini, tetapi secara pribadi saya lebih suka tidak harus mengetikkan itu pada setiap refresh. Masalah lain dengan hal di atas adalah bahwa setelah memuat kembali namespace utama fungsi pembantu REPL standar (seperti
doc
dansource
) tidak lagi dirujuk di sana.Untuk mengatasi masalah ini, saya lebih suka membuat file sumber aktual untuk namespace pengguna sehingga dapat dimuat ulang dengan andal. Saya memasukkan file sumber
~/.lein/src/user.clj
tetapi Anda dapat menempatkan di mana saja. File harus memerlukan fungsi refresh dalam deklarasi ns atas seperti ini:Anda dapat mengatur profil pengguna leiningen di
~/.lein/profiles.clj
lokasi yang Anda masukkan file ditambahkan ke jalur kelas. Profil akan terlihat seperti ini:Perhatikan bahwa saya menetapkan namespace pengguna sebagai titik masuk saat meluncurkan REPL. Ini memastikan bahwa fungsi pembantu REPL mendapatkan referensi di namespace pengguna alih-alih namespace utama aplikasi Anda. Dengan begitu mereka tidak akan hilang kecuali Anda mengubah file sumber yang baru saja kita buat.
Semoga ini membantu!
sumber
:source-paths
saya dapatkan#<FileNotFoundException java.io.FileNotFoundException: Could not locate user__init.class or user.clj on classpath: >
, sementara:resource-paths
semuanya baik-baik saja.:resource-paths
, saya di namespace pengguna saya di dalam repl.reload
masalah ini . Kemudian ternyata semua yang saya pikir sedang bekerja sudah tidak ada lagi. Mungkin seseorang harus memperbaiki situasi ini?Jawaban terbaik adalah:
Ini tidak hanya akan memuat ulang namespace yang Anda tentukan, tetapi juga akan memuat semua ruang nama dependensi.
Dokumentasi:
memerlukan
sumber
lein repl
, Coljure 1.7.0 dan nREPL 0.3.5. Jika Anda baru mengenal clojure: Namespace ('my.namespace
) didefinisikan dengan(ns ...)
disrc/
.../core.clj
, misalnya.proj.stuff.core
mirror struktur file pada disk sukasrc/proj/stuff/core.clj
, REPL dapat menemukan file yang benar dan Anda tidak perluload-file
.Satu liner berdasarkan jawaban papachan:
sumber
Saya menggunakan ini di Lighttable (dan instarepl yang luar biasa) tetapi harus digunakan dalam alat pengembangan lainnya. Saya mengalami masalah yang sama dengan definisi fungsi yang lama dan metode multimetro yang berkeliaran setelah dimuat ulang jadi sekarang selama pengembangan alih-alih mendeklarasikan namespace dengan:
Saya menyatakan ruang nama saya seperti ini:
Cukup jelek, tetapi setiap kali saya mengevaluasi kembali seluruh namespace (Cmd-Shift-Enter di Lighttable untuk mendapatkan hasil instarepl baru dari setiap ekspresi), itu menghapus semua definisi lama dan memberi saya lingkungan yang bersih. Saya tersandung setiap beberapa hari oleh definisi lama sebelum saya mulai melakukan ini dan itu telah menyelamatkan kewarasan saya. :)
sumber
Coba muat file lagi?
Jika Anda menggunakan IDE, biasanya ada pintasan keyboard untuk mengirim blok kode ke REPL, sehingga secara efektif mendefinisikan ulang fungsi terkait.
sumber
Segera setelah
(use 'foo.bar)
bekerja untuk Anda, itu berarti Anda memiliki foo / bar.clj atau foo / bar_init.class di CLASSPATH Anda. Bar_init.class akan menjadi versi bar.clj yang dikompilasi oleh AOT. Jika Anda melakukannya(use 'foo.bar)
, saya tidak yakin apakah Clojure lebih suka kelas daripada clj atau sebaliknya. Jika lebih suka file kelas dan Anda memiliki kedua file, maka jelas bahwa mengedit file clj dan kemudian memuat kembali namespace tidak berpengaruh.BTW: Anda tidak perlu
load-file
sebelumuse
jika CLASSPATH Anda diatur dengan benar.BTW2: Jika Anda perlu menggunakan
load-file
karena suatu alasan, maka Anda bisa melakukannya lagi jika Anda mengedit file.sumber