Skip to content

Instantly share code, notes, and snippets.

@thosmos
Forked from borkdude/specfn.clj
Created September 5, 2018 06:46
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 thosmos/a48f001ffa940ec4db591c3d3346aba0 to your computer and use it in GitHub Desktop.
Save thosmos/a48f001ffa940ec4db591c3d3346aba0 to your computer and use it in GitHub Desktop.
Use a spec for defining function arguments and get validation automatically
(ns specfn.core
(:require [clojure.spec :as s]
[clojure.spec.test :as t]))
(defn- spec-symbols [s]
(->> s
(drop 1)
(partition-all 2)
(map first)
(map name)
(mapv symbol)))
(defmacro defn* [name spec & body]
(let [params (spec-symbols spec)
spec-key (keyword (str *ns*) (str name "__args"))]
`(do
(s/def ~spec-key ~spec)
(defn ~name ~params
(if (s/valid? ~spec-key ~params)
~@body
(throw (ex-info
(s/explain-str ~spec-key ~params)
(s/explain-data ~spec-key ~params))))))))
(comment
(defn* my-fn (s/cat :n number? :s string?)
(str n s))
(my-fn 10 "bar") ;; => "10bar"
(my-fn 10 10)) ;; => clojure.lang.ExceptionInfo: In: [1] val: 10 fails spec: :specfn.core/my-fn__args at: [:s] predicate: string?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment