From e1a6d77b0ccdf1f36d8d73b39fe1c54c5e1926e3 Mon Sep 17 00:00:00 2001 From: Yogthos Date: Thu, 11 Jun 2026 22:56:12 -0400 Subject: [PATCH] core: defprotocol accepts docstring + keyword options (honeysql) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clojure's defprotocol takes an optional docstring and leading keyword options (:extend-via-metadata true) before the signatures; jolt's macro fed the option keyword to (first sig). honeysql declares its InlineValue protocol exactly that way — with the fix, all four honeysql namespaces load unmodified from git and the formatter produces correct sqlvecs for selects/inserts/updates/deletes/joins/:inline. Listed in libraries.md. --- docs/libraries.md | 2 ++ jolt-core/clojure/core/30-macros.clj | 10 +++++++++- test/spec/protocols-spec.janet | 8 ++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/libraries.md b/docs/libraries.md index c3d8c82..57446da 100644 --- a/docs/libraries.md +++ b/docs/libraries.md @@ -12,5 +12,7 @@ Libraries confirmed to load and pass their conformance checks on Jolt on the [ring-app example](https://github.com/jolt-lang/examples/tree/main/ring-app)'s spork/http adapter * [ring-codec](https://github.com/ring-clojure/ring-codec) +* [honeysql](https://github.com/seancorfield/honeysql) — full formatter + helpers + (select/insert/update/delete/joins/:inline), loaded unmodified from git * [clojure.jdbc](https://github.com/yogthos/clojure.jdbc) — as [jolt-lang/db](https://github.com/jolt-lang/db)'s `jdbc.core`, reimplemented over janet sqlite3/pq drivers (SQLite + PostgreSQL) diff --git a/jolt-core/clojure/core/30-macros.clj b/jolt-core/clojure/core/30-macros.clj index 84de98c..db7e113 100644 --- a/jolt-core/clojure/core/30-macros.clj +++ b/jolt-core/clojure/core/30-macros.clj @@ -295,7 +295,15 @@ ;; instead of evaluating its fields. methods is a {kw {:name str}} map (only :name ;; is consulted). Each method is a thin dispatch fn over protocol-dispatch. (defmacro defprotocol [pname & sigs] - (let [methods (reduce (fn [m sig] + ;; Clojure's defprotocol takes an optional docstring and leading keyword + ;; options (:extend-via-metadata true, honeysql uses it) before the method + ;; signatures — drop them (metadata extension is a JVM dispatch detail). + (let [sigs (loop [s sigs] + (cond + (string? (first s)) (recur (rest s)) + (keyword? (first s)) (recur (rest (rest s))) + :else s)) + methods (reduce (fn [m sig] (assoc m (keyword (name (first sig))) {:name (name (first sig))})) {} sigs)] `(do diff --git a/test/spec/protocols-spec.janet b/test/spec/protocols-spec.janet index 548a2eb..b6606cf 100644 --- a/test/spec/protocols-spec.janet +++ b/test/spec/protocols-spec.janet @@ -48,3 +48,11 @@ "(do (deftype P [n]) (.-n (P. 5)))"] ["dot ctor + method" "5" "(do (defprotocol G (val-of [_])) (deftype P [n] G (val-of [_] n)) (val-of (P. 5)))"]) + +# defprotocol accepts Clojure's optional docstring + leading keyword options +# before the signatures (honeysql: :extend-via-metadata true). +(defspec "protocols / defprotocol options" + ["docstring + option + method" ":hi" + "(do (defprotocol Pdoc \"docs\" :extend-via-metadata true (greet [x])) (extend-protocol Pdoc String (greet [s] :hi)) (greet \"x\"))"] + ["option only" "3" + "(do (defprotocol Popt :extend-via-metadata true (plus2 [x])) (extend-protocol Popt Long (plus2 [n] (+ n 2))) (plus2 1))"])