diff --git a/CHANGELOG.md b/CHANGELOG.md index bffa21d..88a9616 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [#63](https://github.com/babashka/pods/issues/63): create directory before un-tarring - [#59](https://github.com/babashka/pods/issues/59): delete port file on exit - [#65](https://github.com/babashka/pods/issues/65): fix warnings when defining var with core name in JVM +- [#66](https://github.com/babashka/pods/issues/66): Allow metadata on fn arguments for transit+json ## v0.2.0 diff --git a/README.md b/README.md index 30f6f14..00072c6 100644 --- a/README.md +++ b/README.md @@ -376,9 +376,9 @@ nil #### Metadata -##### From pod to pod client +**From pod to pod client** -1. Fixed Metadata on vars +*Fixed Metadata on vars* Pods may attach metadata to functions and macros by sending data to the pod client in a `"meta"` field as part of a `"var"` section. The metadata must be an appropriate @@ -396,14 +396,14 @@ For example, a pod can define a function called `add`: "meta" "{:doc \"arithmetic addition of 2 arguments\" :arglists ([a b])}"}]}]} ``` -2. Dynamic Metadata +*Dynamic Metadata* Pods may send metadata on values returned to the client if metadata encoding is enabled -for the particular transport used by the pod. +for the particular transport format used by the pod. -For example, if your pod uses `transit+json` as its format, you can enable metadata +For example, if your pod uses `:transit+json` as its format, you can enable metadata encoding by adding `:transform transit/write-meta` (or whatever transit is aliased to) -to the optional map passed to `transit\writer`. e.g.: +to the optional map passed to `transit/writer`. e.g.: ````clojure (transit/writer baos :json {:transform transit/write-meta}) @@ -411,15 +411,16 @@ to the optional map passed to `transit\writer`. e.g.: ##### From pod client to pod -Currently sending metadata on arguments passed to a function is available only for the -`transit+json` format and must be explicitly enabled on a per var basis. +Currently sending metadata on arguments passed to a pod function is available only for the +`transit+json` format and can be enabled on a per var basis. -For example a pod can enable metadata to be read on arguments for the `round-trip` function: +A pod can enable metadata to be read on arguments by sending the "read-meta?" field to "true" +for the var representing that function. For example: ````clojure {:format :transit+json :namespaces [{:name "pod.babashka.demo" - :vars [{"name" "round-trip" "read-metadata?" "true"}]}]} + :vars [{"name" "round-trip" "read-meta?" "true"}]}]} ```` #### Deferred namespace loading diff --git a/src/babashka/pods/impl.clj b/src/babashka/pods/impl.clj index fe7aa21..0addfb3 100644 --- a/src/babashka/pods/impl.clj +++ b/src/babashka/pods/impl.clj @@ -93,13 +93,13 @@ (defonce vars-with-metadata (atom {})) (defn transit-json-write - ([pod-id ^String s metadata?] - (with-open [baos (java.io.ByteArrayOutputStream. 4096)] - (let [w (transit/writer baos :json (merge {:handlers (get @transit-write-handler-maps pod-id) - :default-handler (get @transit-default-write-handlers pod-id)} - (when metadata? {:transform transit/write-meta})))] - (transit/write w s) - (str baos))))) + [pod-id ^String s metadata?] + (with-open [baos (java.io.ByteArrayOutputStream. 4096)] + (let [w (transit/writer baos :json (merge {:handlers (get @transit-write-handler-maps pod-id) + :default-handler (get @transit-default-write-handlers pod-id)} + (when metadata? {:transform transit/write-meta})))] + (transit/write w s) + (str baos)))) (defn invoke [pod pod-var args opts] (let [handlers (:handlers opts) @@ -111,7 +111,7 @@ :json cheshire/generate-string :transit+json #(transit-json-write (:pod-id pod) % - (some #{pod-var} (get @vars-with-metadata (:pod-id pod))))) + (contains? (get @vars-with-metadata (:pod-id pod)) pod-var))) id (next-id) chan (if handlers handlers (promise)) @@ -142,9 +142,9 @@ name-sym (if vmeta (with-meta name-sym vmeta) name-sym) - metadata? (get-maybe-boolean var "read-metadata?")] + metadata? (get-maybe-boolean var "read-meta?")] (when metadata? - (swap! vars-with-metadata update (:pod-id pod) conj sym)) + (swap! vars-with-metadata update (:pod-id pod) #(conj (set %) sym))) [name-sym (or code (fn [& args] diff --git a/test-pod/pod/test_pod.clj b/test-pod/pod/test_pod.clj index 3fb5b5c..8bd5555 100644 --- a/test-pod/pod/test_pod.clj +++ b/test-pod/pod/test_pod.clj @@ -61,6 +61,12 @@ (transit/write w s) (str baos)))) +(defn transit-json-write-meta [s] + (with-open [baos (java.io.ByteArrayOutputStream. 4096)] + (let [w (transit/writer baos :json {:transform transit/write-meta})] + (transit/write w s) + (str baos)))) + (defn run-pod [cli-args] (let [format (cond (contains? cli-args "--json") :json (contains? cli-args "--transit+json") :transit+json @@ -130,6 +136,8 @@ {"name" "read-other-tag" "code" "(defn read-other-tag [x] [x x])" "meta" "{:doc \"unread\"}"} + {"name" "round-trip-meta" + "read-meta?" "true"} {"name" "-local-date-time"} {"name" "transit-stuff" "code" " @@ -171,70 +179,79 @@ read-string) args (get message "args") args (read-string args) + args1 args args (read-fn args)] (case var pod.test-pod/add-sync (try (let [ret (apply + args)] (write out - {"value" (write-fn ret) - "id" id - "status" ["done"]})) + {"value" (write-fn ret) + "id" id + "status" ["done"]})) (catch Exception e (write out - {"ex-data" (write-fn {:args args}) - "ex-message" (.getMessage e) - "status" ["done" "error"] - "id" id}))) + {"ex-data" (write-fn {:args args}) + "ex-message" (.getMessage e) + "status" ["done" "error"] + "id" id}))) pod.test-pod/range-stream (let [rng (apply range args)] (doseq [v rng] (write out - {"value" (write-fn v) - "id" id}) + {"value" (write-fn v) + "id" id}) (Thread/sleep 100)) (write out - {"status" ["done"] - "id" id})) + {"status" ["done"] + "id" id})) pod.test-pod/assoc (write out - {"value" (write-fn (apply assoc args)) - "status" ["done"] - "id" id}) + {"value" (write-fn (apply assoc args)) + "status" ["done"] + "id" id}) pod.test-pod/error (write out - {"ex-data" (write-fn {:args args}) - "ex-message" (str "Illegal arguments") - "status" ["done" "error"] - "id" id}) + {"ex-data" (write-fn {:args args}) + "ex-message" (str "Illegal arguments") + "status" ["done" "error"] + "id" id}) pod.test-pod/print (do (write out - {"out" (with-out-str (prn args)) - "id" id}) + {"out" (with-out-str (prn args)) + "id" id}) (write out - {"status" ["done"] - "id" id})) + {"status" ["done"] + "id" id})) pod.test-pod/print-err (do (write out - {"err" (with-out-str (prn args)) - "id" id}) + {"err" (with-out-str (prn args)) + "id" id}) (write out - {"status" ["done"] - "id" id})) + {"status" ["done"] + "id" id})) pod.test-pod/return-nil (write out - {"status" ["done"] - "id" id - "value" (write-fn nil)}) + {"status" ["done"] + "id" id + "value" (write-fn nil)}) pod.test-pod/reader-tag (write out - {"status" ["done"] - "id" id - "value" "#my/tag[1 2 3]"}) + {"status" ["done"] + "id" id + "value" "#my/tag[1 2 3]"}) pod.test-pod/other-tag (write out - {"status" ["done"] - "id" id - "value" "#my/other-tag[1]"}) + {"status" ["done"] + "id" id + "value" "#my/other-tag[1]"}) + pod.test-pod/round-trip-meta + (write out + {"status" ["done"] + "id" id + "value" + (case format + :transit+json (transit-json-write-meta (first args)) + (write-fn (first args)))}) pod.test-pod/-local-date-time (write out {"status" ["done"] @@ -255,20 +272,20 @@ (case ns pod.test-pod.loaded (write out - {"status" ["done"] - "id" id - "name" "pod.test-pod.loaded" - "vars" [{"name" "loaded" - "code" "(defn loaded [x] (inc x))"}]}) + {"status" ["done"] + "id" id + "name" "pod.test-pod.loaded" + "vars" [{"name" "loaded" + "code" "(defn loaded [x] (inc x))"}]}) pod.test-pod.loaded2 (write out - {"status" ["done"] - "id" id - "name" "pod.test-pod.loaded2" - "vars" [{"name" "x" - "code" "(require '[pod.test-pod.loaded :as loaded])"} - {"name" "loaded" - "code" "(defn loaded [x] (loaded/loaded x))"}]})) + {"status" ["done"] + "id" id + "name" "pod.test-pod.loaded2" + "vars" [{"name" "x" + "code" "(require '[pod.test-pod.loaded :as loaded])"} + {"name" "loaded" + "code" "(defn loaded [x] (loaded/loaded x))"}]})) (recur))))))) (catch Exception e (binding [*out* *err*] diff --git a/test-resources/test_program.clj b/test-resources/test_program.clj index 476b062..245ac98 100644 --- a/test-resources/test_program.clj +++ b/test-resources/test_program.clj @@ -84,6 +84,16 @@ (.isArray (class v))) true)) +(def round-trip-meta + (if (= "transit+json" fmt) + (= {:my-meta 2} (meta (pod.test-pod/round-trip-meta (with-meta [2] {:my-meta 2})))) + true)) + +(def round-trip-meta-nested + (if (= "transit+json" fmt) + (= {:my-meta 3} (meta (first (pod.test-pod/round-trip-meta [(with-meta [3] {:my-meta 3})])))) + true)) + (require '[pod.test-pod.only-code :as only-code]) (def should-be-1 (only-code/foo)) @@ -116,6 +126,8 @@ fn-called local-date-time assoc-string-array + round-trip-meta + round-trip-meta-nested should-be-1 add-sync-meta error-meta diff --git a/test/babashka/pods/test_common.clj b/test/babashka/pods/test_common.clj index 3a793b4..a71da9f 100644 --- a/test/babashka/pods/test_common.clj +++ b/test/babashka/pods/test_common.clj @@ -34,6 +34,8 @@ 3 true ;; local-date true ;; roundtrip string array + true ;; roundtrip metadata + true ;; roundtrip metadata nested 1 "add the arguments" nil