|
952 | 952 | [keys forms preds gfn] |
953 | 953 | (let [id (java.util.UUID/randomUUID) |
954 | 954 | kps (zipmap keys preds) |
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)))))] |
| 955 | + specs (delay (mapv specize preds)) |
| 956 | + cform (case (count preds) |
| 957 | + 2 (fn [x] |
| 958 | + (let [specs @specs |
| 959 | + ret (conform* (specs 0) x)] |
| 960 | + (if (= ::invalid ret) |
| 961 | + (let [ret (conform* (specs 1) x)] |
| 962 | + (if (= ::invalid ret) |
| 963 | + ::invalid |
| 964 | + (tagged-ret (keys 1) ret))) |
| 965 | + (tagged-ret (keys 0) ret)))) |
| 966 | + 3 (fn [x] |
| 967 | + (let [specs @specs |
| 968 | + ret (conform* (specs 0) x)] |
| 969 | + (if (= ::invalid ret) |
| 970 | + (let [ret (conform* (specs 1) x)] |
| 971 | + (if (= ::invalid ret) |
| 972 | + (let [ret (conform* (specs 2) x)] |
| 973 | + (if (= ::invalid ret) |
| 974 | + ::invalid |
| 975 | + (tagged-ret (keys 2) ret))) |
| 976 | + (tagged-ret (keys 1) ret))) |
| 977 | + (tagged-ret (keys 0) ret)))) |
| 978 | + (fn [x] |
| 979 | + (let [specs @specs] |
| 980 | + (loop [i 0] |
| 981 | + (if (< i (count specs)) |
| 982 | + (let [spec (specs i)] |
| 983 | + (let [ret (conform* spec x)] |
| 984 | + (if (= ::invalid ret) |
| 985 | + (recur (inc i)) |
| 986 | + (tagged-ret (keys i) ret)))) |
| 987 | + ::invalid)))))] |
966 | 988 | (reify |
967 | 989 | Spec |
968 | 990 | (conform* [_ x] (cform x)) |
|
1014 | 1036 | (defn ^:skip-wiki and-spec-impl |
1015 | 1037 | "Do not call this directly, use 'and'" |
1016 | 1038 | [forms preds gfn] |
1017 | | - (reify |
1018 | | - Spec |
1019 | | - (conform* [_ x] (and-preds x preds forms)) |
1020 | | - (unform* [_ x] (reduce #(unform %2 %1) x (reverse preds))) |
1021 | | - (explain* [_ path via in x] (explain-pred-list forms preds path via in x)) |
1022 | | - (gen* [_ overrides path rmap] (if gfn (gfn) (gensub (first preds) overrides path rmap (first forms)))) |
1023 | | - (with-gen* [_ gfn] (and-spec-impl forms preds gfn)) |
1024 | | - (describe* [_] `(and ~@forms)))) |
| 1039 | + (let [specs (delay (mapv specize preds)) |
| 1040 | + cform |
| 1041 | + (case (count preds) |
| 1042 | + 2 (fn [x] |
| 1043 | + (let [specs @specs |
| 1044 | + ret (conform* (specs 0) x)] |
| 1045 | + (if (= ::invalid ret) |
| 1046 | + ::invalid |
| 1047 | + (conform* (specs 1) ret)))) |
| 1048 | + 3 (fn [x] |
| 1049 | + (let [specs @specs |
| 1050 | + ret (conform* (specs 0) x)] |
| 1051 | + (if (= ::invalid ret) |
| 1052 | + ::invalid |
| 1053 | + (let [ret (conform* (specs 1) ret)] |
| 1054 | + (if (= ::invalid ret) |
| 1055 | + ::invalid |
| 1056 | + (conform* (specs 2) ret)))))) |
| 1057 | + (fn [x] |
| 1058 | + (let [specs @specs] |
| 1059 | + (loop [ret x i 0] |
| 1060 | + (if (< i (count specs)) |
| 1061 | + (let [nret (conform* (specs i) ret)] |
| 1062 | + (if (= ::invalid nret) |
| 1063 | + ::invalid |
| 1064 | + ;;propagate conformed values |
| 1065 | + (recur nret (inc i)))) |
| 1066 | + ret)))))] |
| 1067 | + (reify |
| 1068 | + Spec |
| 1069 | + (conform* [_ x] (cform x)) |
| 1070 | + (unform* [_ x] (reduce #(unform %2 %1) x (reverse preds))) |
| 1071 | + (explain* [_ path via in x] (explain-pred-list forms preds path via in x)) |
| 1072 | + (gen* [_ overrides path rmap] (if gfn (gfn) (gensub (first preds) overrides path rmap (first forms)))) |
| 1073 | + (with-gen* [_ gfn] (and-spec-impl forms preds gfn)) |
| 1074 | + (describe* [_] `(and ~@forms))))) |
1025 | 1075 |
|
1026 | 1076 | (defn ^:skip-wiki merge-spec-impl |
1027 | 1077 | "Do not call this directly, use 'merge'" |
|
1609 | 1659 | (with-gen (clojure.spec/& (* (cat ::k keyword? ::v any?)) ::kvs->map mspec#) |
1610 | 1660 | (fn [] (gen/fmap (fn [m#] (apply concat m#)) (gen mspec#)))))) |
1611 | 1661 |
|
| 1662 | +(defn nonconforming |
| 1663 | + "takes a spec and returns a spec that has the same properties except |
| 1664 | + 'conform' returns the original (not the conformed) value. Note, will specize regex ops." |
| 1665 | + [spec] |
| 1666 | + (let [spec (specize spec)] |
| 1667 | + (reify |
| 1668 | + Spec |
| 1669 | + (conform* [_ x] (let [ret (conform* spec x)] |
| 1670 | + (if (= ::invalid ret) |
| 1671 | + ::invalid |
| 1672 | + x))) |
| 1673 | + (unform* [_ x] (unform* spec x)) |
| 1674 | + (explain* [_ path via in x] (explain* spec path via in x)) |
| 1675 | + (gen* [_ overrides path rmap] (gen* spec overrides path rmap)) |
| 1676 | + (with-gen* [_ gfn] (nonconforming (with-gen* spec gfn))) |
| 1677 | + (describe* [_] `(nonconforming ~(describe* spec)))))) |
| 1678 | + |
1612 | 1679 | (defmacro nilable |
1613 | | - "returns a spec that accepts nil and values satisfiying pred" |
| 1680 | + "returns a spec that accepts nil and values satisfying pred" |
1614 | 1681 | [pred] |
1615 | | - `(and (or ::nil nil? ::pred ~pred) (conformer second #(if (nil? %) [::nil nil] [::pred %])))) |
| 1682 | + `(nonconforming (or ::nil nil? ::pred ~pred))) |
1616 | 1683 |
|
1617 | 1684 | (defn exercise |
1618 | 1685 | "generates a number (default 10) of values compatible with spec and maps conform over them, |
|
0 commit comments