Fork me on GitHub
#beginners
<
2022-03-03
>
domparry07:03:44

Or Transit.

👍 1
teodorlu07:03:42

But transit requires a dependency, right?

happyb3at10:03:19

I am stuck figuring out how to create a list with elements from 2 long object ? argh> (def bob 3) #'argh/bob argh> (def sue 7) #'argh/sue argh> (def l1 '(7 3)) #'argh/l1 argh> l1 (7 3) argh> (def l1-from-bob-n-sue '(bob sue)) #'argh/l1-from-bob-n-sue argh> l1-from-bob-n-sue (bob sue) But i want same as l1 ie.. (7 3)

Ferdinand Beyer10:03:26

Use (list bob sue)

Ferdinand Beyer10:03:19

The problem is that you use quote: '(bob sue) does not evaluate bob and sue but just keeps them as symbols. The list function evaluates its arguments and puts them in a list. Alternatively you could use “syntax quote” with “unquote”:

(def l1-from-bob-n-sue `(~bob ~sue))
Here, the backtick is a special form of quoting allowing to selectively “unquote” using the tilde ~. But list is probably easier to read 🙂

pavlosmelissinos10:03:09

Or simply use a vector instead

✔️ 3
happyb3at10:03:41

thx was trying to get list via ' but I can see my error now 😀 thx alot

happyb3at10:03:30

Yeah the unquote thingy was the missing thing in my idea but def list was the intent

happyb3at10:03:03

Why vector isnt that just another form of memory layout ? How does vector makes it easier?

mbjarland10:03:04

Vectors do not require quoting, i.e. you can just write (def l1-from-bob-n-sue [bob sue]) and yes vectors grow (`conj`) at the end whereas lists grow at the beginning. Using vectors is idiomatic and common in clojure.

Tuomas-Matti Soikkeli10:03:05

You can pretty much always use vector [bob sue]. If you are really thinking how to optimise your performance, list has O(n) random access look up time compared to O(1) in vector.

happyb3at10:03:12

thx for the vector reply

happyb3at10:03:43

thx for the vector replys ..

Tuomas-Matti Soikkeli10:03:33

I think quotes are from the lisp heritage and perhaps not the first thing you should consider learning

👍 1
pavlosmelissinos10:03:57

Yes @UTA54EFQF, the internals are different between vector and list but even though lists definitely have their uses, most of the time, especially as a beginner, when you think you need a list you really want a vector in Clojure, so reach out for vectors first.

(comment
  (def l (list :a :b :c))
  (def v [:a :b :c])
  
  (get v 1) ;; => :b
  (get l 1) ;; => nil
  (conj v :d) ;; => [:a :b :c :d]
  (conj l :d) ;; => (:d :a :b :c)
  (assoc v 1 :new-b) ;; => [:a :new-b :c]
  (assoc l 1 :new-b) ;; => ClassCastException
  )
(plus the whole O(1) vs O(n) random access)

happyb3at12:03:29

thx alot for the advice i really appreciate

zendevil.eth15:03:21

does anyone know what might be causing this error when I’m making a request to the server:

{:cached nil, :request-time 35, :repeatable? false, :protocol-version {:name "HTTP", :major 1, :minor 1}, :streaming? true, :http-client #object[org.apache.http.impl.client.InternalHttpClient 0xb6a995b "org.apache.http.impl.client.InternalHttpClient@b6a995b"], :chunked? false, :type :clj-http.client/unexceptional-status, :reason-phrase "Server Error", :headers {"Connection" "close", "Cache-Control" "must-revalidate,no-cache,no-store", "Content-Type" "text/html;charset=iso-8859-1", "Content-Length" "3076", "Server" "Jetty(9.4.28.v20200408)"}, :orig-content-encoding nil, :status 500, :length 3076, :body "<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/>\n<title>Error 500 java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #&apos;ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap</title>\n</head>\n<body><h2>HTTP ERROR 500 java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #&apos;ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap</h2>\n<table>\n<tr><th>URI:</th><td>/api/login</td></tr>\n<tr><th>STATUS:</th><td>500</td></tr>\n<tr><th>MESSAGE:</th><td>java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #&apos;ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap</td></tr>\n<tr><th>SERVLET:</th><td>-</td></tr>\n<tr><th>CAUSED BY:</th><td>java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #&apos;ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap</td></tr>\n</table>\n<h3>Caused by:</h3><pre>java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #&apos;ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap\n\tat clojure.core$_cache_protocol_fn.invokeStatic(core_deftype.clj:583)\n\tat clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:575)\n\tat ring.core.protocols$eval25675$fn__25676$G__25666__25685.invoke(protocols.clj:8)\n\tat ring.util.servlet$update_servlet_response.invokeStatic(servlet.clj:106)\n\tat ring.util.servlet$update_servlet_response.invoke(servlet.clj:91)\n\tat ring.util.servlet$update_servlet_response.invokeStatic(servlet.clj:95)\n\tat ring.util.servlet$update_servlet_response.invoke(servlet.clj:91)\n\tat ring.adapter.jetty$proxy_handler$fn__32745.invoke(jetty.clj:28)\n\tat ring.adapter.jetty.proxy$org.eclipse.jetty.server.handler.AbstractHandler$ff19274a.handle(Unknown Source)\n\tat org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)\n\tat org.eclipse.jetty.server.Server.handle(Server.java:500)\n\tat org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383)\n\tat org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:547)\n\tat org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375)\n\tat org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:273)\n\tat org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)\n\tat org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)\n\tat org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117)\n\tat org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806)\n\tat org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938)\n\tat java.base/java.lang.Thread.run(Thread.java:833)\n</pre>\n<hr><a href=\"\">Powered by Jetty:// 9.4.28.v20200408</a><hr/>\n\n</body>\n</html>\n", :trace-redirects []}
 

dpsutton15:03:42

The error is > java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap Seems straightforward. You returned a map from a handler and your app doesn’t know how to serialize that to the response. I am guessing you intended that to come back as json or edn but haven’t hooked up the middleware that would do that transformation?

James Amberger17:03:44

Hello, can I have the accepted way to go from {:a []} to {:a [:b]} ? in particular when using update-in?

ghadi17:03:43

What have you tried?

James Amberger17:03:15

Is it just (update-in {:a []} [:a] cons :b)

ghadi17:03:28

Yup, except conj not cons

ghadi17:03:45

conj = generic “add to collection”

ghadi17:03:56

cons = specific prepend to list

ghadi17:03:51

user=> (conj [1 2 3] 4)
[1 2 3 4]
user=> (cons [1 2 3] 4) ;; broken arg order!
Execution error (IllegalArgumentException) at user/eval3 (REPL:1).
Don't know how to create ISeq from: java.lang.Long
user=> (cons 4 [1 2 3])
(4 1 2 3) ;; note it returns a seq, not a vector!

James Amberger17:03:52

yeah but isn’t it (conj coll item) where the funciton here will be getting coll in the last position?

ghadi17:03:34

update-in and similar functions will apply the function you pass (conj) to the thing it found, followed by trailing args

ghadi17:03:47

thing it found = []

ghadi17:03:51

trailing args = :b

ghadi17:03:08

(conj [] :b)

James Amberger17:03:39

“followed by trailing args” ok I see

James Amberger17:03:51

I did not grok this point about the behavior of update-in

ghadi17:03:54

you can add more trailing args

ghadi17:03:05

if the function you are passing can handle them

James Amberger17:03:20

i can add more rtailing args but the second position of what’s gonna get executed will be the [] (in this case)

ghadi17:03:28

there are a few other functions in clojure.core with this same exact argument shape: update-in update swap!

ghadi17:03:25

(update-in {:foo [:x]} [:foo] conj :b :c :d) (conj [:x] :b :c :d)

James Amberger17:03:50

As a beginner, I think the docstring for update-in is unnecessarily subtle as to this point!

andy.fingerhut18:03:49

I would recommend checking the community-written http://ClojureDocs.org on update-in to see if it clarifies anything for you. It is not "official" docs, but there are often helpful examples there that the core documentation does not have.

andy.fingerhut18:03:50

You can create an http://ask.clojure.org question asking whether the built-in doc strings can be enhanced, but there is a very high bar there to pass before the Clojure core team would agree to changes.

ghadi17:03:50

ninja edited that ^

James Amberger17:03:13

definitely saved me a couple million brain cycles

🧠 1
zendevil.eth18:03:14

does anyone know how one can replicate a request that contains :body-params using clj-http or peridot that don’t support the :body-params keys but in which the params have to be sent in the body? Here are body-params being sent: https://github.com/metosin/reitit/blob/acfc48faa180e7e194667425147bb9f9e870dc8c/examples/ring-spec-swagger/test/example/server_test.clj#L20. But when I try to send body-params like so using peridot:

(-> session
      (request "/api/reset-password"
               :content-type "application/json"
               :request-method :post
               :body (cc/generate-string
                      {:email email
                       :newPassword newPassword
                       :resetToken token}
                      )))
the body-params don’t seem to be detected in the server. What am I doing wrong?

hiredman18:03:25

you need to look at the set of middleware that server uses

hiredman18:03:48

the set of middleware will tell you how and where the :body-params key comes from, which will tell you how it needs t o be sent

zendevil.eth18:03:54

we’re using the same middleware as in the github example:

[;; swagger feature
   swagger/swagger-feature
   ;; query-params & form-params
   parameters/parameters-middleware
   ;; content-negotiation
   muuntaja/format-negotiate-middleware
   ;; encoding response body
   muuntaja/format-response-middleware
   ;; exception handling
   exception/exception-middleware
   ;; decoding request body
   muuntaja/format-request-middleware
   ;; coercing response bodys
   coercion/coerce-response-middleware
   ;; coercing request parameters
   coercion/coerce-request-middleware
   ;; multipart
   multipart/multipart-middleware]
but they seems to get the body-params in the server, whereas we don’t

hiredman18:03:52

I dunno anything about all this metosi stuff, but you have format-response-middleware and don't appear to have similar for requests

zendevil.eth18:03:48

@hiredman I have both muuntaja/format-request-middleware and muuntaja/format-response-middleware

hiredman18:03:15

then you need to look at request middleware, figure out its rules for decoding stuff (good luck) and then have your requests put things in the format it wants

maverick19:03:58

Can I pass a value by reference in clojure ?

bronsa19:03:51

technically all objects are passed by reference on the JVM (apart from primitive values like longs and doubles)

bronsa19:03:16

can you clarify what you actually need to do?

maverick19:03:59

I need to pass a map to a function and need to add new key-value pair in that map and then use that map back in the calling function.

andy.fingerhut19:03:59

All Clojure collections are immutable. The typical way to do what you ask for is to pass one collection as a parameter, and the function returns a new collection that is similar to the one passed in, but with whatever "changes" you want to return, in the return value.

andy.fingerhut19:03:22

This is a big shift in thinking in day-to-day application development if you are accustomed to mutating objects.

andy.fingerhut19:03:51

In Clojure on the JVM, you can of course use mutable Java collections if you want to.

andy.fingerhut19:03:12

And in ClojureScript, you can use mutable JavaScript collections.

maverick19:03:17

The thing is that it is already returning a function and I can not return new collection so I need to find way of extracting that value somehow

zendevil.eth19:03:00

I think this might fix it: [ring.middleware.format-params :refer [wrap-format-params]] but including this gives:

Could not locate ring/middleware/format_params__init.class, ring/middleware/format_params.clj or ring/middleware/format_params.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.

zendevil.eth19:03:22

even though I have ring in my project.clj

hiredman19:03:32

sure, what makes you think ring.middleware.format-params is a thing?

hiredman19:03:49

what happens on the server side when you make the request?

zendevil.eth19:03:16

I get this:

actual: java.lang.NullPointerException: Cannot invoke "clojure.lang.IFn.invoke(Object, Object, Object)" because "this.handle_error" is null
 at ring.middleware.format_params$wrap_format_params$fn__28345.invoke (format_params.clj:115)
    reitit.ring$ring_handler$fn__23796.invoke (ring.cljc:329)
    clojure.lang.AFn.applyToHelper (AFn.java:154)
    clojure.lang.AFn.applyTo (AFn.java:144)
    clojure.lang.AFunction$1.doInvoke (AFunction.java:31)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    peridot.core$request.invokeStatic (core.clj:18)
    peridot.core$request.doInvoke (core.clj:12)
    clojure.lang.RestFn.invoke (RestFn.java:521)
    helpers.helpers$register_user.invokeStatic (helpers.clj:145)
    helpers.helpers$register_user.invoke (helpers.clj:143)
    unit.login_test$fn__33611.invokeStatic (login_test.clj:12)
    unit.login_test/fn (login_test.clj:11)
    clojure.test$test_var$fn__9761.invoke (test.clj:717)
    clojure.test$test_var.invokeStatic (test.clj:717)
    clojure.test$test_var.invoke (test.clj:708)
    clojure.test$test_vars$fn__9787$fn__9792.invoke (test.clj:735)
    helpers.fixtures$with_db$fn__33049.invoke (fixtures.clj:82)
    clojure.core$with_redefs_fn.invokeStatic (core.clj:7516)
    clojure.core$with_redefs_fn.invoke (core.clj:7500)
    helpers.fixtures$with_db.invokeStatic (fixtures.clj:29)
    helpers.fixtures$with_db.invoke (fixtures.clj:23)
    clojure.test$compose_fixtures$fn__9755$fn__9756.invoke (test.clj:694)
    clojure.test$default_fixture.invokeStatic (test.clj:687)
    clojure.test$default_fixture.invoke (test.clj:683)
    clojure.test$compose_fixtures$fn__9755.invoke (test.clj:694)
    clojure.test$test_vars$fn__9787.invoke (test.clj:735)
    clojure.test$default_fixture.invokeStatic (test.clj:687)
    clojure.test$default_fixture.invoke (test.clj:683)
    clojure.test$test_vars.invokeStatic (test.clj:731)
    clojure.test$test_all_vars.invokeStatic (test.clj:737)
    clojure.test$test_ns.invokeStatic (test.clj:758)
    clojure.test$test_ns.invoke (test.clj:743)
    clojure.core$map$fn__5884.invoke (core.clj:2759)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:51)
    clojure.lang.Cons.next (Cons.java:39)
    clojure.lang.RT.boundedLength (RT.java:1793)
    clojure.lang.RestFn.applyTo (RestFn.java:130)
    clojure.core$apply.invokeStatic (core.clj:669)
    clojure.test$run_tests.invokeStatic (test.clj:768)
    clojure.test$run_tests.doInvoke (test.clj:768)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.test$run_tests.invokeStatic (test.clj:773)
    clojure.test$run_tests.invoke (test.clj:768)
    unit.login_test$eval33664.invokeStatic (login_test.clj:50)
    unit.login_test$eval33664.invoke (login_test.clj:50)
    clojure.lang.Compiler.eval (Compiler.java:7181)
    clojure.lang.Compiler.load (Compiler.java:7640)
    user$eval33597.invokeStatic (form-init15147153642663810079.clj:1)
    user$eval33597.invoke (form-init15147153642663810079.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:7181)
    clojure.lang.Compiler.eval (Compiler.java:7136)
    clojure.core$eval.invokeStatic (core.clj:3202)
    clojure.core$eval.invoke (core.clj:3198)
    nrepl.middleware.interruptible_eval$evaluate$fn__31851$fn__31852.invoke (interruptible_eval.clj:87)
    clojure.lang.AFn.applyToHelper (AFn.java:152)
    clojure.lang.AFn.applyTo (AFn.java:144)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$with_bindings_STAR_.invokeStatic (core.clj:1977)
    clojure.core$with_bindings_STAR_.doInvoke (core.clj:1977)
    clojure.lang.RestFn.invoke (RestFn.java:425)
    nrepl.middleware.interruptible_eval$evaluate$fn__31851.invoke (interruptible_eval.clj:87)
    clojure.main$repl$read_eval_print__9110$fn__9113.invoke (main.clj:437)
    clojure.main$repl$read_eval_print__9110.invoke (main.clj:437)
    clojure.main$repl$fn__9119.invoke (main.clj:458)
    clojure.main$repl.invokeStatic (main.clj:458)
    clojure.main$repl.doInvoke (main.clj:368)
    clojure.lang.RestFn.invoke (RestFn.java:1523)
    nrepl.middleware.interruptible_eval$evaluate.invokeStatic (interruptible_eval.clj:84)
    nrepl.middleware.interruptible_eval$evaluate.invoke (interruptible_eval.clj:56)
    nrepl.middleware.interruptible_eval$interruptible_eval$fn__31882$fn__31886.invoke (interruptible_eval.clj:152)
    clojure.lang.AFn.run (AFn.java:22)
    nrepl.middleware.session$session_exec$main_loop__31950$fn__31954.invoke (session.clj:202)
    nrepl.middleware.session$session_exec$main_loop__31950.invoke (session.clj:201)
    clojure.lang.AFn.run (AFn.java:22)
    java.lang.Thread.run (Thread.java:833)

hiredman19:03:12

that looks like exception happening while looking for an error handle, which doesn't tell you what caused it to look for an error handler

hiredman19:03:16

oh, you aren't actually making a request, you are just passing the data to the function in a test, and passing a string where it wants an inputstream (would be my guess)

zendevil.eth19:03:41

it’s a request

zendevil.eth19:03:53

(-> session
      (request "/api/reset-password"
               :content-type "application/json"
               :request-method :post
               :body (cc/generate-string
                      {:email email
                                    :newPassword newPassword
                                    :resetToken token}
                      )))

hiredman19:03:10

what is 'request'

hiredman19:03:19

and what does the peridot docs say about :body

hiredman19:03:50

it doesn't look like it does anything to body

hiredman19:03:01

so it doesn't turn body into an inputstream

hiredman19:03:49

the ring spec says :body is an inputstream

hiredman19:03:23

so the metosin whatever, if the body is present, treats it as an inputstream and tries to decode it

hiredman19:03:22

I mean, I don't know, if I were you the thing to do is figure out how to set whatever error handler retit wants so that you can display the error that happens, instead of getting a stacktrace that just tells you there was an error trying to call the error handler

hiredman19:03:38

this explains why the example app doesn't get the error

hiredman19:03:18

it doesn't have a :body, it passes in :body-params, so the stuff doesn't look for an inputstream in :body to decode from

zendevil.eth19:03:49

the exception only happens with wrap-format-parasm

zendevil.eth19:03:54

without it I get:

zendevil.eth19:03:04

{:spec
             "(spec-tools.core/spec {:spec (clojure.spec.alpha/keys :req-un [:lms.auth.spec/resetToken :lms.auth.spec/newPassword :lms.auth.spec/email]), :type :map, :leaf? false})",
             :problems
             [{:path [],
               :pred "clojure.core/map?",
               :val nil,
               :via [:lms.auth.spec/reset-password-params],
               :in []}],
             :type :reitit.coercion/request-coercion,
             :coercion :spec,
             :value nil,
             :in [:request :body-params]}

zendevil.eth19:03:23

notice :value nil in :request :body-params

zendevil.eth19:03:06

there’s gotta be a middleware that converts body to body-params

zendevil.eth19:03:31

I tried wrap-format-params but that gave the exception

hiredman19:03:17

I believe the m* whatever stuff does it, but I dunno that I want to spend my time digging through that, so you'll need to dig through it, it may still be the fact that you are passing in a string and not an inputstream