|
44 | 44 |
|
45 | 45 | (defonce ^:private registry-ref (atom {})) |
46 | 46 |
|
47 | | -(defn- named? [x] (instance? clojure.lang.Named x)) |
48 | | - |
49 | | -(defn- with-name [spec name] |
50 | | - (with-meta spec (assoc (meta spec) ::name name))) |
51 | | - |
52 | | -(defn- spec-name [spec] |
53 | | - (cond |
54 | | - (keyword? spec) spec |
55 | | - |
56 | | - (instance? clojure.lang.IObj spec) |
57 | | - (-> (meta spec) ::name))) |
| 47 | +(defn- deep-resolve [reg k] |
| 48 | + (loop [spec k] |
| 49 | + (if (ident? spec) |
| 50 | + (recur (get reg spec)) |
| 51 | + spec))) |
58 | 52 |
|
59 | 53 | (defn- reg-resolve |
60 | | - "returns the spec/regex at end of alias chain starting with k, nil if not found, k if k not Named" |
| 54 | + "returns the spec/regex at end of alias chain starting with k, nil if not found, k if k not ident" |
61 | 55 | [k] |
62 | | - (if (named? k) |
63 | | - (let [reg @registry-ref] |
64 | | - (loop [spec k] |
65 | | - (if (named? spec) |
66 | | - (recur (get reg spec)) |
67 | | - (when spec |
68 | | - (with-name spec k))))) |
| 56 | + (if (ident? k) |
| 57 | + (let [reg @registry-ref |
| 58 | + spec (get reg k)] |
| 59 | + (if-not (ident? spec) |
| 60 | + spec |
| 61 | + (deep-resolve reg spec))) |
69 | 62 | k)) |
70 | 63 |
|
71 | 64 | (defn- reg-resolve! |
|
86 | 79 | [x] |
87 | 80 | (c/and (::op x) x)) |
88 | 81 |
|
| 82 | +(defn- with-name [spec name] |
| 83 | + (cond |
| 84 | + (ident? spec) spec |
| 85 | + (regex? spec) (assoc spec ::name name) |
| 86 | + |
| 87 | + (instance? clojure.lang.IObj spec) |
| 88 | + (with-meta spec (assoc (meta spec) ::name name)))) |
| 89 | + |
| 90 | +(defn- spec-name [spec] |
| 91 | + (cond |
| 92 | + (ident? spec) spec |
| 93 | + |
| 94 | + (regex? spec) (::name spec) |
| 95 | + |
| 96 | + (instance? clojure.lang.IObj spec) |
| 97 | + (-> (meta spec) ::name))) |
| 98 | + |
89 | 99 | (declare spec-impl) |
90 | 100 | (declare regex-spec-impl) |
91 | 101 |
|
92 | 102 | (defn- maybe-spec |
93 | 103 | "spec-or-k must be a spec, regex or resolvable kw/sym, else returns nil." |
94 | 104 | [spec-or-k] |
95 | | - (let [s (c/or (spec? spec-or-k) |
| 105 | + (let [s (c/or (c/and (ident? spec-or-k) (reg-resolve spec-or-k)) |
| 106 | + (spec? spec-or-k) |
96 | 107 | (regex? spec-or-k) |
97 | | - (c/and (named? spec-or-k) (reg-resolve spec-or-k)) |
98 | 108 | nil)] |
99 | 109 | (if (regex? s) |
100 | 110 | (with-name (regex-spec-impl s nil) (spec-name s)) |
|
104 | 114 | "spec-or-k must be a spec, regex or kw/sym, else returns nil. Throws if unresolvable kw/sym" |
105 | 115 | [spec-or-k] |
106 | 116 | (c/or (maybe-spec spec-or-k) |
107 | | - (when (named? spec-or-k) |
| 117 | + (when (ident? spec-or-k) |
108 | 118 | (throw (Exception. (str "Unable to resolve spec: " spec-or-k)))))) |
109 | 119 |
|
| 120 | +(defprotocol Specize |
| 121 | + (specize* [_])) |
| 122 | + |
| 123 | +(extend-protocol Specize |
| 124 | + clojure.lang.Keyword |
| 125 | + (specize* [k] (specize* (reg-resolve! k))) |
| 126 | + |
| 127 | + clojure.lang.Symbol |
| 128 | + (specize* [s] (specize* (reg-resolve! s))) |
| 129 | + |
| 130 | + clojure.spec.Spec |
| 131 | + (specize* [s] s) |
| 132 | + |
| 133 | + Object |
| 134 | + (specize* [o] (spec-impl ::unknown o nil nil))) |
| 135 | + |
110 | 136 | (defn- specize [s] |
111 | | - (c/or (the-spec s) (spec-impl ::unknown s nil nil))) |
| 137 | + (specize* s)) |
112 | 138 |
|
113 | 139 | (defn conform |
114 | 140 | "Given a spec and a value, returns :clojure.spec/invalid if value does not match spec, |
|
279 | 305 | (defn ^:skip-wiki def-impl |
280 | 306 | "Do not call this directly, use 'def'" |
281 | 307 | [k form spec] |
282 | | - (c/assert (c/and (named? k) (namespace k)) "k must be namespaced keyword or resolvable symbol") |
| 308 | + (c/assert (c/and (ident? k) (namespace k)) "k must be namespaced keyword or resolvable symbol") |
283 | 309 | (let [spec (if (c/or (spec? spec) (regex? spec) (get @registry-ref spec)) |
284 | 310 | spec |
285 | 311 | (spec-impl form spec nil nil))] |
286 | | - (swap! registry-ref assoc k spec) |
| 312 | + (swap! registry-ref assoc k (with-name spec k)) |
287 | 313 | k)) |
288 | 314 |
|
289 | 315 | (defn- ns-qualify |
|
795 | 821 | (cond |
796 | 822 | (spec? pred) (cond-> pred gfn (with-gen gfn)) |
797 | 823 | (regex? pred) (regex-spec-impl pred gfn) |
798 | | - (named? pred) (cond-> (the-spec pred) gfn (with-gen gfn)) |
| 824 | + (ident? pred) (cond-> (the-spec pred) gfn (with-gen gfn)) |
799 | 825 | :else |
800 | 826 | (reify |
801 | 827 | Spec |
802 | | - (conform* [_ x] (dt pred x form cpred?)) |
| 828 | + (conform* [_ x] (if cpred? |
| 829 | + (pred x) |
| 830 | + (if (pred x) x ::invalid))) |
803 | 831 | (unform* [_ x] (if cpred? |
804 | 832 | (if unc |
805 | 833 | (unc x) |
|
924 | 952 | [keys forms preds gfn] |
925 | 953 | (let [id (java.util.UUID/randomUUID) |
926 | 954 | kps (zipmap keys preds) |
927 | | - cform (fn [x] |
928 | | - (loop [i 0] |
929 | | - (if (< i (count preds)) |
930 | | - (let [pred (preds i)] |
931 | | - (let [ret (dt pred x (nth forms i))] |
932 | | - (if (= ::invalid ret) |
933 | | - (recur (inc i)) |
934 | | - (tagged-ret (keys i) ret)))) |
935 | | - ::invalid)))] |
| 955 | + cform (let [specs (delay (mapv specize preds))] |
| 956 | + (fn [x] |
| 957 | + (let [specs @specs] |
| 958 | + (loop [i 0] |
| 959 | + (if (< i (count specs)) |
| 960 | + (let [spec (specs i)] |
| 961 | + (let [ret (conform* spec x)] |
| 962 | + (if (= ::invalid ret) |
| 963 | + (recur (inc i)) |
| 964 | + (tagged-ret (keys i) ret)))) |
| 965 | + ::invalid)))))] |
936 | 966 | (reify |
937 | 967 | Spec |
938 | 968 | (conform* [_ x] (cform x)) |
|
0 commit comments