2010-10-22 10 views
8

मेरे पास एक क्लोजर प्रोग्राम है जिसे मैं मैवेन का उपयोग कर एक जेएआर फ़ाइल के रूप में बनाता हूं। जेएआर मैनिफेस्ट में एंबेडेड एक बिल्ड-वर्जन नंबर है, जिसमें बिल्ड टाइमस्टैम्प भी शामिल है।रनटाइम पर क्लोजर "स्थिरांक" सेट करना

मैं आसानी से निम्नलिखित कोड का उपयोग कर जार प्रकट से रनटाइम पर इस पढ़ सकते हैं:

(defn set-version 
    "Set the version variable to the build number." 
    [] 
    (def version 
    (-> (str "jar:" (-> my.ns.name (.getProtectionDomain) 
            (.getCodeSource) 
            (.getLocation)) 
        "!/META-INF/MANIFEST.MF") 
     (URL.) 
     (.openStream) 
     (Manifest.) 
     (.. getMainAttributes) 
     (.getValue "Build-number")))) 

लेकिन मुझे बताया गया है कि यह बुरे कर्म defn अंदर def उपयोग करने के लिए है।

रनटाइम पर निरंतर सेट करने के लिए क्लोजर-बेवकूफ तरीका क्या है? मेरे पास स्पष्ट रूप से def के रूप में मेरे कोड में एम्बेड करने के लिए बिल्ड-संस्करण जानकारी नहीं है, लेकिन मैं प्रोग्राम शुरू होने पर main फ़ंक्शन से एक बार (और सभी के लिए) सेट करना चाहता हूं। इसके बाद इसे चल रहे कोड के def के रूप में उपलब्ध होना चाहिए।

अद्यतन: बीटीडब्ल्यू, क्लोजर को थोड़ी देर में आने वाली सबसे अच्छी भाषाओं में से एक होना है। रिच हिकी के लिए कुडोस!

उत्तर

7

मुझे अभी भी लगता है कि आपके आवेदन की main विधि में alter-var-root का उपयोग करने का सबसे साफ तरीका है।

(declare version) 

(defn -main 
    [& args] 
    (alter-var-root #'version (constantly (-> ...))) 
    (do-stuff)) 

यह संकलन समय पर वार ब्यौरा देता है, एक बार रनटाइम पर उसकी जड़ मूल्य सेट, deref आवश्यकता नहीं है और मुख्य थ्रेड के लिए बाध्य नहीं है। आपने अपने पिछले प्रश्न में इस सुझाव का जवाब नहीं दिया था। क्या आपने इस दृष्टिकोण को आजमाया?

+0

मैंने कोशिश नहीं की है, लेकिन मैं करूँगा। दिलचस्प लगता है। मान सेट होने के बाद कोई प्रदर्शन दंड नहीं। मैं कमांड लाइन विकल्पों से मूल्यों को सेट करने के लिए इस तकनीक का भी उपयोग कर सकता हूं - केवल एक बार सेट करने की आवश्यकता है। – Ralph

1

मुझे आशा है कि मुझे इस बार कुछ याद नहीं आएगा।

यदि संस्करण स्थिर है, तो इसे एक बार परिभाषित किया जा रहा है और इसे बदलने के लिए नहीं जा रहा है, आप आसानी से defn को हटा सकते हैं और (def संस्करण ...) अकेले रख सकते हैं। मुझे लगता है कि आप इसे किसी कारण से नहीं चाहते हैं।

आप एक fn में वैश्विक चर बदलना चाहते हैं मुझे लगता है कि अधिक मुहावरेदार जिस तरह से डेटा और पहुँच स्टोर करने के लिए संगामिति निर्माण से कुछ का उपयोग और एक सुरक्षित तरीका में इसे बदल उदाहरण के लिए के लिए है:

(def *version* (atom "")) 

(defn set-version! [] (swap! *version* ...)) 
+0

@ जेनीरा: "मुझे आशा है कि मुझे इस बार कुछ याद नहीं आएगा।" :-) मैं ऐसा नहीं कर सकता क्योंकि तब यह संकलन-समय (मेरा मानना ​​है) पर मूल्यांकन करता है और अभी तक पढ़ने के लिए कोई जार फ़ाइल नहीं है। – Ralph

+0

हेहे: -पी ठीक है और दूसरा विकल्प? (तीसरा यह होगा कि फ़ंक्शन एक लालसा करने के बजाय तारों को वापस कर देगा लेकिन यह विभिन्न कॉलों के लिए अक्षम हो सकता है) – jneira

+0

मैं सोच रहा था कि मुझे परमाणुओं के साथ कुछ करने की आवश्यकता होगी, मैंने सोचा कि सिंक्रनाइज़ेशन ओवरहेड आदि के साथ, यह अधिक होगा, शायद 'मुख्य' फ़ंक्शन से 'def' को कॉल करना ठीक होगा, भले ही यह "फहरा हुआ" हो। – Ralph

4

आप गतिशील बाध्यकारी का उपयोग कर सकते हैं।

(declare *version*) 

(defn start-my-program [] 
    (binding [*version* (read-version-from-file)] 
    (main)) 

अब main और हर कार्य में यह कहता है *version* का मूल्य देखेंगे।

+0

+1 मुझे याद दिलाने के लिए "और हर फंक्शन जिसे कॉल करता है" एक गतिशील बाध्यकारी होने का कारण बन सकता है, शायद समस्या को ठीक करता है – jneira

+0

मुझे यह पसंद है! मैं परमाणुओं का उपयोग करने जा रहा था, लेकिन मुझे इसे और जानने की आवश्यकता होगी। वेरिएबल्स (स्थिरांक) जिन्हें मुझे सेट करने की आवश्यकता है, बाकी प्रोग्राम को वैसे भी चलाने से पहले सेट किया जाना चाहिए। संस्करण संख्या के अलावा, मैं अपाचे कॉमन्स-क्ली के साथ प्राप्त कमांड लाइन विकल्पों को रिकॉर्ड करने के लिए भी समाधान का उपयोग करने जा रहा हूं। – Ralph

+3

'बाध्यकारी 'की धागा-बाध्यता याद रखें। 'बाउंड-एफएन' भी देखें। – kotarak

2

जबकि कोटरक का समाधान बहुत अच्छी तरह से काम करता है, यहां एक वैकल्पिक दृष्टिकोण है: अपना कोड एक ज्ञापन फ़ंक्शन में बदलें जो संस्करण देता है। इस तरह:

(def get-version 
(memoize 
    (fn [] 
    (-> (str "jar:" (-> my.ns.name (.getProtectionDomain) 
      (.getCodeSource) 
      (.getLocation)) 
     "!/META-INF/MANIFEST.MF") 
    (URL.) 
    (.openStream) 
    (Manifest.) 
    (.. getMainAttributes) 
    (.getValue "Build-number"))))) 
संबंधित मुद्दे