Just watched Sean’s REPL talk using VS Code and Clover. If I’m pretty happy with my Calva set up is there any argument in favour of switching? Or is more a personal preference / devil you know sort of thing?
@allaboutthatmace1789 Mostly personal preference -- as I said in the talk, I want a setup that works with just a socket REPL and no additional dependencies in my project, so I have the exact same experience with any Clojure process running (since I can start a socket REPL via a JVM option -- not code).
Everything I showed can be done with (almost) any other editor/integration setup.
That makes sense, thanks!
Hi everyone, am wondering what is the best way to approach this problem I have. I have a list of data like so
'({ :lrow 0, :col 0, :lcol 2, :row 0 } { :lrow 2, :col 0, :lcol 1, :row 1 } { :lrow 2, :col 2, :lcol 2, :row 1 }))
my function will receive data like ...
{:coord {:row 0, :col 0, :sheet "Sheet1"},
:value "ABC",
:formula nil,
:style {:bold true}}
and I want to transform the data to be the following (when :row and :col correspond to an entry in the list) Aka add in :lrow and :lcol
{:coord {:row 0, :col 0,
:lrow 0, :lcol 2,
:sheet "Sheet1"},
:value "ABC",
:formula nil,
:style {:bold true}}
What might be the best way to approach this?I thought of using sets but doesn't fit exactly(?)
if you construct a map so that you can look up the lrow,lcol coordinates by row, col
what do you mean? 😮
it should be easy to check the map with the row
, col
of the :coord
map to add lrow
and lcol
if it exists
you want to construct a map like:
{[0 0] {:lrow 0, :col 0, :lcol 2, :row 0},
[1 0] {:lrow 2, :col 0, :lcol 1, :row 1},
[1 2] {:lrow 2, :col 2, :lcol 2, :row 1}}
so you can do something like:
(def coord-index {[0 0] {:lrow 0, :col 0, :lcol 2, :row 0},
[1 0] {:lrow 2, :col 0, :lcol 1, :row 1},
[1 2] {:lrow 2, :col 2, :lcol 2, :row 1}})
(def test-val {:coord {:row 0, :col 0,
:lrow 0, :lcol 2,
:sheet "Sheet1"},
:value "ABC",
:formula nil,
:style {:bold true}})
(let [{{:keys [row col]} :coord} test-val]
(if-let [{:keys [lrow lcol]} (get coord-index [row col])]
(update-in test-val [:coord]
assoc :lrow lrow :lcol lcol)
test-val))
Cool! That destructuring really helps I forgot that I could do that! And didn't think/know that I can use the row and col as an index in such a way And wasn't sure how to do the update
Thanks a bunch!
Gotta slow digest it
the example code I wrote is pretty dense. let me know if it would help if I unpacked it more.
Managed to unpack it once I figured out how the destructuring worked :)
I have a file looking like this:
(ns stuff)
(ns stuff-test (:require stuff) (:use clojure.test))
(with-test
(defn sum [s]
(+ s 2))
(is (= 2 (sum 1))))
and I'm asking CIDER to run all tests in project. But it's telling me that there are no tests. What am I doing wrong?Your test file test/project/core_test.clj
should look like
(ns project.core-test
(:require [clojure.test :refer :all]
[project.core :refer :all]))
(deftest a-test
(testing "FIXME, I fail."
(is (= 0 1))))
And your main file doesn't need any test stuffNot too sure where you got with-test
from
cider by default is looking for deftest
or defspec
in outer forms of namespace. then it extract a name associated with that form and run (test (var symbol))
that means with-test is not tracked by cider at all
consider to use deftest
also multiple ns
is not really a proper way to create namespaces
(ns stuff)
(defn x [] "!")
(ns sandbox.foo)
(defn x [] "@")
(x)
(stuff/x)
this is working but I believe will break namespace loading (eg. requiring stuff
from another namespace)I changed the file to this:
(ns stuff)
(ns stuff-test (:require stuff) (:use clojure.test))
(defn sum [s]
(+ s 2))
(deftest addition
(is (= 2 (sum 1))))
But the tests are still not being run, with the same message ("No assertions (or no tests) were run.Did you forget to use 'is' in your tests?")re multiple ns
: deleting the (ns stuff)
above doesn't help either. (I wanted to have multiple namespaces in one file initially and split them later.)
ok it actually helped but only after I restarted CIDER
so
(ns stuff-test (:use clojure.test))
(with-test
(defn sum [s]
(+ s 2))
(is (= 2 (sum 1))))
worksHello,
I have this as response from a api
({:levels
[{:name "z1",
:width 2810,
:height 2177,
:tiles
how can I now takes the levels parts out of it and then filter for the vector where the name is z6 ?
Might be a more idiomatic way, but here's my solution:
(filter #(= "z6" (:name %)) (:levels (first a)))
You can also do it with the thread last macro:
(def a '({:levels [{:name "z1",:width 2810,:height 2177, :tiles 12}]}))
(->> a
first
:levels
(filter #(= "z6" (:name %))))
is there a more idiomatic way to write (first (filter filter-function sequence))
Maybe the thread last macro?
->> sequence
(filter filter-function)
first
this seems all right... I was just wondering if there's a built-in function that I don't know about that. seems there isn't
Ad built-in function: such a proposal was rejected at some point -- see https://clojure.atlassian.net/browse/CLJ-2056?focusedCommentId=12986
(some #(when (filter-function %) %) sequence)
but this will fail if it suppose to return falseThe small library medley contains find-first
, and several other useful small functions: https://github.com/weavejester/medley
What is the difference between >! and put!?
the first is parking (used in go blocks only) - ie park the go block until the operation can succeed. latter is async, can be used from either in or out of go block
in most cases, if you are in a go block, you should prefer the parking operation (the async ops are lower level)
@alexmiller ah of course. For some reason I thought of parking and async as the same thing. Thanks!
This example fails to generate:
(require '[clojure.spec.alpha :as s])
(s/def :person/id string?)
(s/def :robot/id number?)
(s/def ::person
(s/keys :req-un [:person/id]))
(s/def ::robot
(s/merge ::person
(s/keys :req-un [:robot/id])))
(gen/sample (s/gen ::robot))
Is this behavior expected? I thought that one of the benefits of merging map specs would be that you could overwrite defaults specs for certain keysno, that's not expected to be supported
you've written a spec that has incompatible options for the same key
Okay, thanks! So if I understand correctly, the spec merge is semantically different than core merge. Core merge overwrites keys left to right, while spec merge tries to take the union of the map specs being merged. Sometimes, a union of specs can create an impossible to satisfy predicate
👋
Is the union of two specs achieved using s/and
?
Correct
If you want something that satisfies both, yes
But note that s/and flows conformed values
So using it on maps may not be what you want (it depends)
Spec 2 will have an s/and variant that does not flow conformed values (currently called s/and- but maybe to be called s/union)
Just FYI, there is #clojure-spec for more detailed spec questions
Thanks Alex! I am going to make a note to document this on clojureDocs when I have a moment. Super helpful
Oh, http://ClojureDocs.org does have pages for each function in Clojure spec now (and probably has for a while now). I just didn't notice them.
I have a really basic question about spec. I have a library where I define some specs (s/def). They are used in the library for various things and they work fine. However, I would also like to use some of the specs from outside the library (as options or config validation, for example), but I can't figure out how to use the spec outside of the original library. Contrived example (excuse the syntax errors):
(ns my.lib (:require [clojure.spec.alpha :as s]))
(s/def ::is-thingy string?)
(defn publicfn [thing] {:pre [(s/valid? ::is-thingy thing)]} ,,,) ;; this works fine
In client:
(ns my.client (:require [my.lib :as lib] [clojure.spec.alpha :as s])
(defn my-code [options] (when (s/valid? ::lib/is-thingy (:thing options)) ,,,)) ;; this doesn't. "Unable to resolve spec: :my.lib/is-thingy.
How do I refer to the spec definitions created in the library, outside of that library?:my.lib/is-thingy
is the fully-qualified name of your spec
::lib/is-thingy
should work as a way of creating an alias - your code works for me
🤦 I didn't run clojure -X:jar
before installing the library...
Thanks. Must be some other issue I'm having then. Maybe it's not resolving the correct library.
Is multiple maps in sequence in a threaded macro a smell?
(defn get-game-data
[user-id]
(let [url (str BASE_URL user-id)
request-headers {:headers {:accept "application/x-ndjson"}
:query-params {:max 20}}]
(as-> (client/get url request-headers) games
(:body games)
(str/split games #"\n")
(map json/read-str games)
(map walk/keywordize-keys games)
(map #(update-in % [:moves] str/split #" ") games))))
Stuff like the above. I could make it a single map, but then the code wouldn't be as clean@seancorfield Thank you for your Clojure London talk on REPL-Driven Programming. I learned quite a bit! (ref for others: https://www.youtube.com/watch?v=gIoadGfm5T8)
Glad it was useful!
seems fine to me. I guess I would usually reach for ->
or ->>
before as->
. some people really don't like as->
used outside of another arrow form (I don't agree with this)
I'm one of those "some people". I think using as->
there makes it much harder to read...
if you're talking about 10s or maybe even 100s of things, then I wouldn't worry about it, clarity wins. if trying improve perf, better to move to transducers and then multiple maps is also not a big deal.
(-> (client/get url request-headers)
:body
(str/split #"\n")
(->> (map json/read-str)
(map walk/keywordize-keys)
(map #(update-in % [:moves] str/split #" ")))
That is much clearer to my eyes.What this highlights is that you're changing the data type in the middle of the pipeline (from a "thing" to a sequence).
At which point, this applies: https://stuartsierra.com/2018/07/06/threading-with-style
And a follow-up post specifically about as->
: https://stuartsierra.com/2018/07/15/clojure-donts-thread-as
Yes, it was good 🙂 @vlaaad needs to take down his xmas tree though...👀🌲
It's so snowy here in Stockholm, finally some Christmas weather!
I have this code :
(->> (read-all-data)
(filter-artObjects)
(filter-all-objectNumbers)
(ask-for-image-data)
(map filter-image-url))
which produces this :
{:name "z5"
:width 146
:height 179
:tiles
[{:x 0
:y 0
:url
"<http://lh3.googleusercontent.com/dgdeRabPYriIi7v5R3fAk6cudxssTV_oEVaXz1zSo9UPlTcUPAJgZan9jhCfAPzjwtpDTb0v5vSja0uyrSR4LatmTw=s0>"}]})
clj꞉paintings.core꞉>
is there a way I can make it output like this : {width: xx , height: xx url: xxx} ` ?could be, but then I have to take them out when displaying with hiccup. Maybe I have to reconsider my code because later I would like to add the objectnumber I get from a much earlier code to the map. Right now it seems to be impossible
here in the netherlands no snow the whole winter 🙂
It was like that here last year
but maybe net Sunday we have a few hours snow
how many tiles do you expect? always 1?
yep
(defn lift-first-tile [image]
(let [tile (-> image :tiles first)]
(-> image
(dissoc :tiles)
(merge tile))))
(lift-first-tile
{:name "z5"
:width 146
:height 179
:tiles
[{:x 0
:y 0
:url
"<http://lh3.googleusercontent.com/dgdeRabPYriIi7v5R3fAk6cudxssTV_oEVaXz1zSo9UPlTcUPAJgZan9jhCfAPzjwtpDTb0v5vSja0uyrSR4LatmTw=s0>"}]})
;; => {:name "z5",
;; :width 146,
;; :height 179,
;; :x 0,
;; :y 0,
;; :url
;; "<http://lh3.googleusercontent.com/dgdeRabPYriIi7v5R3fAk6cudxssTV_oEVaXz1zSo9UPlTcUPAJgZan9jhCfAPzjwtpDTb0v5vSja0uyrSR4LatmTw=s0>"}
??? now I get everything. I only need the 3 i have said
try select-keys
, in that case 🙂
another approach:
(defn lift-first-tile-url [image]
(let [url (-> image :tiles first :url)]
(assoc image :first-tile/url url)))
(lift-first-tile-url {:name "z5"
:width 146
:height 179
:tiles
[{:x 0
:y 0
:url "http:<http://google.com|google.com>"}]})
;; => {:name "z5",
;; :width 146,
;; :height 179,
;; :tiles [{:x 0, :y 0, :url "http:<http://google.com|google.com>"}],
;; :first-tile/url "http:<http://google.com|google.com>"}
(defn filter-image-url [imagedata]
(->> imagedata
:levels
(sort-by :name)
(last))
(select-keys [:width :height]))
; Error printing return value (ArityException) at clojure.lang.AFn/throwArity (AFn.java:429).
; Wrong number of args (1) passed to: clojure.core/select-keys
a few things jump out at me. first, i think there's a misplaced close parens in the example above - last))
closes the thread last macro before including the call to select-keys
. so that may not be what you want
second, select-keys
expects the map in the first position and the key sequence in the second, but the thread last macro ->>
will feed imagedata
into the last argument of select-keys
you can play with macroexpand-1
to see that:
(macroexpand-1 '(->> imagedata
:levels
(sort-by :name)
(last)
(select-keys [:width :height])))
;; => (select-keys [:width :height] (last (sort-by :name (:levels imagedata))))
does that help?
I need to write something that 1) subscribes to a rabbitmq queue 2) gets a message and writes it to a TCP socket 3) TCP socket must be always open otherwise client (a Spark cluster) will close. AFAIK I need two loops concurrently: 1 to subscribe to rabbitmq and the other to serve the TCP socket. I have never done such a thing and would like to try doing in clojure. What literature do you recommend for such a problem?
Depending on a tcp socket to always be open is usually a bad idea
to see where the problem is yes, to see how to solve it not at the moment
I think it won’t work otherwise, but in any case could you expand on why? I haven’t had experience with these topics at such a low level
Network hiccups are surprisingly common
maybe “always open” is not the correct nomenclature
part of the difficulty can be managing the thread first vs thread last. thread last is good at handling collections but thread first is good at handling associative data structures. if you have an existing threading macro and you want to add an expression that requires the "opposite" argument placement, try writing a function
i'll show an example in a second
oke
https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html#quick-example they use netcat in the tutorial. When you launch nc ...
is it “always on”?
(defn add-key
[m]
(assoc m :c 3))
(->> [{:a 1} {:b 2}] ; <- we're starting with a collection
(filter #(contains? % :a)) ; the vector is placed last in `filter`
first
add-key ; <- `assoc` wouldn't work directly because it expects the map as the first argument
)
;; => {:a 1, :c 3}
My guess is this is written with spark as the client, and your code as the server to deal with exactly this kind of thing
Or not, I dunno
right, so I need to a server running plus the rabbitmq subscriber which also runs in a loop 🤷
My comment about networking hiccups is mostly on the scale of weeks to months, if your whole whatever has a shorter runtime than that you might not care
so, applying that strategy to your filter-image-url
function:
(defn filter-image-url [imagedata]
(let [just-width-and-height (fn [image] (select-keys image [:width :height]))]
(->> imagedata
:levels
(sort-by :name)
(last)
just-width-and-height)))
Can I use the same "trick" to get also the url ?
i guess it depends on the context and the shape of the data. you originally had a thread-last form that returned a single map with the :tiles
value. you could add a function lift-first-tile
to the thread last pipeline. that could be one approach
this is unrelated, but consider whether you really need to exclude the other keys. often in clojure folks find that it's useful, or at least harmless, to pass maps around that include additional data, even if it isn't strictly required.
is there an easy way to remove all existing taps
i find that i've polluted my set of taps with various functions over time and can't seem to remove-tap
all of them
i should just restart the repl.
yeah, a big gotcha is adding a function itself as a tap, rather than the var holding the function
which means when you redef the function, you no longer have the thing to call remove-tap on
(reset! @#'clojure.core/tapset #{})
should work
its just a private atom with a set. you can see from the source of remove-tap
that there's no cleanup dance to do. just toss it
thanks!
@noisesmith do you mean i should (add-tap (var f))
instead of (add-tap f)
?
if you want to be able to reload f, yeah (or the equivalent of (var f)
, #'f
)
f itself is no longer equal after you run defn again, the var remains equal to the var
I'm trying to use next/jdcb for a mssqlserver. I can't see how to specify "TrustedConnection=True;" rather than providing a username and password?
thanks, this has proven really useful just now in refining what i want f
to be
@qmstuart You can pass extra properties via the db-spec hash map (that you build a datasource from): {:dbtype "mssql" :dbname "your-db" :TrustedConnection true :host "..."}
something like that I expect.
Then call jdbc/get-datasource
on that (and then use that return ds everywhere). If you're using a connection pool, you'll need to consult the docs for the pooling library in use and figure out how it passes properties to the driver manager.
#sql is a good place for next.jdbc
questions as well as general DB-related stuff.
thanks! I dunno how I didn't see :TrustedConnection. I looked at the docs, I swear 😄