What I need: a spec for a function, that has two arguments:
(your answer doesn't have to cover all of this, mainly I need a way to tell that if it is a keyword it must exist in hash-map)
Here is what I have:
(this is an example to show that it is possible to access both arguments inside :args, I know that it doesn't test anything and always fails because nil is returned)
(ns my-example.core
(:require
[clojure.spec.alpha :as spec]))
(defn my-example [m v] nil)
(spec/fdef my-example
:args (fn [[m v]] nil))
This fn kind of works (it is possible to create a function that would work how I want), But it isn't very descriptive and when it fails (given that there is (stest/instrument `my-example))
it just shows me body of function (like this: (fn [[m v]] nil)
).
Is this the only way to solve my problem or there is a better way?
I also tryed to define a spec and use it inside :args :
(spec/def :my-example/my-check (fn [[m v]] nil))
(spec/fdef my-example
:args :my-example/my-check)
But result is same.
In the spec for :args
, you can specify any predicate you want. See the example provided at the spec guide for fdef. Given that example, here is a code fragment that mostly works for your case. I say "mostly" because the spec for the first map argument could be made stricter to note that it is a map of keywords to strings. The forms inside the comment
form show some usage examples.
(ns example
(:require [clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest]))
(defn my-example [m v] nil)
(s/fdef my-example
:args (s/and (s/cat :m map? :v vector?)
#(every? (fn [x] (or (string? x)
(and (keyword? x)
(contains? (:m %) x))))
(:v %)))
:ret nil?)
(comment
(stest/instrument `my-example)
(my-example {:a "a" :b "b"} ["foo" :a "bar" :b]) ; => nil
(my-example {:a "a" :b "b"} ["foo" :a "bar" :c]) ; => spec exception
(my-example {:a "a" :b "b"} ["foo" :a "bar" 2]) ; => spec exception
)