Using s/& and Mark’s fdef does “work” but the failure messages seem misleading:

 

boot.user=> (f 2 :even 4)

nil

boot.user=> (f 2 :even 3)

 

clojure.lang.ExceptionInfo: Call to #'boot.user/f did not conform to spec:

                            val: () fails at: [:args :options] predicate: (& (* 
(cat :clojure.spec/k keyword? :clojure.spec/v :clojure.spec/any)) 
:clojure.spec/kvs->map (keys :opt-un [:boot.user/even])),  Insufficient input

                            :clojure.spec/args  (2 :even 3)

                            :clojure.spec/failure  :instrument-check-failed

 

Why Insufficient input here? Why doesn’t it point at 3 failing the ::even or 
even? predicate?

                            

boot.user=> (f 2 :even 4 :odd 5)

 

clojure.lang.ExceptionInfo: Call to #'boot.user/f did not conform to spec:

                            val: {:even 4, :odd 5} fails at: [:args :options] 
predicate: (fn [m] (not (contains? m :odd)))

                            :clojure.spec/args  (2 :even 4 :odd 5)

                            :clojure.spec/failure  :instrument-check-failed

 

This is fine: we see it fails the specific predicate provided.

                            

boot.user=> (f 2 :even 4 :o 5)

nil

 

 

Sean Corfield -- (970) FOR-SEAN -- (904) 302-SEAN
An Architect's View -- http://corfield.org/

"If you're not annoying somebody, you're not really alive."
-- Margaret Atwood

 

On 6/29/16, 5:07 PM, "Alex Miller" <clojure@googlegroups.com on behalf of 
a...@puredanger.com> wrote:

 

As soon as you introduce the s/and, you have dropped out of regex land and into 
a predicate. You are then matching something in a new nested regex inside the 
and like:  [[::even 4]]. To stay within the top-level regex and supply extra 
predicates, use s/& instead:

 

(s/def ::options

  (s/& (s/keys* :opt-un [::even]) (fn [m] (not (contains? m :odd)))))

 

user=> (s/conform ::options [:even 2])

{:even 2}

user=> (s/conform ::options [:even 2 :foo 5])

{:even 2, :foo 5}

 

user=> (s/explain ::options [:even 3])

val: () fails spec: :user/options predicate: (& (* (cat :clojure.spec/k 
keyword? :clojure.spec/v :clojure.spec/any)) :clojure.spec/kvs->map (keys 
:opt-un [:user/even])),  Insufficient input

user=> (s/explain ::options [:even 2 :odd 3])

val: {:even 2, :odd 3} fails spec: :user/options predicate: (fn [m] (not 
(contains? m :odd)))

 


On Wednesday, June 29, 2016 at 5:19:09 PM UTC-5, puzzler wrote:

I'm having trouble spec'ing out something like this, a function that takes an 
integer as an input followed by a series of optional keyworded args.  :even is 
an allowed optional keyword, but we definitely want to forbid :odd as an 
optional keyword.

(s/def ::even even?)
(s/def ::options 
  (s/and 
    (s/keys* :opt-un [::even])
    (fn [m] (not (contains? m :odd)))))
    
(defn f [n & {:as options}] nil)
(s/fdef f :args (s/cat :integer int? :options ::options))
(stest/instrument `f)

This doesn't work at all and gives all sorts of errors when f is called with 
any input. I believe it is because the use of s/and in the definition of 
::options interferes with the ability of ::options to be "flattened" into the 
s/cat definition.

My reasoning:

::options correctly validates [:even 2] and rejects [:even 2 :odd 3] and [:even 
3].  

If I omit the s/and and the second clause so that it reads:
(s/def ::options (s/keys* :opt-un [::even]))

this also behaves as expected.


So my conclusion is that the s/and is interfering with the ability of s/keys* 
to sit within the s/cat definition.

How does one solve this problem?

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to