I find myself writing a lot of specs like this:
(s/def ::name string?) (s/def ::logUri string?) (s/def ::subnet (s/and string? #(> (count %) 5))) (s/def ::instanceType string?) ... (s/def ::key (s/and string? #(> (count %) 5))) (s/def ::instanceCount string?) (s/def ::bidPct string?) I.e. Lots of s/and and s/def. This seems like a waste. So I decided to write a macro that did this for me. Something like:
(defmacro and-spec [validations] (doseq [[keyname & funcs] validations] `(s/def ~keyname (s/and ~@funcs)))) So I would be able to do something like:
(and-spec [[::name1 [string?]] [::name2 [string? #(> (count %) 5)]]]) And this would just do all my s/def stuff for me. Unfortunately, the above macro doesn't work, but I'm not sure why.
(s/valid? ::name1 "asdf") Execution error at emr-cli.utils/eval6038 (form-init17784784591561795514.clj:1). Unable to resolve spec: :emr-cli.utils/name1 Smaller versions of this work:
(defmacro small-and-spec-works [key-name validations] `(s/def ~key-name (s/and ~@validations))) => #'emr-cli.utils/tsmall (and-spec-small-works ::mykey [string?]) => :emr-cli.utils/mykey (s/valid? ::mykey "asdf") => true But the second I introduce a let binding things start getting weird:
(defmacro small-and-spec [validation] (let [[key-name & valids] validation] `(s/def ~key-name (s/and ~@valids)))) => #'emr-cli.utils/small-and-spec (small-and-spec [::mykey2 [string?]]) => :emr-cli.utils/mykey2 (s/valid? ::mykey2 "asdf") Execution error (IllegalArgumentException) at emr-cli.utils/eval6012 (form-init17784784591561795514.clj:1). Key must be integer - How can I make the
doseqmacro work? - What is going wrong with the
small-and-specthat creates theKey must be integererror?