Skip to content

Instantly share code, notes, and snippets.

@ponzao
Created September 26, 2016 16:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ponzao/6476b7df853402ac744222ab18efe1fa to your computer and use it in GitHub Desktop.
Save ponzao/6476b7df853402ac744222ab18efe1fa to your computer and use it in GitHub Desktop.
Clojure Spec coercion nonsense
(ns vice
(:require [clojure.spec :as s]
[clj-time.core :as t]
[clj-time.format :as tf])
(:import [org.joda.time DateMidnight DateTime]
[java.util UUID]
[clojure.lang Keyword]
[java.math BigInteger]
[java.net URL URI]
[java.util.regex Pattern]))
(def invalid :clojure.spec/invalid)
(defmulti coerce-uuid class)
(defmethod coerce-uuid java.util.UUID [u] u)
(defmethod coerce-uuid java.lang.String [s]
(UUID/fromString s))
(defmethod coerce-uuid :default [& args]
invalid)
(def ->uuid
(s/conformer coerce-uuid))
(defmulti coerce-boolean class)
(defmethod coerce-boolean java.lang.Boolean [b] b)
(defmethod coerce-boolean java.lang.String [s]
(case s
"true" true
"false" false
invalid))
(defmethod coerce-boolean :default [& args]
invalid)
(defmulti coerce-bigint class)
(defmethod coerce-bigint java.math.BigInteger [n] n)
(defmethod coerce-bigint java.lang.String [s]
(try
(bigint s)
(catch NumberFormatException e
invalid)))
(defmethod coerce-bigint :default [& args]
invalid)
(def ->uuid
(s/conformer coerce-uuid))
(def ->boolean
(s/conformer coerce-boolean))
(def ->bigint
(s/conformer coerce-bigint))
(def data
(let [id (str (UUID/randomUUID))]
{:vice/post.id id
:vice/post.title "How to Spec"
:vice/post.published? "true"
:vice/post.price "10000"
:vice/post.content (URI/create (str "http://www.google.com/"))
:vice/post.authors [{:vice/author.id (str (UUID/randomUUID))
:vice/author.name "Vesa Marttila"}]}))
(s/def :vice/author.id ->uuid)
(s/def :vice/author.name string?)
(s/def :vice/author
(s/keys :req [:vice/author.id
:vice/author.name]))
(s/def :vice/post.id ->uuid)
(s/def :vice/post.title string?)
(s/def :vice/post.published? ->boolean)
(s/def :vice/post.price ->bigint)
(defn content-resolver
[entity]
(if (uri? entity)
(.substring (slurp entity) 0 50)
entity))
(def ->resolve
(s/conformer content-resolver))
(def ->upper-case
(s/conformer
(fn [s]
(.toUpperCase s))))
(s/def :vice/post.content
(s/and ->resolve
->upper-case))
(s/def :vice/post.authors (s/coll-of :vice/author))
(s/def :vice/post
(s/keys :req [:vice/post.id
:vice/post.title
:vice/post.published?
:vice/post.price
:vice/post.content
:vice/post.authors]))
(clojure.pprint/pprint
(s/conform :vice/post data))
; =>
; #:vice{:post.id #uuid "364f316b-5452-407f-b0cf-ef377f5bacb4",
; :post.title "How to Spec",
; :post.published? true,
; :post.price 10000N,
; :post.content "<!DOCTYPE HTML><HTML ITEMSCOPE=\"\" ITEMTYPE=\"HTTP:/",
; :post.authors
; [#:vice{:author.id #uuid "6a4daf4a-749b-44e1-860a-a63cb9d69837",
; :author.name "Vesa Marttila"}]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment