Clojure.Spec验证的有意义的错误消息:pre

Die*_*ngs 18 clojure clojure.spec

我用了最后几天深入挖掘了Clojure和ClojureScript中的clojure.spec.

到现在为止我觉得最有用的,使用规格为警卫:pre:post在依赖于数据在一定格式的公共职能.

(defn person-name [person]
  {:pre [(s/valid? ::person person)]
   :post [(s/valid? string? %)]}
  (str (::first-name person) " " (::last-name person)))
Run Code Online (Sandbox Code Playgroud)

这种方法的问题是,我得到一个java.lang.AssertionError: Assert failed: (s/valid? ::person person)没有任何关于究竟没有达到规范的信息.

有没有人一个想法如何得到一个更好的错误信息:pre:post警卫?

我知道conformexplain*,但这对那些:pre:post警卫没有帮助.

Ale*_*ler 11

在较新的alpha中,现在s/assert可用于断言输入或返回值与规范匹配.如果有效,则返回原始值.如果无效,则会在解释结果中引发断言错误.断言可以打开或关闭,甚至可以选择从编译的代码中完全省略,以产生0生产影响.

(s/def ::first-name string?)
(s/def ::last-name string?)
(s/def ::person (s/keys :req [::first-name ::last-name]))
(defn person-name [person]
  (s/assert ::person person)
  (s/assert string? (str (::first-name person) " " (::last-name person))))

(s/check-asserts true)

(person-name 10)
=> CompilerException clojure.lang.ExceptionInfo: Spec assertion failed
val: 10 fails predicate: map?
:clojure.spec/failure  :assertion-failed
 #:clojure.spec{:problems [{:path [], :pred map?, :val 10, :via [], :in []}], :failure :assertion-failed}
Run Code Online (Sandbox Code Playgroud)

  • 能够在 pre: 和 :post “钩子”中使用 s/assert 或 s/explain* 会很好...... (2认同)

Pau*_*der 6

我认为这个想法是你spec/instrument用来验证函数输入和输出而不是前后条件.

这篇博文的底部有一个很好的例子:http://gigasquidsoftware.com/blog/2016/05/29/one-fish-spec-fish/.快速摘要:你可以使用:args和:ret键定义一个函数的规范,包括输入和返回值(因此替换前置条件和后置条件),使用spec/fdef,检测它,并得到类似于使用explain时的输出不符合规格.

从该链接派生的最小示例:

(spec/fdef your-func
    :args even?
    :ret  string?)


(spec/instrument #'your-func)
Run Code Online (Sandbox Code Playgroud)

这相当于给出了一个前提条件,即函数有一个整数参数和一个后置条件,它返回一个字符串.除了你得到更多有用的错误,就像你正在寻找.

官方指南中的更多细节:https://clojure.org/guides/spec ---请参阅标题"Spec'ing functions".

  • 这不会检查返回值,因此仪器仅替换:pre.我们的想法是使用test.check来测试您的函数是否正确地将输入映射到输出.然后通过正常测试对仪器中的功能进行检测和测试.最后,您可以在需要生产防护的地方使用s/assert,例如Alex Miller的答案中提到的. (4认同)