I'm struggling with Clojure(script) spec. I slightly found out what part causes problem but I can't solve it.
(defn filter-ids
[[items fields] _]
(let [ids
(for [item items
field-tags (vals fields)
:let [item-tags (-> item second :tags)
item-id (first item)]
:when (and
(seq field-tags)
(empty? (set/difference field-tags item-tags)))]
item-id)]
(into #{} ids)))
Above code is what I tried to define spec. (fdef)
And I defined spec.
(spec/def :common/id (spec/and
keyword?
#(-> %1 name js/parseInt nat-int?)))
(spec/def :common/label string?)
(spec/def :common/tags (spec/coll-of string? :kind set?))
(spec/def :common/item (spec/keys :req-un [:common/label :common/tags]))
(spec/fdef filter-ids
:args (spec/cat
:useful (spec/cat
:items (spec/map-of :common/id :common/item)
:fields (spec/map-of :common/id :common/tags))
:useless any?)
:ret (spec/coll-of :common/id :kind set?))
And when I run it with instrument, error occurs.
(stest/instrument `filter-ids)
(filter-ids [{:0 {:label "task0" :tags #{"one" "two"}}}
{:0 #{"three"}, :1 #{"one"}}]
nil)
; Execution error - invalid arguments to taggy.states.subs/filter-ids at (<cljs repl>:1).
[{:0 {:label "task0", :tags #{"two" "one"}}} {:0 #{"three"}, :1 #{"one"}}] - failed: map? at: [:useful :items]
It seems like spec think first argument needs to be map, which is what I'm not intended to.
When I do like below, it doesn't complaining about map?. (although still a error because it's not valid at all)
(filter-ids {{:0 {:label "task0" :tags #{"one" "two"}}} 1
{:0 #{"three"}, :1 #{"one"}} 2}
nil)
I'm a newbie and really need some help to move on.
Thanks.
spec/catis a "sequence regex" and it "unrolls" if you nest it inside anotherspec/cat.You can either wrap the inner
spec/catcall in aspec/speccall, which prevents that unrolling, or you can switch tospec/tuple(and remove the:itemsand:fieldslabels):Both of those will work. Which you choose may depend on what information you want in your error messages (I think the former provides more context when you get something wrong because of the
:itemsand:fieldslabels).