Fork me on GitHub
#clojure
<
2023-05-08
>
p-himik11:05:48

What would be the most appropriate way to write a spec for a map that: • Must have a key :x with a long • May have a key :y with a string • Has 0 or more other keys that are all vectors and point to vectors Examples: {:x 1, :y "y", [1 2] [3]}, {:x 2, [] [:x]}.

p-himik12:05:58

The best I could come up with:

(s/def ::x integer?)
(s/def ::y string?)
(s/def ::spec (s/and (s/keys :req-un [::x] :opt-un [::y])
                     (s/coll-of (fn [[k v]]
                                  (or (keyword? k)
                                      (and (vector? k) (vector? v))))
                                :kind map?)

Ben Sless12:05:17

That seems right

Ben Sless12:05:35

Isn't there a map-of spec?

Ben Sless12:05:52

you can clean up the second part by using a conformer

Ben Sless12:05:00

which will dissoc x and y

p-himik12:05:35

> Isn't there a map-of spec? Yeah, but it won't enforce "vector and vector" pairs since it doesn't correspond a particular value to a particular key. And it will ruin conforming because I'll have to use s/or - forgot to mention but I also want for the input to remain a proper map after conforming. > you can clean up the second part by using a conformer What do you mean? Can you give a brief example?

Ben Sless12:05:14

(s/and (s/keys ,,,) (s/conformer #(dissoc % :x :y)) (s/map-of vector? vector?))

p-himik12:05:00

Ah, it'll remove the keyword keys when I want to not only validate but also conform the value. :)

p-himik12:05:07

But didn't know about s/conformer, thanks!

Ben Sless13:05:37

you can carry them as meta 🙃

p-himik13:05:28

I'll stick to my simple struggles with an extra or. :D

Ben Sless14:05:38

I think malli has recently added support for extra keys

Ben Sless14:05:47

as in a map schema

p-himik14:05:25

Yeah, I have my eyes on Malli (dealing with spec, even with spec-tools, hasn't been all that great) so will definitely check it out once I've got enough time.

escherize16:05:01

In malli, I think it’s something like

(require '[malli.core :as m])
(require '[malli.generator :as mg])
(mg/generate
  [:map
   [:x :int]
   [:y :string]
   [::m/default
    [:map-of
     [:sequential :int]
     [:sequential :int]]]])

👍 4
timo13:05:41

Anyone ever used RabbitMQ streams in Clojure? I am struggling with advanced interop https://github.com/rabbitmq/rabbitmq-stream-java-client.

thomas13:05:30

maybe that helps

timo13:05:44

it doesn't have the stream part in it

chrisbetz13:05:08

@U4GEXTNGZ Any specific issues, I did Java interop here and there, so maybe I can help you out with stuff?)

chrisbetz13:05:13

You might also want to look into https://fundingcircle.github.io/jackdaw/, solving a similar problem based on Kafka - not having worked with it, it’s hard to assess. The general idea is the same, so there might be some clever abstractions atop replicated append-only logs no matter what tech stack you’re building upon. And from those abstractions, work your way towards the rabbit-mq stream java client.

chrisbetz13:05:48

If you got a github repo wrapping the java client and meaningful tests not compiling / failing, feel free to share it.

timo13:05:49

thanks @U068WTML7, will come back if I need more help

👍 1
kennytilton21:05:43

Do we have any definitive official doc on the combo of CLJC and macros? Looking for the latest supported solutions, btw, cuz it has been evolving in good directions. I was under the impression that it had gotten as simple as, in a .CLJC file:

(ns tiltontec.cell.base
  #?(:cljs (:require-macros [tiltontec.cell.base]))
  ...etc...)

(defn my-fn ...)

(defmacro my-macro ...)
...and then we could in another .CLJC just:
(ns tiltontec.cell.integrity
  (:require
    [tiltontec.cell.base
     :refer [my-fn my-macro]]))
Is that the case? Or is that wishful thinking? :rolling_on_the_floor_laughing:

escherize21:05:09

There’s a trap for macros that return different things in clj and cljs. The reader macro for :clj during a cljs build will be true, because cljs macros are built in clojure. This library’s readme has more info + fixes: https://github.com/cgrand/macrovich

👀 4
kennytilton21:05:36

Hmm, I have a lot of code like:

(#?(:clj ref :cljs atom) 42)
Are you saying that evaluates to (ref 42) in CLJS?

seancorfield21:05:09

@U0PUGPSFR Do you mean inside a macro?

seancorfield21:05:28

I removed the uses of macrovich from all my cljc libraries at some point -- I didn't think it was still an issue at this point?

kennytilton22:05:50

No, @U04V70XH6 this would be inside a function, defined in a .cljc. Kinda vanilla usage, macrovich looks interesting, @U051GFP2V, thx, but right now I am just trying to see if there is a definitive Clojure/CLJC answer. I am getting diff results in figwheel vs shadow and I thought step one should be to find out the official standard.

2
phill09:05:04

I would be interested in the answer, if you find one!

kennytilton10:05:41

@thheller got me sorted out, @phill. No need for a separate CLJ. This is fine in a CLJC:

(ns tiltontec.cell.base
  #?(:cljs (:require-macros [tiltontec.cell.base
                             :refer [un-stopped without-c-dependency]]))
n.b. the explicit :refer. That was the bit I was missing. Now we can ditch the refer-macros in a client:
(ns tiltontec.cell.integrity
  (:require
    [tiltontec.cell.base
     :refer [un-stopped ....]]))
More good stuff: https://code.thheller.com/blog/shadow-cljs/2019/10/12/clojurescript-macros.html

p-himik11:05:38

> Now we can ditch the refer-macros in a client It is the case with separate CLJ+CLJS files as well, even without :refer. At least, with shadow-cljs.

kennytilton11:05:07

Yep. I did not mean to exclude that. Thx for the clarification. 🙏 To any lurkers, the back story is that Matrix is a CLJC state management library intended for use either from CLJS or a pure CLJ app, so CLJ+CLJS would not have worked in my particular use case.

p-himik11:05:25

It's still fine to use CLJ+CLJS in a cross-platform project though. It's just that all cross-platform parts will have to be repeated in those files or moved to a separate CLJC file. When writing cross-platform code, I usually use CLJ files for a JVM implementation and CLJS for a JS implementation in cases when reader conditionals start wrapping whole functions instead of tiny parts of them.

lread14:05:19

@U0PUGPSFR I found the https://clojurescript.org/guides/ns-forms#_macros pretty good. I was at one point very confused by how macros worked in self-hosted ClojureScript and https://github.com/lread/info-clj-cljs-variants, but I don't think you are exploring that road...

kennytilton14:05:02

Thx, @UE21H2HHD! That is good doc, but you are right, CLJC introduces new concerns -- I cannot just have a final CLJS target without, as @U2FRKM4TW notes, duplicating everything in a CLJ file for a CLJ app to consume. Not a maintenance joy. 🙂 So CLJC solves that, and fortunately the compilers supports that, so I can have DEFMACRO forms in a CLJC file without and the compiler (my understanding) sorts that out on its own. Life is good (and CLJC and CLJS are impressive!). 🎉