How can I get Clojure :pre & :post to report their failing value?

南笙酒味 提交于 2019-11-27 20:05:34

You could wrap your predicate with the is macro from clojure.test

(defn string-to-string [s1] 
  {:pre  [(is (string? s1))]
   :post [(is (string? %))]}
 s1)

Then you get:

(string-to-string 10)
;FAIL in clojure.lang.PersistentList$EmptyList@1 (scratch.clj:5)
;expected: (string? s1)
;actual: (not (string? 10))

@octopusgrabbus kind of hinted at this by proposing (try ... (catch ...)), and you mentioned that that might be too noisy, and is still wrapped in an assert. A simpler and less noisy variant of this would be a simple (or (condition-here) (throw-exception-with-custom-message)) syntax, like this:

(defn string-to-string [s1] 
  {:pre  [(or (string? s1)
              (throw (Exception. (format "Pre-condition failed; %s is not a string." s1))))]
   :post [(or (string? %)
              (throw (Exception. (format "Post-condition failed; %s is not a string." %))))]}
  s1)

This essentially lets you use pre- and post-conditions with custom error messages -- the pre- and post-conditions are still checked like they normally would be, but your custom exception is evaluated (and thus thrown) before the AssertionError can happen.

Something like below where clojure spec is explaining the problem? This will throw an assertion error which you can catch.

 (defn string-to-string [s1] 
  {:pre [ (or (s/valid?  ::ur-spec-or-predicate s1) 
              (s/explain ::ur-spec-or-predicate s1)]}
  s1)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!