Skip to content

Instantly share code, notes, and snippets.



Last active Sep 21, 2018
What would you like to do?
A naive implementation of opt-in coercion.
;; Code is largely copied from
;; with minor modifications!
(ns example.coercion
(:require [clojure.walk :as walk]
[clojure.spec.alpha :as s]))
(defonce ^:private registry-ref (atom {}))
;; WARNING - only works if all unqualified kw are unique!!!!
(defn ^:skip-wiki def-impl [k coerce-fn]
(assert (and (ident? k) (namespace k)) "k must be namespaced keyword")
(swap! registry-ref assoc k coerce-fn)
(swap! registry-ref assoc (keyword (name k)) coerce-fn)
(defmacro def
"Given a namespace-qualified keyword, and a coerce function, makes an entry in the
registry mapping k to the coerce function."
[k coercion]
`(def-impl '~k ~coercion))
(defn coerce [k x]
(if-let [coerce-fn (get @registry-ref k)]
(coerce-fn x)
(defn coerce-structure
"Recursively coerce map values on a structure."
(walk/prewalk (fn [x]
(if (map? x)
(with-meta (into {} (map (fn [[k v]]
(let [coercion (get {} k k)]
[k (coerce coercion v)]))) x)
(meta x))
(example.coercion/def ::kw keyword)
(s/def ::kw keyword?)
(s/def ::nested (s/keys :req-un [::kw]))
(s/def ::data (s/keys ::req-un [::nested]))
(coerce-structure {:nested {:kw "x"}}) ;; => {:nested {:kw :x}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment