|
36 | 36 |
|
37 | 37 | (defprotocol Spec
|
38 | 38 | (conform* [spec x])
|
| 39 | + (unform* [spec y]) |
39 | 40 | (explain* [spec path via in x])
|
40 | 41 | (gen* [spec overrides path rmap])
|
41 | 42 | (with-gen* [spec gfn])
|
|
107 | 108 | [spec x]
|
108 | 109 | (conform* (specize spec) x))
|
109 | 110 |
|
| 111 | +(defn unform |
| 112 | + "Given a spec and a value created by or compliant with a call to |
| 113 | + 'conform' with the same spec, returns a value with all conform |
| 114 | + destructuring undone." |
| 115 | + [spec x] |
| 116 | + (unform* (specize spec) x)) |
| 117 | + |
110 | 118 | (defn form
|
111 | 119 | "returns the spec as data"
|
112 | 120 | [spec]
|
|
405 | 413 | (recur ret ks))
|
406 | 414 | ret)))
|
407 | 415 | ::invalid))
|
| 416 | + (unform* [_ m] |
| 417 | + (let [reg (registry)] |
| 418 | + (loop [ret m, [k & ks :as keys] (c/keys m)] |
| 419 | + (if keys |
| 420 | + (if (contains? reg (keys->specs k)) |
| 421 | + (let [cv (get m k) |
| 422 | + v (unform (keys->specs k) cv)] |
| 423 | + (recur (if (identical? cv v) ret (assoc ret k v)) |
| 424 | + ks)) |
| 425 | + (recur ret ks)) |
| 426 | + ret)))) |
408 | 427 | (explain* [_ path via in x]
|
409 | 428 | (if-not (map? x)
|
410 | 429 | {path {:pred 'map? :val x :via via :in in}}
|
|
452 | 471 |
|
453 | 472 | (defn ^:skip-wiki spec-impl
|
454 | 473 | "Do not call this directly, use 'spec'"
|
455 |
| - [form pred gfn cpred?] |
456 |
| - (cond |
457 |
| - (spec? pred) (cond-> pred gfn (with-gen gfn)) |
458 |
| - (regex? pred) (regex-spec-impl pred gfn) |
459 |
| - (named? pred) (cond-> (the-spec pred) gfn (with-gen gfn)) |
460 |
| - :else |
461 |
| - (reify |
462 |
| - IFn |
463 |
| - (-invoke [this x] (valid? this x)) |
464 |
| - Spec |
465 |
| - (conform* [_ x] (dt pred x form cpred?)) |
466 |
| - (explain* [_ path via in x] |
467 |
| - (when (= ::invalid (dt pred x form cpred?)) |
468 |
| - {path {:pred (abbrev form) :val x :via via :in in}})) |
469 |
| - (gen* [_ _ _ _] (if gfn |
470 |
| - (gfn) |
471 |
| - (gen/gen-for-pred pred))) |
472 |
| - (with-gen* [_ gfn] (spec-impl form pred gfn cpred?)) |
473 |
| - (describe* [_] form)))) |
| 474 | + ([form pred gfn cpred?] (spec-impl form pred gfn cpred? nil)) |
| 475 | + ([form pred gfn cpred? unc] |
| 476 | + (cond |
| 477 | + (spec? pred) (cond-> pred gfn (with-gen gfn)) |
| 478 | + (regex? pred) (regex-spec-impl pred gfn) |
| 479 | + (named? pred) (cond-> (the-spec pred) gfn (with-gen gfn)) |
| 480 | + :else |
| 481 | + (reify |
| 482 | + IFn |
| 483 | + (-invoke [this x] (valid? this x)) |
| 484 | + Spec |
| 485 | + (conform* [_ x] (dt pred x form cpred?)) |
| 486 | + (unform* [_ x] (if cpred? |
| 487 | + (if unc |
| 488 | + (unc x) |
| 489 | + (throw (js/Error. "no unform fn for conformer"))) |
| 490 | + x)) |
| 491 | + (explain* [_ path via in x] |
| 492 | + (when (= ::invalid (dt pred x form cpred?)) |
| 493 | + {path {:pred (abbrev form) :val x :via via :in in}})) |
| 494 | + (gen* [_ _ _ _] (if gfn |
| 495 | + (gfn) |
| 496 | + (gen/gen-for-pred pred))) |
| 497 | + (with-gen* [_ gfn] (spec-impl form pred gfn cpred?)) |
| 498 | + (describe* [_] form))))) |
474 | 499 |
|
475 | 500 | (defn ^:skip-wiki multi-spec-impl
|
476 | 501 | "Do not call this directly, use 'multi-spec'"
|
|
492 | 517 | (conform* [_ x] (if-let [pred (predx x)]
|
493 | 518 | (dt pred x form)
|
494 | 519 | ::invalid))
|
| 520 | + (unform* [_ x] (if-let [pred (predx x)] |
| 521 | + (unform pred x) |
| 522 | + (throw (js/Error. (str "No method of: " form " for dispatch value: " (dval x)))))) |
495 | 523 | (explain* [_ path via in x]
|
496 | 524 | (let [dv (dval x)
|
497 | 525 | path (conj path dv)]
|
|
539 | 567 | ::invalid
|
540 | 568 | (recur (if (identical? cv v) ret (assoc ret i cv))
|
541 | 569 | (inc i))))))))
|
| 570 | + (unform* [_ x] |
| 571 | + (assert (c/and (vector? x) |
| 572 | + (= (count x) (count preds)))) |
| 573 | + (loop [ret x, i 0] |
| 574 | + (if (= i (count x)) |
| 575 | + ret |
| 576 | + (let [cv (x i) |
| 577 | + v (unform (preds i) cv)] |
| 578 | + (recur (if (identical? cv v) ret (assoc ret i v)) |
| 579 | + (inc i)))))) |
542 | 580 | (explain* [_ path via in x]
|
543 | 581 | (cond
|
544 | 582 | (not (vector? x))
|
|
570 | 608 | "Do not call this directly, use 'or'"
|
571 | 609 | [keys forms preds gfn]
|
572 | 610 | (let [id (random-uuid)
|
| 611 | + kps (zipmap keys preds) |
573 | 612 | cform (fn [x]
|
574 | 613 | (loop [i 0]
|
575 | 614 | (if (< i (count preds))
|
|
584 | 623 | (-invoke [this x] (valid? this x))
|
585 | 624 | Spec
|
586 | 625 | (conform* [_ x] (cform x))
|
| 626 | + (unform* [_ [k x]] (unform (kps k) x)) |
587 | 627 | (explain* [this path via in x]
|
588 | 628 | (when-not (valid? this x)
|
589 | 629 | (apply merge
|
|
636 | 676 | (-invoke [this x] (valid? this x))
|
637 | 677 | Spec
|
638 | 678 | (conform* [_ x] (and-preds x preds forms))
|
| 679 | + (unform* [_ x] (reduce #(unform %2 %1) x (reverse preds))) |
639 | 680 | (explain* [_ path via in x] (explain-pred-list forms preds path via in x))
|
640 | 681 | (gen* [_ overrides path rmap] (if gfn (gfn) (gensub (first preds) overrides path rmap (first forms))))
|
641 | 682 | (with-gen* [_ gfn] (and-spec-impl forms preds gfn))
|
|
720 | 761 |
|
721 | 762 | (defn ^:skip-wiki maybe-impl
|
722 | 763 | "Do not call this directly, use '?'"
|
723 |
| - [p form] (alt* [p (accept ::nil)] nil [form ::nil])) |
| 764 | + [p form] (assoc (alt* [p (accept ::nil)] nil [form ::nil]) :maybe form)) |
724 | 765 |
|
725 | 766 | (defn- noret? [p1 pret]
|
726 | 767 | (c/or (= pret ::nil)
|
|
762 | 803 | r (if (nil? p0) ::nil (preturn p0))]
|
763 | 804 | (if k0 [k0 r] r)))))
|
764 | 805 |
|
| 806 | +(defn- op-unform [p x] |
| 807 | + ;;(prn {:p p :x x}) |
| 808 | + (let [{[p0 & pr :as ps] :ps, [k :as ks] :ks, :keys [::op p1 ret forms rep+ maybe] :as p} (reg-resolve p) |
| 809 | + kps (zipmap ks ps)] |
| 810 | + (case op |
| 811 | + ::accept [ret] |
| 812 | + nil [(unform p x)] |
| 813 | + ::amp (let [px (reduce #(unform %2 %1) x (reverse ps))] |
| 814 | + (op-unform p1 px)) |
| 815 | + ::rep (mapcat #(op-unform p1 %) x) |
| 816 | + ::pcat (if rep+ |
| 817 | + (mapcat #(op-unform p0 %) x) |
| 818 | + (mapcat (fn [k] |
| 819 | + (when (contains? x k) |
| 820 | + (op-unform (kps k) (get x k)))) |
| 821 | + ks)) |
| 822 | + ::alt (if maybe |
| 823 | + [(unform p0 x)] |
| 824 | + (let [[k v] x] |
| 825 | + (op-unform (kps k) v)))))) |
| 826 | + |
765 | 827 | (defn- add-ret [p r k]
|
766 | 828 | (let [{:keys [::op ps splice] :as p} (reg-resolve p)
|
767 | 829 | prop #(let [ret (preturn p)]
|
|
792 | 854 | (when (accept-nil? p1) (deriv (rep* p2 p2 (add-ret p1 ret nil) splice forms) x)))))))
|
793 | 855 |
|
794 | 856 | (defn- op-describe [p]
|
795 |
| - (let [{:keys [::op ps ks forms splice p1 rep+] :as p} (reg-resolve p)] |
| 857 | + (let [{:keys [::op ps ks forms splice p1 rep+ maybe] :as p} (reg-resolve p)] |
796 | 858 | ;;(prn {:op op :ks ks :forms forms :p p})
|
797 | 859 | (when p
|
798 | 860 | (case op
|
|
802 | 864 | ::pcat (if rep+
|
803 | 865 | (list `+ rep+)
|
804 | 866 | (cons `cat (mapcat vector (c/or (seq ks) (repeat :_)) (c/or (seq forms) (repeat nil)))))
|
805 |
| - ::alt (cons `alt (mapcat vector ks forms)) |
| 867 | + ::alt (if maybe |
| 868 | + (list `? maybe) |
| 869 | + (cons `alt (mapcat vector ks forms))) |
806 | 870 | ::rep (list (if splice `+ `*) forms)))))
|
807 | 871 |
|
808 | 872 | (defn- op-explain [form p path via in input]
|
|
943 | 1007 | (if (c/or (nil? x) (coll? x))
|
944 | 1008 | (re-conform re (seq x))
|
945 | 1009 | ::invalid))
|
| 1010 | + (unform* [_ x] (op-unform re x)) |
946 | 1011 | (explain* [_ path via in x]
|
947 | 1012 | (if (c/or (nil? x) (coll? x))
|
948 | 1013 | (re-explain path via in re (seq x))
|
|
989 | 1054 | (conform* [_ f] (if (fn? f)
|
990 | 1055 | (if (identical? f (validate-fn f specs *fspec-iterations*)) f ::invalid)
|
991 | 1056 | ::invalid))
|
| 1057 | + (unform* [_ f] f) |
992 | 1058 | (explain* [_ path via in f]
|
993 | 1059 | (if (fn? f)
|
994 | 1060 | (let [args (validate-fn f specs 100)]
|
|
1018 | 1084 |
|
1019 | 1085 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; non-primitives ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
1020 | 1086 | (cljs.spec/def ::any (cljs.spec/spec (constantly true) :gen gen/any))
|
1021 |
| -(cljs.spec/def ::kvs->map (cljs.spec/conformer #(zipmap (map ::k %) (map ::v %)))) |
| 1087 | +(cljs.spec/def ::kvs->map (cljs.spec/conformer #(zipmap (map ::k %) (map ::v %)) #(map (fn [[k v]] {::k k ::v v}) %))) |
1022 | 1088 |
|
1023 | 1089 | (defn exercise
|
1024 | 1090 | "generates a number (default 10) of values compatible with spec and maps conform over them,
|
|
0 commit comments