4

I'm trying to use Prismatic schema.core/maybe in a precondition for a function taking an optional argument opts, but it seems to always throw an AssertionError when I call the function with no opts:

(require '[schema.core :as schema])

(defn foo [& modules]
  {:pre [(schema/validate (schema/maybe [(schema/enum :foo :bar)]) opts)]}
  :yay)

(foo :foo)
;=> :yay

(foo :foo :bar)
;=> :yay

(foo)
;=> AssertionError Assert failed: (schema/validate (schema/maybe [(schema/enum :foo :bar)]) modules)  user/foo (form-init3808809389777994177.clj:1)

The interesting thing is that this works as expected:

(schema/validate (schema/maybe [(schema/enum :foo :bar)]) nil)
;=> nil

I've used macroexpand on the defn, but nothing looks out of the ordinary there.

I can of course work around this with a precondition like

Josh Glover
  • 25,142
  • 27
  • 92
  • 129

1 Answers1

3

A function precondition must evaluate as truthy for the assertion to pass, but schema/validate returns the expression being tested if validation passes, and throws an exception if it fails. You'll need to alter your precondition to always return true if the validation passes:

(defn foo [& opts]
  {:pre [(or (schema/validate (schema/maybe [(schema/enum :foo :bar)]) opts) true)]}
  :yay)

(foo :foo) ;=> :yay
(foo :foo :bar) ;=> :yay
(foo) ;=> :yay
(foo :baz) ;=> ExceptionInfo Value does not match schema: [(not (#{:foo :bar} :baz))]
Alex
  • 13,811
  • 1
  • 37
  • 50
  • I can't believe I missed that! I wish schema had a `valid?` function for cases like this. I could roll my own with `(comp nil? schema.core/check)`, I suppose. – Josh Glover Sep 24 '14 at 16:27
  • Though come to think of it, if I did that, I would lose Schema's nice error messages, so maybe I'm better off sticking to the `(or (nil? ...))` approach. – Josh Glover Sep 24 '14 at 16:29
  • 1
    `s/check` is the negation of `valid?`, and more useful -- it returns a descriptive error, or nil if validation passes. So a better precondition might be `(not (s/check ...))`. – Jason Wolfe May 22 '15 at 06:02