2017-01-11 47 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}]) 
... 

结果,尽管它或许可以得到改善,我认为这是相当不错的,不重复和样板代码。