我在我的一些宏中使用gensym
函数,这使得很难测试:
因此某些宏的扩展可能是:
'(let [G__10458 (js-obj)]
(aset G__10458 "a" (fn [] (? G__10458.val)))
(aset G__10458 "val" 3) G__10458)
我想要的是测试它是否符合这种类型的模式:
'(let [%1 (js-obj)]
(aset %1 "a" (fn [] (? %1.val)))
(aset %1 "val" 3) %1)
clojure.core.match
库或其他模式匹配库中是否有某些内容可以执行此操作?
答案 0 :(得分:7)
实际测试宏的扩展是非常脆弱的。如果沿着这条路走下去,宏中的任何微小变化都会导致测试失败 - 即使你的宏仍然做同样的事情!
更好的方法 - IMO - 是测试你的宏应该做什么。我们可以放心地假设调用宏有一个可观察的副作用 - 在你的例子中它设置了一个JS对象的属性。
在这种情况下,我不是测试扩展,而是编写一个测试来确保JS对象的状态是你在调用宏之后所期望的。
这将测试与实现分离,让您可以自由地重构宏,因为测试更加强大,并且只有在宏实际上做错了事情时才会失败。
根据经验,我从不测试宏的扩展。
答案 1 :(得分:1)
我现在已经完成了自己的工作。它模式匹配矢量,列表和哈希映射值(集合上的模式匹配和哈希映射键对我来说太难了)。
(defn match-sym? [v]
(and (symbol? v)
(re-find #"^%" (str v))))
(defn match
([f1 f2] (match f1 f2 (atom {})))
([v1 v2 dict]
(cond (or (and (list? v1) (list? v2))
(and (vector? v1) (vector? v2)))
(and (= (count v1) (count v2))
(->> (map #(match %1 %2 dict) v1 v2)
(every? true?)))
(and (hash-map? v1) (hash-map? v2))
(and (= (keys v1) (keys v2))
(->> (map #(match %1 %2 dict) (vals v1) (vals v2))
(every? true)))
(match-sym? v2)
(if-let [vd (@dict v2)]
(match v1 vd dict)
(do (swap! dict assoc v2 v1)
true))
:else (= v1 v2))))
及其用法:
> (match '(1 1) '(1 1))
;=> true
> (match '(1 1) '(%1 %1))
;=> true
> (match '(1 2) '(%1 %1))
;=> false
> (match '(let [x 1] (+ x 2))
'(let [%x 1] (+ %x 2)))
;=> true
> (match '(let [G__42879 (js-obj)]
(aset G__42879 "a" (fn [] (? G__42879.val)))
(aset G__42879 "val" 3) G__42879)
'(let [%x (js-obj)]
(aset %x "a" (fn [] (? %x.val)))
(aset %x "val" 3) %x))
;=> true