From f3a9b9ab1fbe36966df579d47774d8e973607a5f Mon Sep 17 00:00:00 2001 From: Yogthos Date: Fri, 12 Jun 2026 01:22:28 -0400 Subject: [PATCH] host: scoped reader-feature toggle, clojure.template, java.util.Locale alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-ups for running reitit alongside default-feature libraries in one app: - __reader-features / __reader-features-set! exposed to Clojure so a namespace can load a clj-targeted lib (reitit, under :clj) WITHOUT forcing the whole process to :clj — set features, require, restore. Honeysql/selmer/ring stay on the default set they were validated under. (jolt vector args coerced to a janet array — janet map over a pvec iterates keys otherwise.) - clojure.template added to the stdlib (verbatim, pure Clojure over clojure.walk) — honeysql's :clj branch requires it. - java.util.Locale registered as a qualified alias (+ ROOT) for selmer's :clj Locale/US use. --- src/jolt/clojure/template.clj | 33 +++++++++++++++++++++++++++++++ src/jolt/evaluator.janet | 14 +++++++++++++ src/jolt/javatime.janet | 10 ++++++---- test/spec/host-interop-spec.janet | 11 +++++++++++ 4 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 src/jolt/clojure/template.clj diff --git a/src/jolt/clojure/template.clj b/src/jolt/clojure/template.clj new file mode 100644 index 0000000..b3d4510 --- /dev/null +++ b/src/jolt/clojure/template.clj @@ -0,0 +1,33 @@ +;; Verbatim from clojure.template (Stuart Sierra) — pure Clojure over +;; clojure.walk, which jolt ships. Added so honeysql's :clj branch (which +;; requires clojure.template) loads under JOLT_FEATURES including clj. +(ns clojure.template + "Macros that expand to repeated copies of a template expression." + (:require [clojure.walk :as walk])) + +(defn apply-template + "For use in macros. argv is an argument list, as in defn. expr is + a quoted expression using the symbols in argv. values is a sequence + of values to be used for the arguments. + + apply-template will recursively replace argument symbols in expr + with their corresponding values, returning a modified expr. + + Example: (apply-template '[x] '(+ x x) '[2]) + ;=> (+ 2 2)" + [argv expr values] + (assert (vector? argv)) + (assert (every? symbol? argv)) + (walk/postwalk-replace (zipmap argv values) expr)) + +(defmacro do-template + "Repeatedly copies expr (in a do block) for each group of arguments + in values. values are automatically partitioned by the number of + arguments in argv, an argument vector as in defn. + + Example: (macroexpand '(do-template [x y] (+ y x) 2 4 3 5)) + ;=> (do (+ 4 2) (+ 5 3))" + [argv expr & values] + (let [c (count argv)] + `(do ~@(map (fn [a] (apply-template argv expr a)) + (partition c values))))) diff --git a/src/jolt/evaluator.janet b/src/jolt/evaluator.janet index 8d7817c..3e70f85 100644 --- a/src/jolt/evaluator.janet +++ b/src/jolt/evaluator.janet @@ -1311,6 +1311,20 @@ # Java class jolt doesn't ship (e.g. reitit.Trie). __register-class-statics! # makes (Class/method ...) resolve; __register-class-methods! makes (.method # tagged-value ...) dispatch; __register-class-ctor! makes (Class. ...) build. + # Reader-conditional feature toggle, exposed to Clojure so a namespace can + # load a clj-targeted library (e.g. reitit, under :clj) WITHOUT forcing the + # whole process to :clj — set features, require the lib, restore. Returns the + # previous feature set (a list of name strings) for restoration. + (ns-intern core "__reader-features" + (fn [] (tuple ;(map (fn [k] (string k)) (keys reader-features))))) + (ns-intern core "__reader-features-set!" + (fn [names] + # names arrives as a jolt vector (pvec) or list — coerce to a janet array + (def arr (cond (pvec? names) (pv->array names) + (or (tuple? names) (array? names)) names + @[names])) + (reader-features-set! (map (fn [n] (if (keyword? n) n (string n))) arr)) + nil)) (ns-intern core "__register-class-statics!" (fn [nm tbl] (register-class-statics! nm tbl) nil)) (ns-intern core "__register-class-methods!" diff --git a/src/jolt/javatime.janet b/src/jolt/javatime.janet index 2848036..20f652f 100644 --- a/src/jolt/javatime.janet +++ b/src/jolt/javatime.janet @@ -129,10 +129,12 @@ (register-class-statics! "LocalDateTime" @{"ofInstant" (fn [inst zone] (local-dt (ms-of inst))) "now" (fn [] (local-dt (math/floor (* 1000 (os/clock :realtime)))))}) - (register-class-statics! "Locale" - @{"getDefault" (fn [] @{:jolt/type :jolt/locale :id "default"}) - "ENGLISH" @{:jolt/type :jolt/locale :id "en"} - "US" @{:jolt/type :jolt/locale :id "en-US"}}) + (let [locale-statics @{"getDefault" (fn [] @{:jolt/type :jolt/locale :id "default"}) + "ENGLISH" @{:jolt/type :jolt/locale :id "en"} + "US" @{:jolt/type :jolt/locale :id "en-US"} + "ROOT" @{:jolt/type :jolt/locale :id "root"}}] + (each nm ["Locale" "java.util.Locale"] + (register-class-statics! nm locale-statics))) (register-tagged-methods! :jolt/instant @{"atZone" (fn [self zone] (zoned (self :ms) zone)) "toEpochMilli" (fn [self] (self :ms))}) diff --git a/test/spec/host-interop-spec.janet b/test/spec/host-interop-spec.janet index 8f4bb1b..a0386c8 100644 --- a/test/spec/host-interop-spec.janet +++ b/test/spec/host-interop-spec.janet @@ -212,3 +212,14 @@ "(let [m (HashMap. {:a 1 :b 2})] (.get m :b))"] ["HashMap put + size" "2" "(let [m (HashMap. {})] (.put m :x 1) (.put m :y 2) (.size m))"]) + +# Reader-feature toggle exposed to Clojure (scoped clj-lib loading): a +# namespace can load a clj-targeted library under :clj without forcing the +# whole process — set features, require, restore. +(defspec "host-interop / reader-feature toggle" + ["features default to jolt+default" "true" + "(contains? (set (__reader-features)) \"jolt\")"] + ["set + read back" "true" + "(do (def prev (__reader-features)) (__reader-features-set! [\"clj\" \"jolt\" \"default\"]) (def r (contains? (set (__reader-features)) \"clj\")) (__reader-features-set! prev) r)"] + ["restore returns to default" "false" + "(do (def prev (__reader-features)) (__reader-features-set! [\"clj\"]) (__reader-features-set! prev) (contains? (set (__reader-features)) \"clj\"))"])