Skip to content

Instantly share code, notes, and snippets.

@bhb
Last active September 21, 2018 19:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bhb/7fde08abc1f3f5d06b05481b4e200614 to your computer and use it in GitHub Desktop.
Save bhb/7fde08abc1f3f5d06b05481b4e200614 to your computer and use it in GitHub Desktop.
A naive implementation of opt-in coercion.
;; Code is largely copied from
;; https://github.com/wilkerlucio/spec-coerce/blob/master/src/spec_coerce/core.cljc
;; 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)
k)
(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)
x))
(defn coerce-structure
"Recursively coerce map values on a structure."
[x]
(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))
x))
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]))
(comment
(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