Fork me on GitHub
#beginners
<
2021-08-06
>
Christian11:08:15

Hi, Im working on a http request that need to be have the following query parameters.  ?where=customerId="aa238c96-189c-4740-a881-8d16dbc51001" and that needs to be url encoded into this ?where=customerId%3D%22aa238c96-189c-4740-a881-8d16dbc51001%22 but I´m not able to figure it out.  Using Hato as http client library. Suggestions?

delaguardo11:08:54

(hc/get "" {:query-params {"where" "customerId=\"aa238c96-189c-4740-a881-8d16dbc51001\""}}) did you tried this? sent request contains :query-string "where=customerId%3D%22aa238c96-189c-4740-a881-8d16dbc51001%22"

👍 3
PB15:08:50

I know it's application specific, but what flags do y'all usually set when running a clojure app in production?

ghadi15:08:17

@petr are you running in containers or something else?

PB15:08:36

Yes, in containers

ghadi15:08:11

what sort of information are you looking for?

ghadi15:08:14

I would make sure you have the correct garbage collector for your needs: G1 (default), parallel (throughput), or ZGC

ghadi15:08:35

if you're in containers, prefer using MaxRamPercentage rather than absolute Xmx memory settings

PB15:08:00

We are using kube, so the ram available to the container is already limited, so not setting xmx. The garbage collection flag is one I hadn't thought of. I was thinking about stuff like whether the default heap settings are adequate, etc

ghadi15:08:16

java respects cgroups, fyi it will not use all the available cgroup memory for heap

ghadi15:08:22

(not that you'd want that anyways)

PB15:08:34

Awesome. That's good to know!

PB16:08:29

Thank you

noisesmith18:08:18

> the ram available to the container is already limited, so not setting xmx xmx has a default value, it does not default to "all the memory on this machine", so you need to use the flag to ensure all the memory you provide is used

noisesmith18:08:26

oh I guess ghadi already said that

jumar04:08:56

Yeah, the typical default for max heap is 1/4 of available memory - both in containers and host OS. Other than that I'd avoid tweaking other settings, at least iniitally. You may find other flags useful to have debugging info available when a problem happens, e.g. • -XX:+HeapDumpOnOutOfMemoryError-XX:-OmitStackTraceInFastThrow

Yosevu Kilonzo17:08:33

Hello, can test.check be used with ClojureScript?

indy17:08:51

Haven't used it with CLJS personally though

dev-hartmann17:08:28

Quick question: if I want to read a file from the users home dir, a Config file like a .zshrc, how do I get clojure to find that dir?

seancorfield17:08:49

@dev-hartmann (System/getProperty "user.home")

dev-hartmann17:08:21

@seancorfield thanks, will try that!

seancorfield17:08:38

There are several properties that are useful: you can get a hash map of all of them with (System/getProperties):

dev=> (-> (System/getProperties) (keys) (sort))
("clojure.basis" "clojure.core.async.go-checking" "clojure.tools.logging.factory" "file.encoding" "file.separator" "ftp.nonProxyHosts" "http.nonProxyHosts" "java.class.path" "java.class.version" "java.home" "java.io.tmpdir" "java.library.path" "java.protocol.handler.pkgs" "java.runtime.name" "java.runtime.version" "java.specification.name" "java.specification.vendor" "java.specification.version" "java.vendor" "java.vendor.url" "java.vendor.url.bug" "java.vendor.version" "java.version" "java.version.date" "java.vm.compressedOopsMode" "" "java.vm.name" "java.vm.specification.name" "java.vm.specification.vendor" "java.vm.specification.version" "java.vm.vendor" "java.vm.version" "javafx.runtime.version" "javafx.version" "jdk.debug" "line.separator" "log4j2.configurationFile" "logged-future" "os.arch" "os.name" "os.version" "path.separator" "socksNonProxyHosts" "sun.arch.data.model" "sun.boot.library.path" "sun.cpu.endian" "sun.font.fontmanager" "sun.io.unicode.encoding" "sun.java.command" "sun.java.launcher" "sun.jnu.encoding" "sun.management.compiler" "user.country" "user.dir" "user.home" "user.language" "user.name" "user.timezone" "vlaaad.reveal.prefs")
That's in our dev setup so some of those are set by us at startup of the REPL but most of them are standard/built-in for Java itself.

dev-hartmann17:08:05

Ah, that’s really useful, thx for the info! My Java knowledge is somewhat lacking

quoll18:08:23

If this is the case, then you may want to know about the File type in Java, since this gives you portable access to a file you want to open. The Clojure approach for talking to files on the JVM is in the namespace. You can then create a File object with , which can be used as the argument for opening a file, or just sending to the slurp function. e.g.

(require '[ :as io])

(slurp (io/file (System/getProperty "user.home") ".zshrc"))

quoll18:08:49

The file function is useful here, because you give it the directory as the first arg, and the filename as the second without doing any string manipulation to build a path

dev-hartmann06:08:42

@U051N6TTC thank you very much, that’s the approach I endend up taking 👌:skin-tone-4:

dev-hartmann14:08:57

thanks again @U051N6TTC ended up using exactly this to read and create my applications config file!

👍 2
popeye18:08:13

Team, I was searching in a internet, I am trying to find good resource to learn and become expert in clojure macros, Can anyone help me with link please

indy18:08:01

1. Understanding the Clojure evaluation model. https://www.braveclojure.com/read-and-eval/ 2. Awing at their beauty and power. 3. Awing at the fact that Clojure (and other lisps for that matter) have only a handful of special forms and everything else is defined as a macro. 4. Macroexpanding a ton. 5. Understanding the use of quote, syntax-quote, unquote-splice, gensym. 6. Properly understanding that their use is when you want to transform the source code before evaluation. https://www.braveclojure.com/writing-macros/ 7. Finding the right use case for a macro, and checking if the macro emits the source that you expect by constantly macroexpanding your macro from the REPL. 8. Developing a sense for when to use them.

deleted18:08:23

I own it but have never read it 😅

quoll18:08:53

same! :rolling_on_the_floor_laughing:

😂 3
quoll18:08:02

Well, I did browse it a little

quoll18:08:00

But I felt comfortable with creating macros after reading the relevant parts of “The Joy of Clojure”

popeye18:08:30

This book I have not read yet, let me!

adi18:08:01

> I own it but have never read it Symmetric with my macrology. I read them, but never write them :grinning_face_with_one_large_and_one_small_eye:

quoll18:08:27

I’d written macros before, but The Joy of Clojure really solidified how to do it (and more importantly, how to avoid using them). The most important parts of macro authorship are: • Avoiding writing macros • When you DO write a macro, you should usually minimize the work in the macro and write helper functions • Understanding quoting and unquoting

💯 3
quoll18:08:23

I started out by reading “Programming Clojure” by Stu Halloway (back when the 1st edition was current). After that I believe that I was a competent Clojurista, but I often felt like I wasn’t necessarily being idiomatic in the language. Then I read The Joy of Clojure in 2011, and I finally felt like I got the language

hiredman18:08:31

I think some experience with formal systems / symbolic logic (so something like godel escher bach) and the notion of logics and metalogics helps a lot

adi18:08:11

> The most important parts of macro authorship are: > ... + to all of quoll's points, with small additions: clojure.walk/macroexpand-all is a good friend. I like to run it ever time I use a new macro.

user=> (clojure.walk/macroexpand-all '(or (even? 3) (even? 42)))

(let* [or__5516__auto__ (even? 3)] (if or__5516__auto__ or__5516__auto__ (even? 42)))
Plus, definitely re-write macros you see in the wild, and play with syntax quoting rules to see the changing effect (e.g. the or macro featured above). Fiddle and macroexpand... it will help improve intuitions about how macros work in Clojure.

quoll18:08:39

I macroexpand all the time. It’s especially useful when you’re trying to explain things to people. Like, how do the threading macros work? How does destructuring work? etc

3
adi18:08:02

"Macros are also just functions of data -> to -> data, except they run at compile-time." ... It took me a good while to properly grok this concept.

dpsutton18:08:01

I do wish macroexpansion would expand to bad forms rather than throw spec errors when you are diagnosing bad forms

dpsutton18:08:57

Like if it expanded to (let [single] body) it would show that expansion rather than spec error out

indy18:08:28

@U11BV7MTK I guess let is a special case since it tries to macroexpand let to let* . The following doesn't throw,

(macroexpand-1 '(let* [8]))

seancorfield18:08:57

@UMPJRJU9E Yeah, several of Clojure's "Special Forms" are implemented as macros that expand to the actual, underlying special form. Like fn is a macro implemented on top of fn*, in addition to let, etc.

seancorfield18:08:50

(there was a thread some time back where a new Clojure developer was very surprised that some things listed as Special Forms were actually Clojure macros that expanded to mostly undocumented stuff)

indy18:08:01

1. Understanding the Clojure evaluation model. https://www.braveclojure.com/read-and-eval/ 2. Awing at their beauty and power. 3. Awing at the fact that Clojure (and other lisps for that matter) have only a handful of special forms and everything else is defined as a macro. 4. Macroexpanding a ton. 5. Understanding the use of quote, syntax-quote, unquote-splice, gensym. 6. Properly understanding that their use is when you want to transform the source code before evaluation. https://www.braveclojure.com/writing-macros/ 7. Finding the right use case for a macro, and checking if the macro emits the source that you expect by constantly macroexpanding your macro from the REPL. 8. Developing a sense for when to use them.

noisesmith18:08:08

IMHO you only need to think about macros as an absolute beginner or a highly specialized expert, in between things go best if you don't make new macros

3
3
noisesmith18:08:55

or maybe that's just resentment from having to deal with APIs that force the usage of macros

Franco Gasperino18:08:53

My first frustration to your point was go blocks and function composition.

Akiz19:08:32

Hi, I have got a coll of functions as:

(#function[clojure.core/inc]
 #function[clojure.core/dec])
Now I would like to map it on coll containing colls of same length as:
[[5 5] [6 6] [7 7]]
result should be (lazily): [[6 4] [7 5] [8 6]] Is there some function for this?

quoll19:08:14

(map (fn [p] (map #(%1 %2) fn-coll p)) number-colls)

quoll19:08:51

The first thing I thought of was juxt but that applies everything to the same value. But since you’re going down seqs together, applying the first to the second, then that sounded like using map with 2 seqs

indy19:08:13

(def fns [inc dec])
 
 (for [[fst snd] [[5 5] [6 6] [7 7]]]
   [((first fns) fst)
    ((second fns) snd)])

noisesmith21:08:44

a suggestion from the peanut gallery:

user=> (for [[fst snd] [[5 5] [6 6] [7 7]]
                  :let [[f g] fns]]
              [(f fst) (g snd)])
([6 4] [7 5] [8 6])

🥜 3
indy04:08:51

Yup yup, I’d definitely introduce a let to make it more readable. Was in a hurry here I guess

quoll19:08:23

(oh, also, you can use mapv instead of map to get the requested vector results)

Akiz19:08:13

Thanks, works like a charm

quoll19:08:30

Since your values are the same number repeated (ie. [5 5] ) then juxt would work on a seq of just [5 6 7] As in: (map (apply juxt fn-coll) [5 6 7]) But that’s just extrapolating from your example, rather than what you asked for

👏 3
Akiz20:08:18

Yeah, it was just example - not really good one 🙂. I will use this one (map (fn [p] (map #(%1 %2) fn-coll p)) number-colls)

quoll20:08:40

Just 2 comments then: 1. as I noted, you can use mapv rather than map if vectors matter to you. I don’t usually bother unless there’s need for it. 2. I called the argument p to mean “pair”, but it may make sense to change it, particularly since it’s written to take a function seq (along with argument seq) of arbitrary length

Akiz06:08:30

Yeah, I get the code. I was just hoping that there is some “native” function for that.. something like zipmap but for functions and values 🙂

varun21:08:51

Hey all i'm using the luminus template and im working through Web Development with Clojure and I'm trying to access the basic index route of the app at / (by going to localhost:3000) and i get a null pointer exception with not much to go off of. Any ideas on how I might begin to debug?

user=> Fri Aug 06 23:40:51 CEST 2021 [worker-1] ERROR - GET /
java.lang.NullPointerException
	at org.httpkit.server.HttpHandler.run(RingHandler.java:117)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:830)

seancorfield21:08:59

@varun.jayaraman How did you create your project and have you changed the code since creating the project? i.e., does a brand new generated project not work, or do you only get this error after making changes?

seancorfield21:08:04

(a common "gotcha" is folks adding a println to their handler, making it return nil instead of a Ring response)

varun21:08:10

yeah i made a couple of changes, but ive followed the book until page 21 (not sure if you also have the book yourself). but basically ive modified routes/home.clj to look like this:

(ns guestbook.routes.home
  (:require
   [guestbook.layout :as layout]
   [guestbook.db.core :as db]
   [ :as io]
   [guestbook.middleware :as middleware]
   [ring.util.response]
   [ring.util.http-response :as response]))

(defn home-page [request]
  (layout/render 
    request "home.html"))

(defn save-message! [{:keys [params]}]
  (db/save-message! params)
  (response/found "/"))

(defn about-page [request]
  (layout/render request "about.html"))

(defn home-routes []
  [""
   {:middleware [middleware/wrap-csrf
                 middleware/wrap-formats]}
   ["/" {:get home-page}]
   ["/about" {:get about-page}]
   ["/message" {:post save-message!}]])
And home.html looks like this:
{% extends "base.html" %}
{% block content %}
<div class="content">
  <div class="columns is-centered">
    <div class="column is-two-thirds">
      <!-- Content -->
    </div>
  </div>
</div>
{% endblock %}

varun21:08:50

i thought it might have something to do with a typo in my selmer template but i cant seem to see anything. and the route itself at / is dead simple, I can't imagine what is throwing the null pointer exception there. Unfortunately i'm quite a noob and am not sure how to even begin debugging this

varun21:08:53

i was wondering if maybe i could replace home.html with just rendering a simple string and seeing if it works, so something like:

(defn home-page [request]
  (layout/render 
    request "<html><body><p>hi</p></body></html>"))
But layout/render takes a filename that it automatically looks up in the resources folder i think, so that wont work 😕

varun21:08:28

oh sorry @seancorfield i created the project with lein new luminus guestbook --template-version 3.91 -- +h2 +http-kit

seancorfield21:08:55

Yeah, I just dug the book out to take a look. There's a lot of moving parts between running that and page 21 🙂

varun21:08:56

ill try a brand new project and see if it works

varun21:08:32

hmm a brand new one does work :thinking_face:

seancorfield21:08:33

A suggestion: if you git init after first creating the template and then add and commit each step along the way, you'll have an easier time reverting to a working version and also you'll have the specific diffs showing the changes you made between a working version and a non-working version.

varun21:08:50

yeah true. i probably should have initialized it as a git project from the beginning

varun21:08:21

i must have fudged a file somewhere by accident

seancorfield21:08:41

(I generally recommend Clojure beginners start with just Ring and Compojure (or reitit) to learn the basics of web dev before attempting to use Luminus -- it's very complicated for a new-to-Clojure developer)

varun21:08:17

would you recommend it to someone who is an experienced web dev but just new to clojure?

varun21:08:22

(it being luminus)

seancorfield21:08:46

No, if you're new-to-Clojure, regardless of background, start with something much simpler than the Luminus template.

5
varun21:08:04

hmm i see. ok

seancorfield21:08:26

I see so many beginners stumble with Luminus. It's fine until something goes wrong but then there are so many libraries involved and so much going on that debugging an error is really tricky 😕

11
Darrell21:08:47

I’m an experienced web dev who has been learning Clojure for about the last 1.5 years (on and off) and I’ve found Ring and Compojure by itself to be pretty straightforward.

Darrell21:08:14

So @seancorfield’s advice is sound. Not that there was any questioning that fact. 😉

seancorfield22:08:34

To put it in perspective, that Luminus project (created via that command-line) has all these libraries in play:

:dependencies [[ch.qos.logback/logback-classic "1.2.3"]
                 [cheshire "5.10.0"]
                 [clojure.java-time "0.3.2"]
                 [com.h2database/h2 "1.4.200"]
                 [conman "0.9.1"]
                 [cprop "0.1.17"]
                 [expound "0.8.7"]
                 [funcool/struct "1.4.0"]
                 [luminus-http-kit "0.1.9"]
                 [luminus-migrations "0.7.1"]
                 [luminus-transit "0.1.2"]
                 [luminus/ring-ttl-session "0.3.3"]
                 [markdown-clj "1.10.5"]
                 [metosin/muuntaja "0.6.7"]
                 [metosin/reitit "0.5.10"]
                 [metosin/ring-http-response "0.9.1"]
                 [mount "0.1.16"]
                 [nrepl "0.8.3"]
                 [org.clojure/clojure "1.10.1"]
                 [org.clojure/tools.cli "1.0.194"]
                 [org.clojure/tools.logging "1.1.0"]
                 [org.webjars.npm/bulma "0.9.1"]
                 [org.webjars.npm/material-icons "0.3.1"]
                 [org.webjars/webjars-locator "0.40"]
                 [ring-webjars "0.2.0"]
                 [ring/ring-core "1.8.2"]
                 [ring/ring-defaults "0.3.2"]
                 [selmer "1.12.31"]]
compared to what you get with lein new compojure webapp:
:dependencies [[org.clojure/clojure "1.10.0"]
                 [compojure "1.6.1"]
                 [ring/ring-defaults "0.3.2"]]

varun22:08:02

makes sense

seancorfield22:08:19

(and I also really dislike Mount and some of the other choices Luminus makes -- I especially don't think they are good choices for beginners)

seancorfield22:08:25

I ought to take a look at Coast some time. I sort of deliberately stay away from "framework-y" things in Clojure...

varun22:08:18

i used to be against frameworky things after rails but after using phoenix in the elixir world, i think i'm less dogmatic

varun22:08:48

but i'll go back to basics and maybe only touch luminus once i understand how to debug a bit more in clojure

seancorfield22:08:52

I think it's telling that Pragmatic rate this book as intermediate-expert:

seancorfield22:08:28

@varun.jayaraman Don't feel disheartened about tripping up with Luminus -- that happens to pretty much everyone who is trying to learn Clojure from that book I think. A lot of people suggest Getting Clojure as a really good book to learn Clojure from.

seancorfield22:08:38

It uses Pedestal -- how approachable is that for a beginner?

:deps    {com.github.seancorfield/next.jdbc {:mvn/version "1.2.674"}
           hiccup/hiccup                     {:mvn/version "2.0.0-alpha2"}
           io.pedestal/pedestal.jetty        {:mvn/version "0.5.9"}
           io.pedestal/pedestal.service      {:mvn/version "0.5.9"}
           org.clojure/clojure               {:mvn/version "1.10.3"}
           org.postgresql/postgresql         {:mvn/version "42.2.23"}}
(I looked at Pedestal when Cognitect first released it and thought it was pretty complex -- but there was next to no documentation for it back then either)

varun22:08:29

alright i do have Getting Clojure , maybe i'll work through that first

varun22:08:14

i think i was getting impatient and just wanted to build something with clojure so i reached for the web dev book

seancorfield22:08:50

If it helps, here's a simple web app example I put together: https://github.com/seancorfield/usermanager-example and the README links to a variant created by @admin055 that swaps out Compojure and Component for Reitit and Integrant so it's good to compare the two.

👍 3
varun22:08:08

awesome, thanks ill bookmark it

varun22:08:20

how does leiningen know about these different templates by the way? are they hardcoded into lein?

varun22:08:26

i.e. luminus, compojure-app, etc

seancorfield22:08:51

It searches http://clojars.org for <template-name>/lein-template

varun22:08:54

or does it hit some remote repository of registered templates

seancorfield22:08:53

clj-new for the Clojure CLI/`deps.edn` looks for <template-name>/clj-template but also supports Leiningen templates (but the latter mostly generate Leiningen-based projects).

seancorfield22:08:09

(there also a few simple templates built into both tools: app, lib, and plugin I think for Leiningen? It's template for clj-new -- and clj-new also has polylith built-in)