Protocol/interop fixes to run metosin/malli (jolt-ltwk) (#105)
* Protocol/interop fixes to run metosin/malli Bringing up malli (schema validation) surfaced a batch of protocol and host-interop gaps. m/validate now works across the schema vocabulary (predicates, :map incl. nested/optional, :vector, :tuple, :enum, :maybe, :and, bounded int/string). - extend-type and reify now accept MULTIPLE protocols in one form (each bare symbol switches the current protocol). reify records every protocol it implements, so instance?/satisfies? recognise all of them. - Protocol method params support destructuring: reify/extend-type/deftype/ defrecord emit (fn ...) (which desugars patterns) instead of raw fn*. - instance? of a PROTOCOL works like satisfies? for reify/record instances, matching short names across qualified/bare protocol references. - @x reads as the qualified clojure.core/deref, so it still derefs where a ns excludes and rebinds deref (malli does). Updated reader-test + the reader spec/grammar (S11, deref rule). - Java collection interop on jolt collections: .nth/.count/.valAt/.get/.seq/ .containsKey route to the clojure.core equivalent (1-arg and 0-arg paths). - java.util.HashMap capacity/load-factor constructors + .putAll. - A class used as a value resolves to its instances' type, so Pattern -> the regex type (malli keys class-schemas by it). - Shims for malli's load path: LazilyPersistentVector/createOwning and PersistentArrayMap/createWithCheck statics. m/explain not yet working (jolt-fjb1). Full gate green. * satisfies? recognizes reify, consistent with instance? A reify's protocol methods are instance-local, so they aren't in the global type registry that type-satisfies? consults — satisfies? returned false for a reify even when it implemented the protocol. Check the protocols the reify records on itself (the same :jolt/protocols list instance? uses), matching short names like instance? does. Covers single- and multi-protocol reify. --------- Co-authored-by: Yogthos <yogthos@gmail.com>
This commit is contained in:
parent
d1f73f1740
commit
910c4b6c99
9 changed files with 149 additions and 33 deletions
|
|
@ -376,14 +376,24 @@
|
|||
(register-method (name atype) pname (name k) f)))
|
||||
(recur (nnext s)))))
|
||||
|
||||
(defmacro extend-type [tsym psym & impls]
|
||||
(defmacro extend-type [tsym & body]
|
||||
;; register-method is a fn (clojure.core); pass type/protocol/method NAMES as
|
||||
;; strings (not the symbols) so the call compiles as a plain invoke. A nil
|
||||
;; type extends on nil values (the host tag is the string "nil").
|
||||
`(do ~@(map (fn [spec]
|
||||
`(register-method ~(if (nil? tsym) "nil" (name tsym)) ~(name psym) ~(name (first spec))
|
||||
(fn* ~(nth spec 1) ~@(drop 2 spec))))
|
||||
impls)))
|
||||
;; `body` is one or more protocols, each followed by its method specs:
|
||||
;; (extend-type T P1 (m1 [_] ..) P2 (m2 [_] ..)) — a bare symbol switches the
|
||||
;; current protocol (like reify), so multiple protocols extend in one form.
|
||||
(let [tname (if (nil? tsym) "nil" (name tsym))]
|
||||
(loop [items (seq body) proto nil forms []]
|
||||
(if (empty? items)
|
||||
`(do ~@forms)
|
||||
(let [x (first items)]
|
||||
(if (symbol? x)
|
||||
(recur (rest items) (name x) forms)
|
||||
(recur (rest items) proto
|
||||
(conj forms
|
||||
`(register-method ~tname ~proto ~(name (first x))
|
||||
(fn ~(nth x 1) ~@(drop 2 x)))))))))))
|
||||
|
||||
(defmacro extend-protocol [psym & type-impls]
|
||||
`(do ~@(map (fn [g] `(extend-type ~(first g) ~psym ~@(rest g)))
|
||||
|
|
@ -400,15 +410,18 @@
|
|||
;; ordinary map literal that evaluates to {keyword fn}, and the protocol NAME is
|
||||
;; passed as a string (not the symbol) so the call compiles as a plain invoke.
|
||||
(defmacro reify [& forms]
|
||||
(loop [items (seq forms) proto nil methods {}]
|
||||
;; a reify can implement SEVERAL protocols; collect them all (each bare symbol
|
||||
;; switches the current protocol, like extend-type) and pass every protocol name
|
||||
;; to make-reified so (instance? Proto r)/satisfies? recognise all of them.
|
||||
(loop [items (seq forms) protos [] methods {}]
|
||||
(if (empty? items)
|
||||
`(make-reified ~(name proto) ~methods)
|
||||
`(make-reified ~methods ~@(vec (map name protos)))
|
||||
(let [x (first items)]
|
||||
(if (symbol? x)
|
||||
(recur (rest items) (if proto proto x) methods)
|
||||
(recur (rest items) proto
|
||||
(recur (rest items) (conj protos x) methods)
|
||||
(recur (rest items) protos
|
||||
(assoc methods (keyword (name (first x)))
|
||||
`(fn* ~(nth x 1) ~@(drop 2 x)))))))))
|
||||
`(fn ~(nth x 1) ~@(drop 2 x)))))))))
|
||||
|
||||
(defmacro defrecord [name-sym fields & body]
|
||||
(let [tn (name name-sym)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue