fulcrologic / guardrails

Efficient, hassle-free function call validation with a concise inline syntax for clojure.spec and Malli
Eclipse Public License 2.0
240 stars 26 forks source link

>defn reports spec failure of spec that is registered, but not required when using s/keys #20

Closed MrEbbinghaus closed 3 years ago

MrEbbinghaus commented 3 years ago

Guardrails reports spec failure even though spec isn't defined in function definition. Seems just to happen with a s/keys spec

Have a look at this REPL Session:

(require '[clojure.spec.alpha :as s])
;; => nil
(s/def ::foo int?)
;; => :user/foo
(s/def ::bar int?)
;; => :user/bar
(require '[com.fulcrologic.guardrails.core :refer [>defn =>]])
;; => nil
(>defn add-foo-bar [{::keys [foo bar]}]
  [any? => (s/keys :req [::foo])]
  {::foo 42
   ::bar (+ foo bar)})
;; => #'user/add-foo-bar
(add-foo-bar {::foo 1
              ::bar 3.0})
;; => #:user{:foo 42, :bar 4.0}

;; add-foo-bar's return type
;; -- Spec failed --------------------
;; 
;;   {:user/foo 42, :user/bar 4.0}
;;                            ^^^
;; 
;; should satisfy
;; 
;;   int?
;; 
;; -- Relevant specs -------
;; 
;; :user/bar:
;;   clojure.core/int?
;; 
;; -------------------------
;; Detected 1 error
;;
;; java.lang.AssertionError: 
;;    com.fulcrologic.guardrails.core$callsite_exception.invokeStatic (core.cljc:574)
;;    com.fulcrologic.guardrails.core$callsite_exception.invoke (core.cljc:574)
;;    user$add_foo_bar.invokeStatic (form-init18326497060998450108.clj:1)
;;    user$add_foo_bar.invoke (form-init18326497060998450108.clj:1)
;;    ...

Fails as well

(>defn add-foo-bar [{::keys [foo bar]}]
  [(s/keys :req [::foo]) => any?]
  {::foo 42
   ::bar (+ foo bar)})
;; => #'user/add-foo-bar
(add-foo-bar {::foo 1
              ::bar 3.0})
;; => #:user{:foo 42, :bar 4.0}
;; like above

Following works fine:

(>defn add-foo-bar [{::keys [foo bar]}]
  [any? => map?]
  {::foo 42
   ::bar (+ foo bar)})
;; => #'user/add-foo-bar
(add-foo-bar {::foo 1
              ::bar 3.0})
;; => #:user{:foo 42, :bar 4.0}
MrEbbinghaus commented 3 years ago

This behavior is described in the documentation for s/keys

In addition, the values of all namespace-qualified keys will be validated (and possibly destructured) by any registered specs. Note: there is no support for inline value specification, by design.