2009-11-10 24 views
14

मैं एक मैक्रो लिखने का प्रयास कर रहा हूं जो इसे दिए गए तर्कों के आधार पर जावा सेटटर विधियों को कॉल करेगा।क्लोजर मैक्रो में गतिशील विधि कॉल?

तो, उदाहरण के लिए:

(doto (new MyClass) 
    (.setUsername "fred") 
    (.setPassword "wilma")) 

आप इस से निपटने के लिए कैसे की सिफारिश करेंगे:

(my-macro login-as-fred {"Username" "fred" "Password" "wilma"}) 

निम्नलिखित की तरह कुछ करने के लिए विस्तार कर सकते हैं?

विशेष रूप से, मुझे सेटटर विधि नाम बनाने का सबसे अच्छा तरीका काम करने में परेशानी हो रही है और इसे मैक्रो द्वारा प्रतीक के रूप में व्याख्या किया गया है।

+0

तुम सच में 'doto' पहला तर्क के रूप में एक वर्ग के साथ कॉल करना चाहते हैं:

(defmacro configure [object options] '(doto ~object [email protected](map (fn [[property value]] (let [property (name property) setter (str ".set" (.toUpperCase (subs property 0 1)) (subs property 1))] '(~(symbol setter) ~value))) options)))

यह तो के रूप में इस्तेमाल किया जा सकता: यहाँ मेरी ले रहा है? आप उस वर्ग के उदाहरण के बजाय क्लास ऑब्जेक्ट में चीजें करने जा रहे हैं। –

+0

आह, धन्यवाद - वह एक टाइपो था। मैंने इसे अभी सही कर दिया है। – npad

उत्तर

20

मैक्रो है कि आप वास्तव में वर्ग या ऐसा कुछ में खुदाई करने के लिए की जरूरत नहीं है के बारे में अच्छी बात यह है। आपको बस कोड लिखना है जो उचित एस-एक्सप्रेशन उत्पन्न करता है।

पहले एक समारोह की तरह (.setName 42)

(defn make-call [name val] 
    (list (symbol (str ".set" name) val))) 

एक रों अभिव्यक्ति एक मैक्रो भाव पैदा करते हैं और एक doto अभिव्यक्ति में प्लग (~ @) उन्हें उत्पन्न करने के लिए तो।

(defmacro map-set [class things] 
    `(doto ~class [email protected](map make-call things)) 

क्योंकि यह एक मैक्रो यह पता है कि वर्ग बात उस पर बुलाया जा रहा है या वर्ग जिस पर यह उपयोग किया जाएगा मौजूद है भी कि नहीं है कभी नहीं है।

+0

काम नहीं करता है। एक चीज के लिए आप '.' के मान नहीं ले सकते हैं। –

+0

ब्रायन कार्पर के परिवर्तनों को शामिल करने के लिए तय –

2

आप गोली काटने और clojure.lang.Reflector/invokeInstanceMethod इस तरह उपयोग करने के लिए:

(defn do-stuff [obj m] 
    (doseq [[k v] m] 
    (let [method-name (str "set" k)] 
     (clojure.lang.Reflector/invokeInstanceMethod 
     obj 
     method-name 
     (into-array Object [v])))) 
    obj) 

(do-stuff (java.util.Date.) {"Month" 2}) ; use it 

किसी मैक्रो के लिए कोई ज़रूरत नहीं (जहाँ तक मुझे पता है, एक मैक्रो, या तो प्रतिबिंब को नाकाम करने की अनुमति नहीं होगी, कम से कम के लिए सामान्य मामला)।

+0

मैक्रो पट्टे पर प्रतिबिंब को प्रतिबिंबित नहीं करता है। यह इस तथ्य के संबंध में स्पष्ट रूप से एस-अभिव्यक्ति उत्पन्न करता है कि वे कक्षाओं के संदर्भ में होते हैं। –

+0

इसके लिए प्रतिबिंब का उपयोग करना बहुत खराब है। मैक्रोज़ और प्रतिबिंब दोनों भारी उपकरण हैं जिन्हें आपको उपयोग करने से पहले दो बार सोचना चाहिए, लेकिन यदि आप फ़ील्ड को अक्षर के रूप में सेट करने के लिए निर्दिष्ट कर सकते हैं तो मैक्रोज़ बहुत अच्छे लगते हैं। – amalloy

4

कोई (मुझे विश्वास है कि आर्थर उलफेल्ड) का उत्तर एक उत्तर था जो लगभग सही था, लेकिन अब इसे हटा दिया गया है। यदि वह दोबारा पोस्ट करता है तो कृपया इसे मेरे बजाय स्वीकार करें। (या PMF के स्वीकार करते हैं।) यह एक काम कर संस्करण है:

(defmacro set-all [obj m] 
    `(doto ~obj [email protected](map (fn [[k v]] 
         (list (symbol (str ".set" k)) v)) 
        m))) 

user> (macroexpand-1 '(set-all (java.util.Date.) {"Month" 0 "Date" 1 "Year" 2009})) 
(clojure.core/doto (java.util.Date.) (.setMonth 0) (.setDate 1) (.setYear 2009)) 

user> (set-all (java.util.Date.) {"Month" 0 "Date" 1 "Year" 2009}) 
#<Date Fri Jan 01 14:15:51 PST 3909> 
+0

ठीक है, मैंने इसे हटा दिया। –

5

कृपया मैक्रो के लिए list साथ स-भाव का निर्माण नहीं है। यह मैक्रो की स्वच्छता को गंभीर रूप से चोट पहुंचाएगा। गलती करना बहुत आसान है, जो ट्रैक करना मुश्किल है। कृपया हमेशा वाक्यविन्यास-उद्धरण का प्रयोग करें! हालांकि, इस मामले में यह कोई समस्या नहीं है, सिंटैक्स-कोट का उपयोग करने की आदत में जाना अच्छा है!

अपने मानचित्र के स्रोत के आधार पर, आप कीवर्ड को कुंजी के रूप में उपयोग करने पर भी विचार कर सकते हैं ताकि इसे अधिक क्लोजर-जैसा दिख सके।

user=> (macroexpand-1 '(configure (MyClass.) {:username "fred" :password "wilma"})) 
(clojure.core/doto (MyClass.) (.setUsername "fred") (.setPassword "wilma"))
+0

मैं असहमत हूं। 'सूची' का उपयोग करना खतरनाक हो सकता है यदि आप समझ नहीं पाते कि क्या हो रहा है, लेकिन यदि आप स्वयं को केवल' सिंटैक्स-कोट 'का उपयोग करने के लिए प्रतिबंधित करते हैं, तो मैक्रोज़ आंतरिक रूप से कैसे काम करते हैं, इस पर स्पर्श करना बहुत आसान होता है, और मानते हैं कि' वाक्यविन्यास-उद्धरण 'एकमात्र मैक्रो-बिल्डिंग टूल है। एक बात मैं * * के खिलाफ सलाह देना चाहूंगा '(नक्शा (एफएन [[x y]] ...) coll) '; यह अधिक स्पष्ट रूप से '([[x y] coll] के लिए व्यक्त किया गया है ...) '। – amalloy

+0

हाँ, मैं अक्सर पर्याप्त रूप से उपयोग नहीं करता हूं। हालांकि मैं सूची से संबंधित अपनी राय के लिए खड़ा हूं। उद्धरण बनाम बैकटिक गलती करना आसान है। और यह जंगली में अक्सर किया जाता है। Clojure.core में भी और लोगों द्वारा contrib जो निश्चित रूप से मैक्रोज़ काम कैसे पता है। वाक्यविन्यास-उद्धरण बस बग की एक पूरी कक्षा को समाप्त करता है। तथ्य के बाद फिक्सिंग से हमेशा बेहतर। – kotarak

+0

ठीक है। "बग का वर्ग" शायद थोड़ा सा है। लेकिन यह एक दुर्घटना के बजाय प्रतीक कैप्चर स्पष्ट बनाता है। – kotarak

संबंधित मुद्दे