का उपयोग कर 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 सहायक कार्यों को आपके आवेदन के मुख्य नामस्थान के बजाय उपयोगकर्ता नामस्थान में संदर्भित किया जाता है। जब तक आप हमारे द्वारा बनाई गई स्रोत फ़ाइल को बदल नहीं देते हैं, तब तक वे खो नहीं जाएंगे।
उम्मीद है की यह मदद करेगा!
(use 'foo.bar :reload-all)
मेरे लिए हमेशा ठीक काम किया है। इसके अलावा,(load-file)
कभी भी आवश्यक नहीं होना चाहिए यदि आपके पास अपना क्लासपैथ सही है। "आवश्यक प्रभाव" क्या आपको नहीं मिल रहा है?