This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-07-12
Channels
- # announcements (2)
- # babashka (22)
- # babashka-sci-dev (15)
- # beginners (62)
- # calva (2)
- # cider (8)
- # clj-kondo (33)
- # clojure (52)
- # clojure-europe (46)
- # clojure-losangeles (1)
- # clojure-norway (5)
- # clojure-spec (7)
- # clojurescript (31)
- # conjure (20)
- # data-science (4)
- # datalevin (16)
- # fulcro (28)
- # hyperfiddle (71)
- # introduce-yourself (3)
- # lsp (50)
- # off-topic (16)
- # polylith (8)
- # portal (3)
- # practicalli (1)
- # reitit (1)
- # releases (2)
- # tools-build (22)
- # vim (8)
- # xtdb (17)
What does :>
mean? I see it a lot in ClojureScript React Native guides, but not sure if it's actually related to that
But that keyword is being used as part of the syntax of whatever dsl, I guess reagent
To my understanding it's used when you want to use a javascript component like material ui:
[:> muc/Tabs options [...]]
Where muc
is imported like:
["@material-ui/core" :as muc]
Yup, it's a particularity of their hiccup-like syntax, you can see it in action here: https://cljdoc.org/d/reagent/reagent/1.2.0/doc/tutorials/interop-with-react#creating-reagent-components-from-react-components
Still a little confused about the syntax here - my understanding that per the linked doc, :>
is shorthand for a function, but it’s called like [:> rn/Text "Text"]
, so an element in a vector. If it’s a function, shouldn’t it be called like [(:> rn/Text "Text")]
?
the meaning is given to it by the library that is processing the datastructure it appears in
Oh so it’s creating a data structure that Reagent knows “this keyword means that the next symbol is a JavaScript component”?
user=> [:> 1 2]
[:> 1 2]
user=> (type [:> 1 2])
clojure.lang.PersistentVector
user=> (mapv type [:> 1 2])
[clojure.lang.Keyword java.lang.Long java.lang.Long]
user=>
runtime more likely, not compile time, given the examples I've seen, but I am not sure
Is compile “take this CLJS and write a JS file”? wouldn’t that be the only time this would be possible?
the compiled output for something like (fn [] [:> 1 2])
is compiled for clojurescript, but in generally you can assume it will generate javascript code that when it is run will produce a function that when called will return a cljs vector where the first element is the keyword :>
and the second is the number 1
, etc
there is no reason other code cannot traverse and do whatever it wants with that datastructure
the cljs world is a little bit fonder of ridiculous macros, which is how you would handle this at compile time, so I won't rule that out, but with the examples I've seen there would be significant challenges to doing this all as a macro at compile time, so my guess would be the datastructure is run through an interpreter at runtime
https://github.com/reagent-project/reagent/blob/a14faba55e373000f8f93edfcfce0d1222f7e71a/src/reagent/impl/template.cljs#L282 part of the little interpreter
How do you guys go about checking for nil in a series of calls (threading macro or let-chain)? From what I've found, it seems like several people are using custom macros for if-let
/`when-let` to support multiple bindings, but considering how common it is to get something, then check that what you tried to get is actually there, I expected to find some kind of standard approach.
Just checking for nil is obviously poor man's validation, but often it's enough. Take this example,
(if-let [a (op-1)
b (op-2 a)
c (op-3 b)]
;; success
;; error
)
How would you go about achieving this, checking that a
, b
and c
are not nil? Considered chaining the forms like (some-> (op-1) (op-2))
but wanted to check how you guys do this first. 🙂(let [[a b c :as var-list] [1 3 2
;;; (op-1) (op-2 a) (op-3 b)
]]
(if (not-any? nil? var-list)
:success
:not-very-successful
)
)
I think he's intending that if-let
works the same as let
with an if
inside. So I think
(if-let [result (some-> (op-1) op-2 op-3)]
:success
:fail)
is more what the op intends.Being able to retain the individual bindings is nice, but not strictly necessary for my use case. Was also mostly curious how others are solving this, so thanks for the feedback, both 😄
I didnt use this and have a quite vague understanding of monads but just lately came across this project: https://github.com/clojure/algo.monads where in tutorial 1 they do said task with
(defn f [x]
(domonad maybe-m
[a x
b (inc a)]
(* a b)))
Monads didnt seem to me much used in clojure thoughYa, I don't need to do this very often, but it's a shame if-let doesn't support more bindings
Yeah this pattern is encoded well with the “maybe monad” - that doesn’t mean you have to use the monad library but it’s a good source for a search term and validation that this is a familiar pattern!
elixir has a with
statement that acts like if-let
with multiple bindings, but it isn't conditional, if any of the bindings fail then there is some catch
like statement for handling that. maybe something similar could be done in clojure, possibly more intuitive than if-let
with multiple bindings.
heya. I’ve got two (more to come) scenarios for running a bunch of tests. So, I’d like to deduplicate them a bit. Right now, the two test cases have the same set of fixtures, but evaluated in different directories (`test/basic/` and test/not-basic/
); operating on some standard set of files (docker-compose.yml and some service config).
How could I get this sorted out? My first idea was to look into some sort of *file*
magic to figure out the right config to use, but maybe that’s a silly approach altogether. (I noticed that the test runner doesn’t let me resolve *file*
, it’ll be <expr>
.)
my setup is exactly that of https://blog.michielborkent.nl/babashka-test-runner.html, starting with the bb.edn paragraph.
exec-a1bd4801-48c2-4151-96ae-50c63588de11
unless I’ve done it wrong. I’ve added a (shell "echo" *ns*)
yeah, so my idea would be that each of the test files imports some generic fixture, which in turn will use the files from the test’s directory. if that’s not completely unreasonable.
I guess I could “just” parameterize the fixtures, give them the working dir (or the config file path directly) as argument. I guess that would be more explicit?
OK I’ll just go with that. I think I should be able to figure that out myself. thanks!
thank you!
(ns data-kafka-test
(:require [clojure.test :refer [deftest is testing use-fixtures]]
[babashka.http-client :as http]
[babashka.process :as process]
[test_utils :as util]))
(def dir "test/data-kafka")
(def messages "{\"id\": \"bob\", \"permissions\": [{\"path\": [\"cars\"], \"method\":\"GET\"}]}\n")
(defn publish-messages []
(process/shell {:dir dir :in messages} "docker compose run -T kcat -P -b broker:29092 -t users"))
(defn with-messages [f]
(publish-messages)
(f))
(use-fixtures :once (util/with-dc dir) with-messages)
☝️ test code
with this utility code 👇
(ns test_utils
(:require [babashka.process :refer [shell]]))
(defn start-docker-compose [dir] (shell {:dir dir} "docker compose up --wait --quiet-pull"))
(defn stop-docker-compose [dir] (shell {:dir dir} "docker compose down"))
(defn with-dc [dir]
(fn [f]
(start-docker-compose dir)
(f)
(stop-docker-compose dir)))
seems to work fine. thanks for your help. would you cringe when seeing this in the wild? 😄thanks for bearing with me. all that help! and it also helps to have a place where you (well, I) feel like no question is too basic or embarrassing.
Is it ill-advised to use the namespace part of a keyword (e.g. :ns\key
) to store data if the namespace part doesn't actually refer to a Clojure namespace?
For context, I'm building an api that has data that's always 1 level deep, so it would make sense for me to do :users/by-name
, :users/emails
, orders/count
, etc. to access information. I have a feeling it's okay because clojure.spec and next.jdbc seem to do it, but I wanted to get some opinions
What do you mean by "store data"?
But in answer to the Q I think you're asking, qualified keywords do not need to match code namespaces.
You can even use a long qualifier, like :
and say [this.is.my.qualifier :as-alias q]
in your :require
so you can use ::q/my-key
in your code without needing a namespace of code for this/is/my/qualifier.clj
(`:as` will load a namespace of code but :as-alias
will not)
Sorry for being vague, I was just trying not to get too far into the weeds. I'm using CouchDB which structures data from db -> design -> views. So I was going to use the namespace part as the design name, and keyword name as the view name. Something like:
(get-document db :design-name/view-name document-id)
.
I'm still not sure if I'm abusing the namespace part, or if I should just do`(get-document db [:design-name :view-name] document-id)`
It's good to know that there's no consequence for not matching code namespaces, and thanks for the tip about aliasing, I'll use it
The main idea behind qualified keyword is to provide context and uniqueness: if you have :id
or :name
it doesn't tell you much and it will collide with any other unqualified :id
or :name
keywords; if you have :user/id
or :account/name
you can tell more about it -- and you can have :page/name
and :account/name
in the same hash map.
Sounds like it fits with my use case. I'll play around with it. Thanks! I appreciate the help
Hi All, Is there a way I can combine these 2 collection passes into one, this code produces correct result but I am trying to reduce it to single pass.
(defn count-all-counties [coll]
(let [key1-count (->> coll
(group-by
#(get % :key1))
(count))
key2-count (->> coll
(group-by
#(get % :key2))
(count))]
(+ key1-count key2-count)))
reduce over coll and throw the values into sets in a map or something, and then count the sets
(defn count-all-counties [coll]
(count (reduce (fn [acc i]
(-> acc
(conj (:key1 i))
(conj (:key2 i))))
#{} coll)))
that would be something like thisit might be desirable to keep the values separate, assuming that there could be overlaps in the values and they should be counted separately
true!