-
Notifications
You must be signed in to change notification settings - Fork 6
/
core.cljc
97 lines (86 loc) · 2.89 KB
/
core.cljc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
(ns defn-spec.core
(:require
[clojure.spec.alpha :as s]
#?(:clj [clojure.spec.test.alpha :as st]
:cljs [cljs.spec.test.alpha :as st])))
#?(:clj
(defn qualify-symbol
[sym-name]
(symbol (str *ns*) (str sym-name))))
#?(:clj
(defn platform
[env]
(if (:ns env) :cljs :clj)))
;; From https://github.com/borkdude/speculative/blob/master/src/speculative/impl.cljc
#?(:clj (defmacro ?
[& {:keys [cljs clj]}]
(if (contains? &env '&env)
`(if (:ns ~'&env) ~cljs ~clj)
(if #?(:clj (:ns &env) :cljs true)
cljs
clj))))
#?(:clj
(def *orchestra?
(delay
(try
(require 'orchestra.spec.test)
true
(catch Exception _ false)))))
#?(:clj
(defmacro instrument*
[symbol]
(let [instrument-sym (case [@*orchestra? (platform &env)]
[true :clj]
'orchestra.spec.test/instrument
[true :cljs]
'orchestra-cljs.spec.test/instrument
[false :clj]
'clojure.spec.test.alpha/instrument
[false :cljs]
'cljs.spec.test.alpha/instrument)]
`(~instrument-sym ~symbol))))
#?(:clj
(defmacro fdef
"Exact same parameters as `s/fdef`. Automatically enables instrumentation
for `fn-sym` when `s/*compile-asserts*` is true."
[fn-sym & specs]
`(let [r# (s/fdef ~fn-sym ~@specs)]
~@(when s/*compile-asserts*
[`(instrument* '~(qualify-symbol fn-sym))])
r#)))
(s/def ::defn-args
(s/cat :name simple-symbol?
:docstring (s/? string?)
:meta (s/? map?)
:bs (s/* any?)))
#?(:clj
(defn- defn-spec-form
[args]
(let [{:keys [name meta]} (s/conform ::defn-args args)
args-spec (::args meta)
ret-spec (::ret meta)
fn-spec (::fn meta)
fdef-sym (if (false? (::instrument? meta)) `s/fdef `fdef)]
`(do
(defn ~@args)
(~fdef-sym ~name
~@(when-let [s args-spec] [:args s])
~@(when-let [s ret-spec] [:ret s])
~@(when-let [s fn-spec] [:fn s]))))))
#?(:clj
(defmacro defn-spec
"Exact same parameters as `defn`. You may optionally include `::s/args`
and/or `::s/ret` in your function's attr-map to have the args and/or return
value of your function checked with `s/assert`.
Setting `s/*compile-asserts*` to `false` will result in a regular function
definition."
{:arglists '([name doc-string? attr-map? [params*] prepost-map? body]
[name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?])}
[& args]
(if s/*compile-asserts*
(defn-spec-form args)
`(defn ~@args))))
#?(:clj
(s/fdef defn-spec
:args ::defn-args
:ret any?))