2016-08-05 8 views
0

私はEnliveが好きですが、次のことを観察すると多少混乱します。Enliveはどのようにルール/変換を評価しますか?

は(also available on github)次Clojureのコードを考えてみましょう:

ここ
(ns enlivetest.core 
    (:require [net.cgrand.enlive-html :refer [deftemplate defsnippet] :as html])) 

(deftemplate page "index.html" 
    [ctx] 
    [:.foobar] (html/content (do (println "GENERATING FOOBAR") 
           "===FOOBAR==="))) 

このHTMLテンプレート(リソース/ index.htmlを):

<!DOCTYPE html> 
<html> 
    <body> 
    </body> 
</html> 

pageテンプレートを呼び出すとき、私は期待したいですルールのセレクタ:.foobarに一致するHTMLタグがないため、ルールの右側(変換)を完全に無視します。

結局のところしかし、ルールの右手側は、実際に評価を受けるん:

user=> (require '[enlivetest.core :as c]) 
nil 
user=> (c/page {}) 
GENERATING FOOBAR 
GENERATING FOOBAR 
("<!DOCTYPE html>\n" "<" "html" ">" "\n " "<" "body" ">" "\n " "</" "body" ">" "\n\n" "</" "html" ">") 

(もちろん、それも二回評価されます - テンプレート内の各ルートHTML要素のためとして、いったんそうみたいです)。

しかし、セレクタに一致する要素はありませんが、なぜ評価されていますか?これは正しい動作ですか?私はここで何かを見逃していますか?

この例では、READMEに示されているように、Enlive 1.1.6を使用しています。

明確にされています。

EDIT#1:

それは(おかげで@leetwinskiする)結局のところ、どのように物事の仕事の私の仮定が間違っていました:

私はdeftemplateマクロは右のみを評価することを想定しましたそのルールのセレクタが指定されたHTML内の要素と一致するとき、ルールの変換側(変換部分)に渡されます。

しかし、正しいはこれです:

ルールの右手側は常に定義されたテンプレート関数の呼び出し(例えばpage)中に評価されますし、そのターンにする関数に評価することが期待されています呼び出されたときに望ましいコンテンツ(この例では "=== FOOBAR ===")に評価します。セレクタと一致する要素に対してのみ呼び出されるのはこの関数です。

これは、 html/contentはそのような関数を評価します(直接的には目的のコンテンツではありません)。

(deftemplate page "index.html" 
    [ctx] 
    [:.foobar] #((html/content (do (println "GENERATING FOOBAR") 
           "===FOOBAR===")) %)) 

次のような出力になりますどの:物事は私が当初の予想通り、私はこのようにそれを書くことができます動作させるためには

user=> (c/page {}) 
("<!DOCTYPE html>\n" "<" "html" ">" "\n " "<" "body" ">" "\n " "</" "body" ">" "\n\n" "</" "html" ">") 

または<div class="foobar"></div>への追加HTMLテンプレート:

user=> (c/page {}) 
GENERATING FOOBAR 
("<!DOCTYPE html>\n" "<" "html" ">" "\n " "<" "body" ">" "\n\t\t" "<" "div" " " "class" "=\"" "foobar" "\"" ">" "===FOOBAR===" "</" "div" ">" "\n " "</" "body" ">" "\n\n" "</" "html" ">") 

EDIT#2:

これは数週間経っていますが、私はまだこれがEnliveでどのように実装されているのか苦労しています。私はルールの変形部分を#((html/content ...) %)に何度も繰り返しラップしています。

現在のレンダリングプロセスにも関係しない場合でも、Enliveが変換を(すべてまたは複数回)評価する理由について誰かが説明していますか?

これは私以外の誰かに迷惑をかけていないと私は本当に驚いているので、私は何かを見落としているかもしれません。

それはセレクタ・ツー・機能のペアを取る:

答えて

2

理由はenliveのdeftemplateマクロの性質です。あなたには、関数を動的にここで生成されます。

(html/content (do (println "GENERATING FOOBAR") "===FOOBAR===")) 

contentちょうど一致した場合に呼び出されることになる機能を、作成します。

user> ((html/content "this" "is" "fine") {:content []}) 
{:content ("this" "is" "fine")} 

contentはマクロではありませんので、その引数を評価する必要があります。 あなたが見ているのは、誤って一致する関数呼び出しではなく、一致した場合に呼び出される関数の世代への呼び出しです。

簡単にあなたのdeftemplateフォームのマクロ展開でそれを見ることができました:

(def page 
(let* 
    [opts__8226__auto__ 
    (merge (html/ns-options (find-ns 'user)) {}) 
    source__8227__auto__ 
    "index.html"] 
    (html/register-resource! source__8227__auto__) 
    (comp 
    html/emit* 
    (let* 
     [nodes29797 
     (map 
      html/annotate 
      (html/html-resource 
      source__8227__auto__ 
      opts__8226__auto__))] 
     (fn* 
     ([ctx] 
      (doall 
      (html/flatmap 
       (fn* 
       ([node__8199__auto__] 
        (html/transform 
         (html/as-nodes node__8199__auto__) 
        [:.foobar] 
        (html/content 
         (do 
         (println "GENERATING FOOBAR") 
         "===FOOBAR==="))))) 
       nodes29797)))))))) 

ので、printlnの正しい文字列は次のようになります。

(deftemplate page "index.html" 
    [ctx] 
    [:.foobar] (html/content (do (println "GENERATING FUNCTION SETTING FOOBAR AS THE NODE CONTENT") 
           "===FOOBAR==="))) 

あなたが期待する行動がこのように達成することができます

user> 
(deftemplate page "index.html" 
    [ctx] 
    [:.foobar] (fn [node] (assoc node :content 
           (do (println "GENERATING FOOBAR" node) 
            "===FOOBAR===")))) 
#'ttask.core/page 

user> (page {}) 
("<!DOCTYPE html>\n" "<" "html" ">" "\n " "<" "body" ">" "\n " "</" "body" ">" "\n\n" "</" "html" ">") 

また、 "foobar"クラスをindex.htmlの本文に追加すると、これが実行されます(HTMLを変更した後deftemplate再実行することを忘れないでください):非常にうまくその説明を起草のための

user> (page {}) 
GENERATING FOOBAR {:tag :body, :attrs {:class foobar}, :content []} 
("<!DOCTYPE html>\n" "<" "html" ">" "\n " "<" "body" " " "class" "=\"" "foobar" "\"" ">" "=" "=" "=" "F" "O" "O" "B" "A" "R" "=" "=" "=" "</" "body" ">" "\n\n" "</" "html" ">") 
+0

感謝を!私は今、なぜそれがそれと同じように動作するのか理解しています。 – Oliver

+0

しかし、ルールの変換部分が同じルールのセレクタが一致するときだけ評価されると誤解される可能性があるので、動作する方法は可能な限り直感的な方法ではないと思います。 私はおそらく、この事実を少なくともEnliveのdocs/READMEに明示的にするプルリクエストを提出するでしょう。 – Oliver

関連する問題