Skip to content

Instantly share code, notes, and snippets.

@mathesz
Created May 15, 2022 19:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mathesz/28c378ec3045f74adf94ebb1396ca74e to your computer and use it in GitHub Desktop.
Save mathesz/28c378ec3045f74adf94ebb1396ca74e to your computer and use it in GitHub Desktop.
babashka compatible metosin/spec-tools
;; $ bb -f bb_spec_tools_examples.clj
(deps/add-deps {:deps '{org.babashka/spec.alpha {:git/url "https://github.com/babashka/spec.alpha"
:git/sha "1a841c4cc1d4f6dab7505a98ed2d532dd9d56b78"}}})
(deps/add-deps {:deps '{babashka/spec-tools {:git/url "https://github.com/mathesz/spec-tools"
:git/sha "81b3cd8f448a303146b57c2e4dbaf3dbbd509ec6"}
expound/expound {:mvn/version "0.9.0"}}})
(require '[clojure.spec.alpha :as s])
(require '[spec-tools.core :as st])
(require '[expound.alpha :as exp])
(def adult? (s/and int? #(>= % 18)))
(println (st/coerce adult? "20" st/string-transformer))
(require '[spec-tools.json-schema :as json-schema])
(s/def ::id string?)
(s/def ::name string?)
(s/def ::street string?)
(s/def ::city #{:tre :hki})
(s/def ::address (s/keys :req-un [::street ::city]))
(s/def ::user (s/keys :req-un [::id ::name ::address]))
(println (json-schema/transform ::user))
(require '[spec-tools.data-spec :as ds])
(s/def ::age pos-int?)
;; a data-spec
(def person
{::id uuid?
::age ::age
:boss boolean?
(ds/req :name) string?
(ds/opt :description) string?
:languages #{keyword?}
:aliases [(ds/or {:maps {:alias string?}
:strings string?})]
:orders [{:id int?
:description string?}]
:address (ds/maybe
{:street string?
:zip string?})})
(def person-spec
(ds/spec ::person person))
(def person-data {::age 63
:boss true
:name "Liisa"
:languages #{:clj :cljs}
:aliases [{:alias "Lissu"} "Liisu"]
:orders [{:id 1, :description "cola"}
{:id 2, :description "kebab"}]
:description "Liisa is a valid boss"
:address {:street "Amurinkatu 2"
:zip "33210"}})
(s/valid? person-spec person-data)
;; false
(exp/expound person-spec person-data)
;; let's remove ::id from the spec
(def new-person-spec (ds/spec ::person (dissoc person ::id)))
(s/valid? new-person-spec person-data)
;; true
(exp/expound new-person-spec person-data)
;; Success!
(st/decode
new-person-spec
{::age "63"
:boss "true"
:name "Liisa"
:languages ["clj" "cljs"]
:aliases [{:alias "Lissu"} "Liisu"]
:orders [{:id "1", :description "cola"}
{:id "2", :description "kebab"}]
:description "Liisa is a valid boss"
:address nil}
st/string-transformer)
;20
;{:type object, :properties {id {:type string}, name {:type string}, address {:type object, :properties {street {:type string}, city {:enum [:tre :hki]}}, :required [street city], :title user/address}}, :required [id name address], :title user/user}
;-- Spec failed --------------------
;
;{:user/age 63,
; :boss true,
; :name "Liisa",
; :languages #{:clj :cljs},
; :aliases [{:alias "Lissu"} "Liisu"],
; :orders [{:id 1, :description "cola"} {:id 2, :description "kebab"}],
; :description "Liisa is a valid boss",
; :address {:street "Amurinkatu 2", :zip "33210"}}
;
;should contain key: :user/id
;
;| key | spec |
;|==========+======================================|
;| :user/id | (spec-tools.core/spec |
; | | {:spec uuid?, |
; | | :type :uuid, |
; | | :leaf? true, |
; | | :spec-tools.core/synthetic? true}) |
;
;-------------------------
;Detected 1 error
;Success!
;{:user/age 63, :boss true, :name "Liisa", :languages #{:clj :cljs}, :aliases [{:alias "Lissu"} "Liisu"], :orders [{:id 1, :description "cola"} {:id 2, :description "kebab"}], :description "Liisa is a valid boss", :address nil}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment