首页 > 解决方案 > 如何修复这个宏?

问题描述

我正在尝试将我的宏转换为以下扩展:

(re-frame.core/reg-event-db
 :some-name
 (fn [db [foo bar]]
   (assoc db :foo foo :bar bar)
   ))

到目前为止我有这个

(defmacro db-event 
  [name params & body]
  `(re-frame.core/reg-event-db
    ~name
    (fn [db ~params]
      ~@body)))

但是当我尝试使用时,这并没有真正起作用

(db-event :some-name [foo bar] 
  (assoc db :foo foo :bar bar))

我得到以下信息:

------ WARNING - :undeclared-var -----------------------------------------------
 Resource: :1:17
 Use of undeclared Var vendo.macros/foo
--------------------------------------------------------------------------------
------ WARNING - :undeclared-var -----------------------------------------------
 Resource: :1:21
 Use of undeclared Var vendo.macros/bar
--------------------------------------------------------------------------------
------ WARNING - :undeclared-var -----------------------------------------------
 Resource: :1:33
 Use of undeclared Var vendo.macros/db
--------------------------------------------------------------------------------
------ WARNING - :undeclared-var -----------------------------------------------
 Resource: :1:41
 Use of undeclared Var vendo.macros/foo
--------------------------------------------------------------------------------
------ WARNING - :undeclared-var -----------------------------------------------
 Resource: :1:50
 Use of undeclared Var vendo.macros/bar
--------------------------------------------------------------------------------


(re-frame.core/reg-event-db {:foo nil, :bar nil} (cljs.core/fn [vendo.macros/my-db nil]))

我该如何解决?

标签: clojuremacros

解决方案


首先查看有关宏的此答案。然后慢慢建立起来。

不是这样,因为db它只在你构造的函数中使用,它不需要是宏调用的参数。

第一次迭代:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test))

(defn db-event-impl
  [[name params]]
  (spyx name)
  (spyx params)
  (let [result `(re-frame.core/reg-event-db
                  )
        ]
    (spyx-pretty result))
  )

(dotest
  (db-event-impl (quote [:some-name [foo bar]]))
  )

结果:

name => :some-name
params => [foo bar]
result => 
(re-frame.core/reg-event-db)

添加更多代码:

(defn db-event-impl
  [[name params]]
  (spyx name)
  (spyx params)
  (let [result `(re-frame.core/reg-event-db
                  ~name
                  (fn [~'db ; trick to prevent namespacing of `db`
                       ~params ]
                    (assoc ~'db )

                    ) ) ]
    (spyx-pretty result)) )

并得到:

name => :some-name
params => [foo bar]
result => 
(re-frame.core/reg-event-db
 :some-name
 (clojure.core/fn [db [foo bar]] (clojure.core/assoc db)))

为该assoc部分添加更多内容:

  (let [assoc-form (->list
                     (apply glue
                       (quote [assoc db])
                       (forv [param params]
                         [(->kw param) param])))
        result     `(re-frame.core/reg-event-db
                      ~name
                      (fn [~'db ; trick to prevent namespacing of `db`
                           ~params]
                        (assoc ~'db)

                        ))]
    (spyx assoc-form)
    (spyx-pretty result)))

结果:

name => :some-name
params => [foo bar]
assoc-form => (assoc db :foo foo :bar bar)
result => 
(re-frame.core/reg-event-db
 :some-name
 (clojure.core/fn [db [foo bar]] (clojure.core/assoc db)))

然后把它们放在一起:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test))

(defn db-event-impl
  [[name params]]
  (let [assoc-form (->list
                     (apply glue
                       (quote [assoc db])
                       (forv [param params]
                         [(->kw param) param])))
        result     `(re-frame.core/reg-event-db
                      ~name
                      (fn [~'db ; trick to prevent namespacing of `db`
                           ~params]
                        ~assoc-form))]
    result))

(defmacro db-event
  [& args]
  (db-event-impl args))

(dotest
  (let [expected (quote
                   (re-frame.core/reg-event-db
                     :some-name
                     (clojure.core/fn [db [foo bar]]
                       (assoc db :foo foo :bar bar))))]
    (is= expected
      (db-event-impl (quote [:some-name [foo bar]])))))

推荐阅读