This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-03-25
Channels
- # announcements (8)
- # aws (50)
- # aws-lambda (6)
- # babashka (25)
- # beginners (119)
- # bristol-clojurians (5)
- # calva (25)
- # chlorine-clover (23)
- # cider (6)
- # cljs-dev (125)
- # clojure (63)
- # clojure-austin (1)
- # clojure-belgium (1)
- # clojure-dev (48)
- # clojure-europe (11)
- # clojure-italy (2)
- # clojure-nl (5)
- # clojure-spec (3)
- # clojure-uk (66)
- # clojurescript (14)
- # core-logic (5)
- # datomic (13)
- # emacs (10)
- # events (2)
- # fulcro (37)
- # graalvm (11)
- # hoplon (95)
- # jobs-discuss (9)
- # juxt (11)
- # kaocha (16)
- # meander (13)
- # off-topic (24)
- # pedestal (4)
- # re-frame (36)
- # reagent (10)
- # reitit (15)
- # ring-swagger (5)
- # shadow-cljs (23)
- # spacemacs (2)
- # sql (13)
- # tools-deps (32)
- # xtdb (11)
It was a Jackson issue (I think)
I installed version 2.10.3
of Jackson and now it's functioning correctly
I'm not sure I quite understand what went wrong
Why didn't leiningen pick up that I needed it?
tl:dr jackson is terrible
it uses your recursive deps, the version of jackson someting else used was not compatible with the versin amazonica needed
by adding a version explicitly, you forced it to use the version amazonica could use
luckily you didn't also break some other lib in the process (that can happen sometimes)
Does that mean that somewhere a project had an implicit dependency on jackson, or that lein chose a different version to use?
that's why I suggested running lein deps :tree
- that exposes the recursive dep path (the short version is lein goes depth first and registers versions in order of your dep vector)
it also warns you if different libs wanted different versions of the same lib, usually this is innocuous because libs maintain some compatibility, but jackson really doesn't do that
interesting. Thanks for the help 🙂
@noisesmith I'll agree that Jackson is terrible (from a version conflict p.o.v.) but it's so widely used it's hard to get away from. Are there non-Jackson JSON options that behave better?
(asking for a friend, honest!)
I recall that once upon a time, in the distant early years, many of us changed from data.json to cheshire because data.json had a release that renamed a few functions. But it was long enough ago I could be remembering wrong.
I just went and looked at metosin/jsonista
hoping it wasn't based on Jackson. It is.
(we switched from data.json
to Cheshire because the former failed to correctly format some things we had -- but Cheshire worked flawlessly... of course, I should have reported a bug against data.json
which I don't think I did, because I needed a working JSON converter "immediately" to resolve a problem at work)
Cheshire depends on Jackson also. I guess it uses it in a different more performant way, but that wouldn't prevent dependency problems.
Right, and lots of things use Cheshire under the hood so it's very hard to avoid Jackson 😞
clj-http
, for example, if you use any of its built-in JSON stuff.
Yes, I'm using etaoin
and it also uses Cheshire. At work we've also had lots of problems with Jackson breakage.
Ya, I was surprised that no Clojure wrapper for Gson existed. Maybe the Gson model doesn't let you build a Clojure parser, and is too specific to Java. But Gson in Java land is much more dependency friendly.
oooh - that might be a worthwhile evening hack :D
looking at the API, seems very sensible so far (should be easy to use directly...)
regarding the Gson discussion the other day: as far as I'm concerned this just works and doesn't require a wrapper lib:
user=> (def gson (Gson.))
#'user/gson
user=> (.toJson gson {:a 0 :b 1 :c [1 2 3] :d #{4}})
"{\":a\":0,\":b\":1,\":c\":[1,2,3],\":d\":[4]}"
custom type registry that isn't global:
user=> (def gson-custom (com.google.gson.GsonBuilder.))
#'user/gson-custom
user=> (.registerTypeAdapter gson-custom clojure.lang.Atom (reify com.google.gson.JsonSerializer (serialize [this src _type context] (com.google.gson.JsonPrimitive. @src))))
#object[com.google.gson.GsonBuilder 0x145414f "com.google.gson.GsonBuilder@145414f"]
user=> (def gson-2 (.create gson-custom))
#'user/gson-2
user=> (.toJson gson (atom 12))
"{\"state\":{\"value\":12},\"watches\":{}}"
user=> (.toJson gson-2 (atom 12))
"12"
I didn't actually experiment with that half yet, but it definitely looked straightforward
Another possibly "cool?" option. I wonder if Cheshire could bundle the Jackson libs in a shaded state.
It's like taking the appropriate Jackson libs, renaming the package to something unique, have Cheshire import those renamed packages, and bundle them with Cheshire.
Can cider just load functions from a local file? I've set up emacs and I can start cider-jack-in but it gives me an error that im not using a project. I just want to have the repl load in my functions and be able to edit them and run. any ideas?
cider-scratch
can be used if you dont have a project. However, as you are creating a file, then it will simplify things greatly if you create a Clojure project.
Leiningen is a build tool that has been around for a long time, so lots of people use it to create a project.
Clojure CLI and tools deps is the approach many people are taking for new projects.
As people have mentioned, the BraveClojure Emacs setup setup is about a dozen major releases out of date and significant changes have been made to CIDER.
For Emacs & Clojure, Prelude, Doom and Spacemacs seem to be the most popular community configurations. Prelude provides the essentials, Doom provides a bit more opinionated features and Spacemacs is a full batteries included experience. I use Spacemacs and am writing this guide on Clojure development with Spacemacs/Emacs https://practicalli.github.io/spacemacs/
@me1159 it wants to start an nrepl from a specific project, you can set emacs' current directory before running jack-in, or start emacs from that dir, or use cider-connect and point it to a port for a repl you already started
You mightve mentioned the wrong person 😃 ha
oh sorry
how would I set emacs current dir after its started?
I guess I can google that
https://emacs.stackexchange.com/questions/36980/how-to-change-the-current-working-directory
I think default-directory
is actually the thing you want though, q's assumptions notwithstanding
@me1159 sesman-link-* commands are also useful if you already have a repl and just want to connect it to a file in a different dir
so i tried using the cider-connect-clj to connect it to the same instance that cider-jack-in-clj started but im not really clear how to fun the function I have in my file
maybe the way I want to do this is just wrong. I basically just want to have a scratch pad of functions I can just rapidly iterate on and run in a repl without needing lein and stuff.
Ive just been copying things out of a file and into the repl and running them but thats tedious
if your file didn't define a namespace form, the function you defined should end up in the repl's default ns, or user if there is none
you can use (apropos "function-name")
also
user=> (apropos "merge")
(clojure.core/merge clojure.core/merge-with clojure.spec.alpha/merge clojure.spec.alpha/merge-spec-impl)
@me1159 clojure namespaces everything, so even for "scratch" code, it's less friction to just put (ns scratch)
at the top of the file
or whatever you want to call your default / dummy / wip ns
so my function is just
(defn foo
"test"
[]
(println "foo))
ill try namespacing it
if you do (apropos "foo")
it will show you where it ended up
so I get this
user> (apropos "foo")
()
i made a directory in /tmp/blah, made a file called foo.clj, cider-jack-in and everything works for me
sure one sec
does it also matter I loaded up the clojure for the brave and true defaults for emacs. Im also using the gui emacs not the emacs that comes preloaded on mac
the above is gui emacs. can you link me to the clojure for the brave and true setup you're using?
that's an old CIDER. can i recommend using a well done emacs startup called prelude? It's by the maintainer of CIDER and is tastefully done: https://github.com/bbatsov/prelude
im totally cool with that
thanks. yea ill try that and see if it that works. I knew there was no way it could be this difficult
btw just curious where did you find the cider version that project was using? I know he takes PR's to keep that stuff updated
don't kno why but I installed prelude and theres no cider options available when M-x
sry to spam you. I got cider installed. stil the same issue. cider just doens't bring in the file. im going to try something else.
im just simply starting cider-jack-in from the buffer where the file is
I literally setup the same structure as you
foo.clj , ns foo, defn foo that adds a number
ok. is that (load-file) then?
M-x
that in the cider buffer?
sorry im like drinking from the clojure/emacs/cider firehouse right now trying to set up an envrionment
im suspecting this page is very helpful https://docs.cider.mx/cider/usage/cider_mode.html#_basic_workflow
god damnit =( PEBKAC
thank you for your help. going too fast here.
it works
This is making more sense now. The whole repl idea and live coding is insane but this is neat. thanks again so much
that means the current clojure process didn't get a foo defined anywhere
on my API i’m checking if some parameters are present
(or (empty? customer-uuid) (empty? debtor-uuid))
(error-response "Customer or Debtor UUID is missing!")
the error-response
is a bit meh.. how would you get the parameter that is missing (or both), and add that to the message so that is reads like "
customer_uuid` is missing, but expected UUID"`I'd probably use cond
and have each error condition tested separately (so they each can have a separate error response), then :else (happy-path)
at the end of the checks.
@U04V70XH6 so you test 3 conditions? 1 - neither are present 2 - customer is not present 3 - debtor is not present
(cond (empty? customer-uuid) (error-response "`customer-uuid` is missing")
(empty? debtor-uuid) (error-response "`debtor-uuid` is missing")
:else (happy-path))
depending on exactly what error messages I wanted from which conditions.Is there an idiomatic way to write to files in directories that may not exist?
also see https://clojure.github.io/clojure/clojure.java.io-api.html#clojure.java.io/make-parents
if you want to avoid interop
Wondering about best practice when it comes to protocols. In Java I'd declare an Interface, let's say MessagingService, in its own self-contained file. I'd then create two other files, RabbitMQService and DummyService, and in each implement the Interface. In Clojure, do most declare these things all in the same file?
it's really up to you - one place for protocols vs. various implementations, vs all in one place - it's more a question of your app's needs, but it is usually simpler to put the implementations with the protocol if they are created to be mutual alternatives rather than something open ended for user extension
On contrary, I'd recommend putting the protocol in a separate namespace, not only for code organization but to avoid issues with code reloading in the REPL
@U06GS6P1N it's the opposite - if every extension of the protocol is in the same ns as the protocol, you don't end up with the protocol and extensions going out of sync
the protocol and instances implementing it can go out of sync just as easily with both approaches
actually, I guess if you never reload the protocol ns, that can help with values going out of sync with the protocols they implement
I have a 2-d vector with values in each position, and I'd like to set values inside a certain range of x and y coordinates. Is there an idiomatic way to do this functionally? I know how I'd do it imperatively, but I can't figure out a simple way to do this functionally.
Something like a cumulative for
loop?
clojure for is a list comprehension, not a loop - it's useful for generating lists but not transforming inputs per se
@ordoflammae I would use a reduce
with (range i j)
as a collection input providing all the indexes
something like (reduce (fn [v idx] (update v idx f)) my-vec (range i j))
where if takes current value at index idx and returns the replacement
(you can change the update call if f should get different input, of course)
Ah. Thanks @noisesmith for the help.
That makes so much more sense.
(ins)user=> (def i 2)
#'user/i
(ins)user=> (def j 5)
#'user/j
(ins)user=> (reduce (fn [v idx] (update v idx (fn [old] (+ old idx)))) [1 1 1 1 1 1 1 1] (range i j))
[1 1 3 4 5 1 1 1]
for indexes i through j-1 (2,4) it updates value at index by summing with its index
regarding the Gson discussion the other day: as far as I'm concerned this just works and doesn't require a wrapper lib:
user=> (def gson (Gson.))
#'user/gson
user=> (.toJson gson {:a 0 :b 1 :c [1 2 3] :d #{4}})
"{\":a\":0,\":b\":1,\":c\":[1,2,3],\":d\":[4]}"
custom type registry that isn't global:
user=> (def gson-custom (com.google.gson.GsonBuilder.))
#'user/gson-custom
user=> (.registerTypeAdapter gson-custom clojure.lang.Atom (reify com.google.gson.JsonSerializer (serialize [this src _type context] (com.google.gson.JsonPrimitive. @src))))
#object[com.google.gson.GsonBuilder 0x145414f "com.google.gson.GsonBuilder@145414f"]
user=> (def gson-2 (.create gson-custom))
#'user/gson-2
user=> (.toJson gson (atom 12))
"{\"state\":{\"value\":12},\"watches\":{}}"
user=> (.toJson gson-2 (atom 12))
"12"