Compare commits

...

6 commits

Author SHA1 Message Date
Jude Payne
bdb0409889 Changelog, Readme & tests 2023-05-05 12:32:34 +01:00
Jude Payne
8f921b4d1a Changelog, Readme & tests 2023-05-05 12:26:07 +01:00
Jude Payne
8fc86b15a0 tidied up naming 2023-05-04 13:41:01 +01:00
Jude Payne
d76f26f5f1 updated README 2023-05-04 09:25:49 +01:00
Jude Payne
7ed071f13b bump to trigger circle 2023-05-04 08:56:36 +01:00
Jude Payne
0acd7a1788 opt-in metadata sketch 2023-05-03 22:38:41 +01:00
6 changed files with 132 additions and 54 deletions

View file

@ -5,6 +5,7 @@
- [#63](https://github.com/babashka/pods/issues/63): create directory before un-tarring - [#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 - [#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 - [#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 ## v0.2.0

View file

@ -376,11 +376,15 @@ nil
#### Metadata #### Metadata
**From pod to pod client**
*Fixed Metadata on vars*
Pods may attach metadata to functions and macros by sending data to the pod client 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 in a `"meta"` field as part of a `"var"` section. The metadata must be an appropriate
map, encoded as an EDN string. This is only applicable to vars in the pod and will be map, encoded as an EDN string. This is only applicable to vars in the pod and will be
ignored if the var refers to Client-side code, since metadata can already be defined ignored if the var refers to Client-side code, since metadata can already be defined
in those code blocks. in those code blocks (see 'Dynamic Metadata' below to enable the encoding of metadata).
For example, a pod can define a function called `add`: For example, a pod can define a function called `add`:
@ -392,6 +396,33 @@ For example, a pod can define a function called `add`:
"meta" "{:doc \"arithmetic addition of 2 arguments\" :arglists ([a b])}"}]}]} "meta" "{:doc \"arithmetic addition of 2 arguments\" :arglists ([a b])}"}]}]}
``` ```
*Dynamic Metadata*
Pods may send metadata on values returned to the client if metadata encoding is enabled
for the particular transport format used by the pod.
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.:
````clojure
(transit/writer baos :json {:transform transit/write-meta})
````
##### From pod client to pod
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.
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-meta?" "true"}]}]}
````
#### Deferred namespace loading #### Deferred namespace loading
When your pod exposes multiple namespaces that can be used independently from When your pod exposes multiple namespaces that can be used independently from

View file

@ -28,6 +28,9 @@
(defn bytes->string [^"[B" bytes] (defn bytes->string [^"[B" bytes]
(String. bytes)) (String. bytes))
(defn bytes->boolean [^"[B" bytes]
(boolean bytes))
(defn get-string [m k] (defn get-string [m k]
(-> (get m k) (-> (get m k)
bytes->string)) bytes->string))
@ -36,6 +39,10 @@
(some-> (get m k) (some-> (get m k)
bytes->string)) bytes->string))
(defn get-maybe-boolean [m k]
(some-> (get m k)
bytes->boolean))
(defn next-id [] (defn next-id []
(str (java.util.UUID/randomUUID))) (str (java.util.UUID/randomUUID)))
@ -83,10 +90,14 @@
(let [wh (transit/write-handler tag-fn val-fn)] (let [wh (transit/write-handler tag-fn val-fn)]
(swap! transit-default-write-handlers assoc *pod-id* wh))) (swap! transit-default-write-handlers assoc *pod-id* wh)))
(defn transit-json-write [pod-id ^String s] (defonce vars-with-metadata (atom {}))
(defn transit-json-write
[pod-id ^String s metadata?]
(with-open [baos (java.io.ByteArrayOutputStream. 4096)] (with-open [baos (java.io.ByteArrayOutputStream. 4096)]
(let [w (transit/writer baos :json {:handlers (get @transit-write-handler-maps pod-id) (let [w (transit/writer baos :json (merge {:handlers (get @transit-write-handler-maps pod-id)
:default-handler (get @transit-default-write-handlers pod-id)})] :default-handler (get @transit-default-write-handlers pod-id)}
(when metadata? {:transform transit/write-meta})))]
(transit/write w s) (transit/write w s)
(str baos)))) (str baos))))
@ -98,7 +109,9 @@
write-fn (case format write-fn (case format
:edn pr-str :edn pr-str
:json cheshire/generate-string :json cheshire/generate-string
:transit+json #(transit-json-write (:pod-id pod) %)) :transit+json #(transit-json-write
(:pod-id pod) %
(contains? (get @vars-with-metadata (:pod-id pod)) pod-var)))
id (next-id) id (next-id)
chan (if handlers handlers chan (if handlers handlers
(promise)) (promise))
@ -128,7 +141,10 @@
edn/read-string) edn/read-string)
name-sym (if vmeta name-sym (if vmeta
(with-meta name-sym vmeta) (with-meta name-sym vmeta)
name-sym)] name-sym)
metadata? (get-maybe-boolean var "read-meta?")]
(when metadata?
(swap! vars-with-metadata update (:pod-id pod) #(conj (set %) sym)))
[name-sym [name-sym
(or code (or code
(fn [& args] (fn [& args]

View file

@ -61,6 +61,12 @@
(transit/write w s) (transit/write w s)
(str baos)))) (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] (defn run-pod [cli-args]
(let [format (cond (contains? cli-args "--json") :json (let [format (cond (contains? cli-args "--json") :json
(contains? cli-args "--transit+json") :transit+json (contains? cli-args "--transit+json") :transit+json
@ -130,6 +136,8 @@
{"name" "read-other-tag" {"name" "read-other-tag"
"code" "(defn read-other-tag [x] [x x])" "code" "(defn read-other-tag [x] [x x])"
"meta" "{:doc \"unread\"}"} "meta" "{:doc \"unread\"}"}
{"name" "round-trip-meta"
"read-meta?" "true"}
{"name" "-local-date-time"} {"name" "-local-date-time"}
{"name" "transit-stuff" {"name" "transit-stuff"
"code" " "code" "
@ -176,65 +184,73 @@
pod.test-pod/add-sync pod.test-pod/add-sync
(try (let [ret (apply + args)] (try (let [ret (apply + args)]
(write out (write out
{"value" (write-fn ret) {"value" (write-fn ret)
"id" id "id" id
"status" ["done"]})) "status" ["done"]}))
(catch Exception e (catch Exception e
(write out (write out
{"ex-data" (write-fn {:args args}) {"ex-data" (write-fn {:args args})
"ex-message" (.getMessage e) "ex-message" (.getMessage e)
"status" ["done" "error"] "status" ["done" "error"]
"id" id}))) "id" id})))
pod.test-pod/range-stream pod.test-pod/range-stream
(let [rng (apply range args)] (let [rng (apply range args)]
(doseq [v rng] (doseq [v rng]
(write out (write out
{"value" (write-fn v) {"value" (write-fn v)
"id" id}) "id" id})
(Thread/sleep 100)) (Thread/sleep 100))
(write out (write out
{"status" ["done"] {"status" ["done"]
"id" id})) "id" id}))
pod.test-pod/assoc pod.test-pod/assoc
(write out (write out
{"value" (write-fn (apply assoc args)) {"value" (write-fn (apply assoc args))
"status" ["done"] "status" ["done"]
"id" id}) "id" id})
pod.test-pod/error pod.test-pod/error
(write out (write out
{"ex-data" (write-fn {:args args}) {"ex-data" (write-fn {:args args})
"ex-message" (str "Illegal arguments") "ex-message" (str "Illegal arguments")
"status" ["done" "error"] "status" ["done" "error"]
"id" id}) "id" id})
pod.test-pod/print pod.test-pod/print
(do (write out (do (write out
{"out" (with-out-str (prn args)) {"out" (with-out-str (prn args))
"id" id}) "id" id})
(write out (write out
{"status" ["done"] {"status" ["done"]
"id" id})) "id" id}))
pod.test-pod/print-err pod.test-pod/print-err
(do (write out (do (write out
{"err" (with-out-str (prn args)) {"err" (with-out-str (prn args))
"id" id}) "id" id})
(write out (write out
{"status" ["done"] {"status" ["done"]
"id" id})) "id" id}))
pod.test-pod/return-nil pod.test-pod/return-nil
(write out (write out
{"status" ["done"] {"status" ["done"]
"id" id "id" id
"value" (write-fn nil)}) "value" (write-fn nil)})
pod.test-pod/reader-tag pod.test-pod/reader-tag
(write out (write out
{"status" ["done"] {"status" ["done"]
"id" id "id" id
"value" "#my/tag[1 2 3]"}) "value" "#my/tag[1 2 3]"})
pod.test-pod/other-tag pod.test-pod/other-tag
(write out (write out
{"status" ["done"] {"status" ["done"]
"id" id "id" id
"value" "#my/other-tag[1]"}) "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 pod.test-pod/-local-date-time
(write out (write out
{"status" ["done"] {"status" ["done"]
@ -255,20 +271,20 @@
(case ns (case ns
pod.test-pod.loaded pod.test-pod.loaded
(write out (write out
{"status" ["done"] {"status" ["done"]
"id" id "id" id
"name" "pod.test-pod.loaded" "name" "pod.test-pod.loaded"
"vars" [{"name" "loaded" "vars" [{"name" "loaded"
"code" "(defn loaded [x] (inc x))"}]}) "code" "(defn loaded [x] (inc x))"}]})
pod.test-pod.loaded2 pod.test-pod.loaded2
(write out (write out
{"status" ["done"] {"status" ["done"]
"id" id "id" id
"name" "pod.test-pod.loaded2" "name" "pod.test-pod.loaded2"
"vars" [{"name" "x" "vars" [{"name" "x"
"code" "(require '[pod.test-pod.loaded :as loaded])"} "code" "(require '[pod.test-pod.loaded :as loaded])"}
{"name" "loaded" {"name" "loaded"
"code" "(defn loaded [x] (loaded/loaded x))"}]})) "code" "(defn loaded [x] (loaded/loaded x))"}]}))
(recur))))))) (recur)))))))
(catch Exception e (catch Exception e
(binding [*out* *err*] (binding [*out* *err*]

View file

@ -84,6 +84,16 @@
(.isArray (class v))) (.isArray (class v)))
true)) 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]) (require '[pod.test-pod.only-code :as only-code])
(def should-be-1 (only-code/foo)) (def should-be-1 (only-code/foo))
@ -116,6 +126,8 @@
fn-called fn-called
local-date-time local-date-time
assoc-string-array assoc-string-array
round-trip-meta
round-trip-meta-nested
should-be-1 should-be-1
add-sync-meta add-sync-meta
error-meta error-meta

View file

@ -34,6 +34,8 @@
3 3
true ;; local-date true ;; local-date
true ;; roundtrip string array true ;; roundtrip string array
true ;; roundtrip metadata
true ;; roundtrip metadata nested
1 1
"add the arguments" "add the arguments"
nil nil