0

私はEnliveが好きですが、次のことを観察したときに少し混乱しました。

次の Clojure コードを検討してください ( github でも入手できます)。

(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 テンプレート (resources/index.html) は次の場所にあります。

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

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

しかし、結局のところ、ルールの右側は実際に評価されます。

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 要素に対して 1 回ずつ、2 回評価されることさえあります)。

しかし、セレクターに一致する要素がないのに、なぜ評価されるのでしょうか? これは正しい動作ですか?ここで明らかな何かが欠けていますか?

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

明確化は大歓迎です。

編集#1:

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

deftemplateルールのセレクターが指定された HTML の要素と一致する場合、マクロはルールの右側 (変換部分) のみを評価すると想定していました。

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

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

これは、 eghtml/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" ">")

編集#2:

数週間経ちましたが、これが Enlive にどのように実装されているのか、いまだに苦労しています。ルールの変換部分を#((html/content ...) %)何度も何度もラップしているように見えます。

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

これが私以外の誰も気にしないように見えることに本当に驚いているので、私は何かを見落としているかもしれません.

4

1 に答える 1

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" ">")

deftemplateまた、index.html の body にクラス "foobar" を追加すると、次のようになります ( html を変更した後に再実行することを忘れないでください)。

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" ">")
于 2016-08-05T17:08:06.600 に答える