REPL में क्लोजर फ़ाइल को पुनः लोड कैसे करें


170

आरईपीएल को पुनः आरंभ किए बिना क्लोजर फ़ाइल में परिभाषित कार्यों को पुनः लोड करने का पसंदीदा तरीका क्या है। अभी, मेरे पास अद्यतन की गई फ़ाइल का उपयोग करने के लिए:

  • संपादित करें src/foo/bar.clj
  • REPL बंद करें
  • REPL खोलें
  • (load-file "src/foo/bar.clj")
  • (use 'foo.bar)

इसके अलावा, (use 'foo.bar :reload-all)आवश्यक प्रभाव नहीं पड़ता है, जो कि संशोधित निकायों के कार्यों का मूल्यांकन कर रहा है और नए मानों को वापस कर रहा है, बदले में व्यवहार नहीं कर रहा है क्योंकि स्रोत बिल्कुल नहीं बदला है।

प्रलेखन:


20
(use 'foo.bar :reload-all)मेरे लिए हमेशा ठीक काम किया है। इसके अलावा, (load-file)कभी भी आवश्यक नहीं होना चाहिए यदि आपके पास अपना क्लासपैथ सही है। "आवश्यक प्रभाव" क्या आपको नहीं मिल रहा है?
डेव रे

हां, "आवश्यक प्रभाव" क्या है? bar.clj"आवश्यक प्रभाव" पर एक विवरण का नमूना पोस्ट करें ।
श्रीधर रत्नाकुमार

1
आवश्यक प्रभाव से मेरा तात्पर्य यह था कि यदि मेरा कोई कार्य होता है (defn f [] 1)और मैंने इसकी परिभाषा बदल दी है (defn f [] 2), तो मुझे यह प्रतीत हुआ कि मैं कार्य करने के बाद इसे जारी करता हूं (use 'foo.bar :reload-all)और fइसे वापस लौटाना चाहिए, 2 नहीं। 1. दुर्भाग्य से यह मेरे और प्रत्येक के लिए उस तरह से काम नहीं करता है समय मैं फ़ंक्शन के शरीर को बदलने के लिए मुझे REPL को पुनरारंभ करना होगा।
pkaleta

आपके सेटअप में एक और समस्या होनी चाहिए ... :reloadया :reload-allदोनों काम करने चाहिए।
जेसन

जवाबों:


196

या (use 'your.namespace :reload)


3
:reload-allकाम भी करना चाहिए। ओपी विशेष रूप से कहते हैं कि यह नहीं है, लेकिन मुझे लगता है कि ओपी के देव वातावरण में कुछ और गलत था क्योंकि एक ही फाइल के लिए दोनों ( :reloadऔर :reload-all) का एक ही प्रभाव होना चाहिए। यहाँ के लिए पूर्ण आदेश है :reload-all: (use 'your.namespace :reload-all) यह सभी निर्भरताएँ भी पुनः लोड करता है।
जेसन

77

Tools.namespace का उपयोग करना भी एक विकल्प है , यह बहुत ही कुशल है:

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

user=> (refresh)

:reloading (namespace.app)

:ok

3
यह उत्तर अधिक उचित है
बहादुर कंबल

12
कैविएट: रनिंग (refresh)भी लगता है कि आरईपीएल भूल गया है कि आपको आवश्यक है clojure.tools.namespace.repl। इसके बाद आने वाली कॉल (refresh)आपको एक RuntimeException देगी, "प्रतीक को हल करने में असमर्थ: इस संदर्भ में ताज़ा करें।" ऐसा करने के लिए शायद सबसे अच्छी बात तो है (require 'your.namespace :reload-all)यदि आप जानते हैं आप अपने आरईपीएल, किसी दिए गए परियोजना के लिए एक बहुत ताज़ा करने के लिए चाहते करने जा रहे हैं, या, एक बनाने के :devप्रोफाइल और जोड़ने [clojure.tools.namespace.repl :refer (refresh refresh-all)]के लिएdev/user.clj
डेव यारवुड

1
Tools.namespace के लेखक द्वारा Clojure वर्कफ़्लो पर Blogpost: Thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded
David Tonhofer

61

का उपयोग कर Clojure कोड को पुन: लोड (require … :reload)और :reload-allहै बहुत समस्याग्रस्त :

  • यदि आप दो नामस्थानों को संशोधित करते हैं जो एक दूसरे पर निर्भर करते हैं, तो आपको संकलन त्रुटियों से बचने के लिए उन्हें सही क्रम में पुनः लोड करना याद रखना चाहिए।

  • यदि आप किसी स्रोत फ़ाइल से परिभाषाएँ निकालते हैं और फिर उसे पुनः लोड करते हैं, तो वे परिभाषाएँ अभी भी स्मृति में उपलब्ध हैं। यदि अन्य कोड उन परिभाषाओं पर निर्भर करता है, तो यह काम करना जारी रखेगा लेकिन अगली बार जब आप जेवीएम को फिर से शुरू करेंगे तो यह टूट जाएगा।

  • यदि पुनः लोड किए गए नामस्थान में शामिल है 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)

आप इस समस्या के समाधान के लिए पूरी तरह से योग्य वर नाम का उपयोग कर सकते हैं, लेकिन व्यक्तिगत रूप से मैं प्रत्येक ताज़ा पर टाइप करना पसंद नहीं करता। उपरोक्त के साथ एक और समस्या यह है कि मुख्य नाम स्थान को पुनः लोड करने के बाद मानक 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 सहायक कार्यों को आपके आवेदन के मुख्य नामस्थान के बजाय उपयोगकर्ता नामस्थान में संदर्भित किया जाता है। जब तक आप हमारे द्वारा बनाई गई स्रोत फ़ाइल को बदल नहीं देते हैं, तब तक वे खो नहीं जाएंगे।

उम्मीद है की यह मदद करेगा!


अच्छा सुझाव है। एक सवाल: क्यों ": स्रोत-पथ" ऊपर प्रविष्टि?
एलन थॉम्पसन

2
@DirkGeurs, :source-pathsमुझे मिलता है #<FileNotFoundException java.io.FileNotFoundException: Could not locate user__init.class or user.clj on classpath: >, जबकि :resource-pathsसब कुछ ठीक है।
fl00r

1
@ fl00r और यह अभी भी उस त्रुटि को फेंकता है? क्या आपके पास एक मान्य प्रोजेक्ट है। उस फ़ोल्डर में जिसे आप REPL से लॉन्च कर रहे हैं? जो आपकी समस्या को ठीक कर सकता है।
डिर्क ज्यूरस

1
हां, यह बहुत मानक है, और सभी के साथ ठीक काम करता है :resource-paths, मैं उत्तर के अंदर अपने उपयोगकर्ता नामस्थान में हूं।
fl00r

1
मुझे अभी एक REPL के साथ काम करने में बहुत अच्छा समय था जो इस reloadमुद्दे के कारण मुझसे झूठ बोल रहा था । फिर यह सब कुछ मुझे लगा कि काम कर रहा था अब और नहीं था। शायद किसी को इस स्थिति को ठीक करना चाहिए?
अल्पर

41

सबसे अच्छा जवाब है:

(require 'my.namespace :reload-all)

यह न केवल आपके निर्दिष्ट नामस्थान को फिर से लोड करेगा, बल्कि सभी निर्भरता नामस्थान को भी फिर से लोड करेगा।

प्रलेखन:

की आवश्यकता होती है


2
यह एकमात्र उत्तर है, जिसके साथ काम किया lein repl, Coljure 1.7.0 और nREPL 0.3.5। यदि आप क्लोजर के लिए नए हैं: नामस्थान ( 'my.namespace) (ns ...)में src/... के साथ परिभाषित किया गया है /core.clj
एरोन डिगुल्ला

1
इस उत्तर के साथ समस्या यह है कि मूल प्रश्न (लोड-फाइल ...) का उपयोग कर रहा है, कोई आवश्यकता नहीं है। उसे कैसे जोड़ सकते हैं: लोड-फ़ाइल के बाद नामस्थान पर पुनः लोड करें?
jgomo3

क्योंकि नाम स्थान संरचना जैसे proj.stuff.coreडिस्क पर फ़ाइल संरचना दर्पण src/proj/stuff/core.clj, REPL सही फ़ाइल का पता लगा सकता है और आपको इसकी आवश्यकता नहीं है load-file
एलन थॉम्पसन


5

मैं इसका उपयोग लाइटवेट (और भयानक इंस्ट्रप्ले) में करता हूं, लेकिन इसका उपयोग अन्य विकास साधनों में होना चाहिए। मुझे फंक्शंस की पुरानी परिभाषाओं के साथ एक ही समस्या थी और मल्टीमिथोड के साथ घूमने के बाद चारों ओर लटके हुए थे अब विकास के दौरान नाम स्थान घोषित करने के बजाय:

(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))

बहुत बदसूरत, लेकिन जब भी मैं पूरे नामस्थान (Cmd-Shift-Enter को लाइटटेबल में प्रत्येक अभिव्यक्ति के नए instarepl परिणाम प्राप्त करने के लिए) का पुनर्मूल्यांकन करता हूं, तो यह सभी पुरानी परिभाषाओं को उड़ा देता है और मुझे एक स्वच्छ वातावरण देता है। ऐसा करने से पहले मुझे कुछ दिनों तक पुरानी परिभाषाओं में उलझाया गया और इससे मेरी पवित्रता बच गई। :)


3

लोड-फ़ाइल को फिर से आज़माएँ?

यदि आप एक आईडीई का उपयोग कर रहे हैं, तो आमतौर पर REPL को कोड-ब्लॉक भेजने के लिए एक कीबोर्ड शॉर्टकट होता है, इस प्रकार प्रभावी रूप से संबंधित कार्यों को फिर से परिभाषित करता है।


1

जैसे ही (use 'foo.bar)आप के लिए काम करता है, इसका मतलब है कि आपके पास अपने CLASSPATH पर foo / bar.clj या foo / bar_init.class है। Bar_init.class, Bar.clj का AOT- संकलित संस्करण होगा। यदि आप करते हैं (use 'foo.bar), तो मुझे बिलकुल यकीन नहीं है कि क्लॉज क्लास से ज्यादा क्लीज या दूसरे तरीके से पसंद करती है। यदि यह वर्ग फ़ाइलों को पसंद करेगा और आपके पास दोनों फाइलें हैं, तो यह स्पष्ट है कि clj फाइल को संपादित करना और फिर नाम स्थान को फिर से लोड करना कोई प्रभाव नहीं है।

BTW: अगर आपके CLASSPATH को ठीक से सेट किया गया है load-file, useतो आपको पहले की आवश्यकता नहीं है।

BTW2: यदि आपको load-fileकिसी कारण से उपयोग करने की आवश्यकता है , तो आप फ़ाइल को संपादित करने के बाद इसे फिर से कर सकते हैं।


14
निश्चित नहीं है कि इसे सही उत्तर के रूप में क्यों चिह्नित किया गया है। यह स्पष्ट रूप से प्रश्न का उत्तर नहीं देता है।
अन्नपूर्णय

5
इस प्रश्न पर आने वाले किसी व्यक्ति के रूप में, मुझे यह उत्तर बहुत स्पष्ट नहीं है।
ctford
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.