4

I'm relatively new to clojure and I'm looking for a way to use the value of one required key in the validation of another. I can do it by creating another map with the two values and passing that, but I was hoping there was a simpler way. Thanks

(s/def ::country string?)
(s/def ::postal-code   
  ;sudo-code
  ;(if (= ::country "Canda")
  ;(re-matches #"^[A-Z0-9]{5}$") 
  ;(re-matches #"^[0-9]{5}$"))
)

(s/def ::address
  (s/keys :req-un [
    ::country
    ::postal-code
    ::street
    ::state
  ]))

1 Answer 1

3

Here's a way to do it with multi-spec:

(defmulti country :country)
(defmethod country "Canada" [_]
  (s/spec #(re-matches #"^[A-Z0-9]{5}$" (:postal-code %))))
(defmethod country :default [_]
  (s/spec #(re-matches #"^[0-9]{5}$" (:postal-code %))))

(s/def ::country string?)
(s/def ::postal-code string?)
(s/def ::address
  (s/merge
    (s/keys :req-un [::country ::postal-code])
    (s/multi-spec country :country)))

(s/explain ::address {:country "USA" :postal-code "A2345"})
;; val: {:country "USA", :postal-code "A2345"} fails spec: :sandbox.so/address at: ["USA"] predicate: (re-matches #"^[0-9]{5}$" (:postal-code %))
(s/explain ::address {:country "Canada" :postal-code "A2345"})
;; Success!

Another option is and-ing another predicate on your keys spec:

(s/def ::address
  (s/and
    (s/keys :req-un [::country ::postal-code])
    #(case (:country %)
       "Canada" (re-matches #"^[A-Z0-9]{5}$" (:postal-code %))
       (re-matches #"^[0-9]{5}$" (:postal-code %)))))

You might prefer the multi-spec approach because it's open for extension i.e. you can define more defmethods for country later as opposed to keeping all the logic in the and predicate.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.