मैंने केवल क्लोजर का उपयोग करके एक वेब एप्लिकेशन कैसे लिखा



हाल ही में मुझे एक दिलचस्प भाषा मिली - क्लोजर। मुझे तुरंत आलसी और अपरिवर्तनीय संग्रह पसंद आया, एसटीएम, मैक्रोज़, सभी अवसरों के लिए बहुत सारे ब्रैकेट और डीएसएल।
और मैंने केवल क्लोजर का उपयोग करके एक वेब एप्लिकेशन बनाने का प्रयास करने का निर्णय लिया।

आवेदन


यह एक सरल उपशीर्षक साधक बनाने का इरादा था:

पारसर्स


हैरानी की बात है, पार्सर्स लिखना आसान और सुविधाजनक था। पहले, ऐसा लगता था कि बहुत सारे ब्रैकेट थे, लेकिन मैक्रोज़ ( -> , - >> , - <-> और - <> - अगली अभिव्यक्ति के तर्क का परिणाम पारित करना) से बहुत मदद मिली।

उदाहरण के लिए, पायथन और क्लोजर में एक ही काम करने वाले नोटाबोन पार्सर का एक टुकड़ा:
clojureअजगर
(defn get-release-page-result "Get release page result" [page] (-<>> (get-release-page-url page) helpers/fetch (html/select <> [:ul.search-results :li :p :a]) (map (helpers/make-safe book-from-line nil)) (remove nil?) (map episodes-from-book) flatten)) 
 def get_release_page_result(page): """Get release page result""" url = get_release_page_url(page) content = requests.get(url).content soup = BeautifulSoup(content) for line in get_lines_from_soup(soup): book = get_book_from_line(line) if book: yield from get_episodes_from_book(book) 
16 कोष्ठक14 कोष्ठक
पर- लाइब्रेरी का उपयोग पार्सर्स को शुरू करने के लिए किया जाता है, और HTML को पार्स करने के लिए एनलाइव का उपयोग किया जाता है । परिणाम elasticsearch को लिखा गया है।

सर्वर साइड


सर्वर

सर्वर के रूप में, मैंने http-kit को चुना, मुख्यतः क्योंकि मैं वेब सॉकेट चाहता था। और उन्हें यहां उपयोग करना बहुत आसान है, उदाहरण के लिए, अपडेट के बाद सभी ग्राहकों को अनुक्रमित उपशीर्षक की संख्या भेजना इस तरह दिखेगा:
 (add-watch total-count :notifications #(doseq [con @subscribers] (send! con (prn-str {:total-count %4})))) 

मार्ग

रूटिंग के लिए - कंपोजर । Django और अन्य लोकप्रिय रूपरेखाओं से कोई मतभेद नहीं हैं:
 (defroutes main-routes (GET "/" [] (views/index-page)) (GET "/api/list-languages/" {params :params} (api/list-languages params)) (GET "/notifications/" [] push/notifications) (route/resources const/static-path)) 

एपीआई

चूँकि हम हर जगह क्लोज़र का उपयोग करते हैं, इसलिए हमारे एपीआई को मूल डेटा संरचनाओं में और json (अजगर में डेस्कटॉप क्लाइंट के लिए) में परिणाम वापस करना चाहिए। मुझे वह लाइब्रेरी नहीं मिली जो इस तरह से हो सकती है (पहले से मिली हुई) , इसलिए मुझे थोड़ा सा साइकिल चलाना पड़ा और अपने खुद के मिनी डीएल का आविष्कार करना पड़ा:
 (defn- get-writer "Get writer from params" [params] (if (= (:format params) "json") json/write-str prn-str)) (defmacro defapi "Define api method" [name doc args & body] `(defn ~name ~args ((get-writer (first ~args)) ~@body))) 

और एक साधारण उपयोग के मामले के रूप में:
 (defapi list-languages "List all available languages" [params] (models/list-languages)) 

राय

Html रेंडरिंग के लिए, मैंने एक विशेष dsl - हिचकी का उपयोग किया, इसके साथ टेम्पलेट थोड़ा "मार्टियन" दिखता है।
 (defn index-page [] (html5 [:head [:title "Subman - subtitle search service"] [:body [:h1 "Welcome to subman!"]])) 

शैलियों

शैलियों के लिए, क्लोजर का अपना डीएसएल - बगीचा भी है । इसके साथ कोड भी अजीब लगता है:
 (defstyles main [:.search-input {:z-index 100 :background-color "#fff"}] [:.info-box {:text-align "center" :font-size (px 18)}] [:.search-result-holder {:padding-left 0 :padding-right 0}]) 

ग्राहक भाग


मैंने क्लाइंट भाग को पूरी तरह से क्लोजर पर नहीं, बल्कि क्लोजरस्क्रिप्ट पर लिखा था, जो अंततः जावास्क्रिप्ट में संकलित होता है। एक रूपरेखा के रूप में, मैंने अभिकर्मक का उपयोग किया - प्रतिक्रिया के लिए बाध्यकारी। क्लोजर के लिए जेएस, जो हर सेकंड (परमाणुओं के लिए धन्यवाद) के लिए वस्तुओं की जांच नहीं करता है और घटकों का वर्णन करने के लिए हिचकी जैसी डीएसएल का उपयोग करता है:
 (defn info-box "Show info box" [text] [:div.container.col-xs-12.info-box [:h2 text]]) 

यहां सब कुछ बहुत अच्छा है, जब तक आपको सीधे जेएस पुस्तकालयों के साथ काम करने की आवश्यकता नहीं है। उदाहरण के लिए, टाइप फ़ील्ड को खोज फ़ील्ड से जोड़ने का कोड:
 (defn init-autocomplete "Initiale autocomplete" [query langs sources] (let [input ($ "#search-input")] (.typeahead input (js-obj "highlight" true) (js-obj "source" (fn [query cb] (cb (apply array (take const/autocomplete-limit (map #(js-obj "value" %) (get-completion query @langs @sources)))))))) (.on input "typeahead:closed" (fn [] (reset! query (.val input)))))) ) (defn init-autocomplete "Initiale autocomplete" [query langs sources] (let [input ($ "#search-input")] (.typeahead input (js-obj "highlight" true) (js-obj "source" (fn [query cb] (cb (apply array (take const/autocomplete-limit (map #(js-obj "value" %) (get-completion query @langs @sources)))))))) (.on input "typeahead:closed" (fn [] (reset! query (.val input)))))) 

UPD: थोड़ा रिफैक्टिंग के बाद, कोड कम डरावना हो गया:
 (defn completion-source "Source for typeahead autocompletion" [langs sources query cb] (cb (->> (get-completion query @langs @sources) (map #(js-obj "value" %)) (take const/autocomplete-limit) (apply array)))) (defn init-autocomplete "Initiale autocomplete" [query langs sources] (let [input ($ "#search-input")] (.typeahead input #js {:highlight true} #js {:source (partial completion-source langs sources)}) (.on input "typeahead:closed" #(reset! query (.val input))))) 

और "संकलित" फ़ाइल का आकार भी इतना बड़ा नहीं था - केवल 290kb।

एक विशाल प्लस के रूप में, क्लोजर के साथ क्लोजर का उपयोग करते हुए - आप क्लाइंट और सर्वर के लिए क्लजेक्स का उपयोग करके एक कोड लिख सकते हैं।

निष्कर्ष


यद्यपि clojure आपको html, css और javascript के ज्ञान और उपयोग के बिना वेब एप्लिकेशन विकसित करने की अनुमति देता है, लेकिन मैं इस तरह की उत्पादन परियोजनाएं करने की हिम्मत नहीं करूंगा।

परिणाम का स्रोत कोड।
नतीजा खुद।

Source: https://habr.com/ru/post/In222737/


All Articles