2017-01-11 43 views
1

我有一個以下Clojure的代碼渲染功能使用enlive-HTML這使得一個HTML頁面。根據所選語言,使用不同的html模板。如何減少下面Clojure代碼中的重複項?

正如你可以看到,有很多重複的代碼,我想將其刪除。

我正在考慮編寫一些宏,但如果我理解正確,語言(即lang參數)在宏執行時不可用,因爲它在請求中提供,並且處於執行時並且不處於編譯時。

我還試圖修改enlive爲了在以後的某個點添加國際化支持,但我Clojure的技能還沒有。

所以問題是:

如何刪除在下面的代碼的代碼重複?

是enlive-HTML的方式去還是我應該用另一個庫? 有沒有類似於支持i18n的圖書館?

謝謝!

在這裏看到的代碼:

(ns myapp.core 
    (:require [net.cgrand.enlive-html :as e)) 

(deftemplate not-found-en "en/404.html" 
    [{path :path}] 
    [:#path] (e/content path)) 

(deftemplate not-found-fr "fr/404.html" 
    [{path :path}] 
    [:#path] (e/content path)) 


(defn getTemplate [page lang] 
    (case lang 
     :en (case page 
       :page/not-found not-found-en) 
     :fr (case page 
       :page/not-found not-found-fr))) 

(defn render [lang [page params]] 
    (apply (getTemplate page lang) params)) 
+0

究竟你的意思是,回覆:「語言是不是可以在宏執行時間」? –

+0

...如果你的宏正在生成你的'deftemplate',你只需要在編譯時運行它們來執行那個執行。 –

+3

這屬於http:// codereview。stackexchange.com/因爲它已經有效。 – tar

回答

1

,一方面,它不是太難寫一個宏,將產生你這裏的語言任意設定確切的代碼。在另一方面,有可能是比使用deftemplate一個更好的方法 - 事情是def d的事情,你希望通過名稱來引用的源代碼,而你只是想這件事創建並自動使用。但我並不熟悉有效的API,所以我不能說你應該做什麼。

如果你決定與宏堅持相反,你可以寫這樣的:

(defmacro def-language-404s [languages] 
    `(do 
    [email protected](for [lang languages] 
     `(deftemplate ~(symbol (str "not-found-" lang)) ~(str lang "/404.html") 
      [{path# :path}] 
      [:#path] (e/content path#))) 
    (defn get-template [page# lang#] 
     (case page# 
     :page/not-found (case lang# 
          [email protected](for [lang languages 
            clause [(keyword lang) 
              (symbol (str "not-found-" lang))]] 
           clause)))))) 

user> (macroexpand-1 '(def-language-404s [en fr])) 
(do 
    (deftemplate not-found-en "en/404.html" 
    [{path__2275__auto__ :path}] 
    [:#path] (content path__2275__auto__)) 
    (deftemplate not-found-fr "fr/404.html" 
    [{path__2275__auto__ :path}] 
    [:#path] (content path__2275__auto__)) 
    (defn get-template [page__2276__auto__ lang__2277__auto__] 
    (case page__2276__auto__ 
     :page/not-found (case lang__2277__auto__ 
         :en not-found-en 
         :fr not-found-fr)))) 
+0

感謝您的回答。這個宏很好,至少現在是這樣,但是你的答案中的那個對我來說不起作用。它抱怨施工[:#path]看到這裏:https://gist.github.com/anonymous/ec0f2b18269f28d5d1c333945cf386ac – vidi

+0

嗯? ':#path'從你的問題逐字複製;我的宏擴展到你需要的代碼。我不知道你的repl錯誤是怎麼處理的,但它們和':#path'沒有關係,甚至沒有提及它。你複製/粘貼錯了嗎?引導回報搞砸了嗎?誰知道,但錯誤信息與代碼不匹配。 – amalloy

+0

我沒有複製粘貼錯誤。 boot和lein都使用相同版本的nrepl,所以我不認爲它與啓動有關。我嘗試了Clojure v1.7.0和1.8.0,它的行爲相同。我上面說過,這個問題和##中的字符有關:#path,因爲如果我刪除了#那麼錯誤就沒有了。我想這是因爲#在宏裏面有一個意思,它應該被轉義或什麼,但我還沒有找到如何做到這一點。看到這個要點https://gist.github.com/anonymous/312877d8e15a0f5791ff9bab759a203f – vidi

0

頗有幾分宏孚的我給我很高興與結果之後。從幾個漂亮的stackoverflowers一些幫助我寫的enlive頂部以下宏:

(ns hello-enlive 
    (:require [net.cgrand.enlive-html :refer [deftemplate]])) 

(defn- template-name [lang page] (symbol (str "-template-" (name page) "-" (name lang) "__"))) 
(defn- html-file [lang page] (str (name lang) "/" (name page) ".html")) 
(defn- page-fun-name [page] (symbol (str "-page" (name page)))) 

(defmacro def-page [app languages [page & forms]] 
    `(do 
    [email protected](for [lang languages] 
     `(deftemplate ~(template-name lang page) ~(html-file lang page) 
      [email protected])) 

     (defn ~(page-fun-name page) [lang#] 
     (case lang# 
      [email protected](for [lang languages 
        clause [(keyword lang) (template-name lang page)]] 
       clause))) 

     (def ^:dynamic ~app 
     (assoc ~app ~page ~(page-fun-name page))) 
    )) 

(defmacro def-app [app-name languages pages] 
    (let [app (gensym "app__")] 
    `(do 
     (def ~(vary-meta app merge {:dynamic true}) {}) 

     [email protected](for [page# pages] 
      `(def-page ~app ~languages ~page#)) 

     (defn ~app-name [lang# [page# params#]] 
     (apply (apply (get ~app page#) [lang#]) params#))))) 

...然後用於這樣的:

的HTML模板存儲在一個樹這樣

html/fr/not-found.html 
html/fr/index.html 
html/en/not-found.html 
html/en/index.html 
... 

...並呈現邏輯是這樣的:

(def-app my-app [:en :it :fr :de] 
    [ [:page/index [] ] 

    ;... put your rendering here 

    [:page/not-found [{path :path}] 
     [:#path] (content path)]]) 

。 ..和使用情況是這樣的:

... 
(render lang [:page/index {}]) 
(render lang [:page/not-found {:path path}]) 
... 

結果,儘管它或許可以得到改善,我認爲這是相當不錯的,不重複和樣板代碼。