3

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库或其他模式匹配库中是否有这样做的东西?

4

2 回答 2

7

实际测试宏的扩展是非常脆弱的。如果你沿着这条路走,你的宏中的任何微小变化都会导致你的测试失败——即使你的宏仍然做同样的事情!

更好的方法 - IMO - 是测试你的宏应该做什么。我们可以安全地假设调用您的宏具有可观察到的副作用 - 在您的示例中,它在 JS 对象中设置属性。

在这种情况下,我不会测试扩展,而是编写一个测试来确保 JS 对象的状态是您在调用宏后所期望的状态。

这将测试与实现分离,让您可以自由地重构您认为合适的宏,因为测试更加健壮,并且只有在您的宏实际上做错事时才会失败。

根据经验,我永远不会测试宏的扩展。

于 2013-05-02T01:54:30.620 回答
1

我现在已经推出了自己的。它在向量、列表和哈希映射 val 上进行模式匹配(现在对集合和哈希映射键的模式匹配对我来说太难了)。

(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
于 2013-05-05T00:52:14.087 回答