Fork me on GitHub
David Pham04:05:24

How do You eval? I actually want the default generator because I override it, but for testing i would also like to test the generic one.

Alex Miller (Clojure team)13:05:49

with the eval function?

Alex Miller (Clojure team)13:05:09

(s/gen (eval (s/form ::a)))


Hello, I want to introduce clojure spec to validate API endpoints. The parsed response naturally does not have namespaced keywords. How do I go about validating the data? Should I simply use unqualified keys? Where should I keep my spec?


I know it is a very common question of where to put spec but can't find the right answer

Alex Miller (Clojure team)19:05:50

I answered these in #beginners - in the future, it's best to put questions in just one channel

👍 4
David Pham19:05:05

Is it not a bad thing to use the eval function?

Alex Miller (Clojure team)20:05:13

it's not inherently bad, it's just a tool

Alex Miller (Clojure team)20:05:20

Clojure evals all of your expressions after all


I have a simple function and an associated fdef specification, but am not getting an error when calling the function with incorrect arguments. The function should take a map that is a ::customer specification. Have I misunderstood something?

(defn customer-fullname
  "Return customer full name from customer details"
  (str (::first-name customer-details)
       (::last-name customer-details)))

(spec/fdef customer-fullname
  :args (spec/cat :customer ::customer)
  :ret string?
  :fn #(= (:ret %)
          (str (::first-name :args) " " (::last-name :args))))

(spec/def ::first-name string?)
(spec/def ::last-name string?)
(spec/def ::email-address
  (spec/and string?
            #(re-matches #"^[a-zA-Z0-9._%+-][email protected][a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$" %)))

(spec/def ::customer
    :req [::first-name ::last-name ::email-address]))
I would have expected a call to the customer-fullname to fail when the wrong kind of arguments are passed
(customer-fullname "customer")


The ::customer spec works with spec/valid? and spec/assert when I use them with :pre and :post conditions in a function definition, but seem to be missing something when using spec/fdef.


Ah, I have now learned about instrumenting the fdef specifications, and now it works, well fails when I expect it too...

(spec-test/instrument `customer-fullname)


I am not clear on if it is valuable to use fdef without instrumenting them. Some discussions suggest is it but I have not really understood why as yet. I am still not that clear on the :fn aspect of fdef so will be on the look out for more examples. I still have a lot to understand about spec.

Alex Miller (Clojure team)21:05:55

you can see the specs in (doc customer-fullname)


@jr0cket You can also spec-test/check them, separate from instrumentation.

👍 4
Alex Miller (Clojure team)21:05:35

those are the main benefits


In particular, instrumentation checks :args passed in are correct (and ignores :ret and :fn). Check is generative and passes in conforming random arguments (per the :args spec) and then checks :ret and :fn are satisfied.


I can see the specs in the docs, yes that is very useful (had forgotten that in my frustration to get the code to fail). Will try out spec-test/check in the morning, sound promising. Thank you both.