Clojure: 当解构操作失败时,如何在 :pre 报告中返回失败的值

3

根据这篇SO帖子,我想在我的函数中打印前置条件的值。然而,在以下情况下它会失败(可能是解构):

我有一个dir?助手函数(可以跳过这个):

(defn dir? [s]
  "returns true if the string passed is is an existing directory"
  (->> (clojure.java.io/file s)
       ((juxt #(.exists %) #(.isDirectory %)))
       (every? true?)))

它运行得很好,使用is宏,我可以获得一些漂亮的错误消息,其中我可以看到测试和传递的参数:

(is (dir? (io/file "resources/static"))) ;; => true

(is (dir? (io/file "resources/statice"))) ;; typo, error below

在clojure.lang.PersistentList$EmptyList@1(boot.user4515592986834245937.clj:86)中失败,期望:(dir?(io / file“resources / statice”))实际:(not(dir?#object [java.io.File 0x6730a420“resources / statice”]))

但是,当我尝试在先决条件:pre中使用它时,我得到了一个丑陋的错误:

(defn make-something
  [&{:keys [dir]
     :or {dir "default-dir"}}]
  {:pre [(is (dir? (clojure.java.io/file dir)))]}
  ;;... do something with these
 )

(make-something :dir "resources/statices") ;; doesn't exist

clojure.lang.Compiler$CompilerException: java.lang.AssertionError: 断言失败:(is (dir?(io / file dir))), 编译:(boot.user4515592986834245937.clj:80:12) java.lang.AssertionError: 断言失败:(is (dir?(io / file dir)))

我该如何在函数中获得一个像上面这样的漂亮错误消息?

如果有影响的话,我正在使用Clojure 1.7。


“nice”错误信息应该被打印在标准输出(stdout)中。 - DanLebrero
1
memfn在Clojure 1.0之前已被弃用,现在更常见的是#(.isDirectory ...)形式。 - Arthur Ulfeldt
@ArthurUlfeldt 哦,有趣,我没在其他地方看到过。你从哪里得到这个信息的?它不在源代码 https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L3717 中。 - nha
1个回答

1

你需要检查你的代码(dir?函数)。下面的片段对我有效:

(require '[clojure.java.io :as io])

(defn dir? [s]
  (let [dir (io/file s)]
    (and (.exists dir)
         (.isDirectory dir))))

(defn make-something
  [& {:keys [dir] :or {dir "default-dir"}}]
  {:pre [(is (dir? dir))]}
  (println dir))

(make-something :dir "/tmp")
out => /tmp
ret => nil

(make-something :dir "/xxxx")
FAIL in clojure.lang.PersistentList$EmptyList@1 (form-init3332271312167175068.clj:1)
expected: (dir? dir)
actual: (not (dir? "/xxxx"))

AssertionError Assert failed: (is (dir? dir))  user/make-sth (form-init3332271312167175068.clj:1)

这是因为我在 Arthur 的评论后手动编辑了代码。你的代码现在可以在我的 REPL 中运行,所以我接受了你的答案(虽然是 Clojure 1.8 - 我没有使用原来问题中的 1.7 进行测试)。 - nha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接