Fork me on GitHub
#beginners
<
2018-09-05
>
Cheese Cake Aficionado00:09:58

@troglotit what font is that if you don't mind my asking?

Cheese Cake Aficionado03:09:35

Could anyone recommend a web framework like Flask for me? It just needs to be able to do very basic routing and be easy to use.

seancorfield03:09:51

@sasha504 Compojure (and Ring) would probably do what you need. With Selmer or Hiccup for generating web pages.

seancorfield03:09:48

(Clojure doesn't really have "web frameworks" for the most part -- there's a strong preference for composing libraries instead)

deliciousowl03:09:03

I use Luminus for web, and also saw this somewhere recently: https://github.com/coast-framework/coast

Cheese Cake Aficionado03:09:28

I don’t need any rails or Django-esque features. I want to be able to link a function to a path, and be able to read the post data.

deliciousowl03:09:29

then what I linked is definitely overkill

Cheese Cake Aficionado03:09:08

Is there a nice library like requests to quickly make http requests you would recommend?

deliciousowl03:09:41

you can use [http-kit "2.1.16"] which is already in the compojure example* mentioned above I think

seancorfield03:09:01

A +1 for clj-http. I didn't know http-kit could be a client as well as a server @coinedtalk?

seancorfield03:09:09

I guess I need to read the docs better 🙂

seancorfield04:09:29

Ah, I see, it's an async client library as well as a great server. I'll have to play with that 🙂

henrik04:09:24

I’ve been using http-kit with Ions. As a client when deployed, and as a server in dev.

henrik04:09:05

Not sure if it’s the best choice, but certainly convenient.

seancorfield04:09:32

I like clj-http's built-in JSON handling but I guess that can be handled with http-kit with a call back (that populates the promise).

henrik04:09:35

Yeah, I had to attach some JSON conversion to it. That’s a nice aspect of clj-http.

Saikyun06:09:36

how do I diff a map? clojure.data.diff seems to care about the order of the collections

mihir06:09:59

Make the collections a set.

mihir06:09:00

Then diff

mihir06:09:36

As long as the collections are of the type LazySeq or Vector the order will matter. If the collections are #{} then it will be fine.

Saikyun06:09:23

but my collections are maps, not sets 😞

Saikyun06:09:31

I wan't to go deep and diff every element in a map

Saikyun06:09:38

I also have maps in my maps, so I'm guessing some recursing thingy would be good, but I was just curious if one exists in clojure or if I have to write it myself

andy.fingerhut08:09:32

Do you have an example where clojure.data.diff seems to care about the order of key/value pairs in a map? I didn't think that it did.

Saikyun08:09:55

@andy.fingerhut I also didn't think so! it's kind of funny because this explains some odd behaviour I have in another project. here's an example:

(use 'clojure.data)
(def a {:a 10 :b 20})
(diff a (reverse a))
;; [{:a 10, :b 20} ([:b 20] [:a 10]) nil]

decim08:09:01

Can someone tell me what’s wrong with my project.clj file. My project isn’t picking up on figwheel https://gist.github.com/titaniumbrella/6fc89a42acece7d2a95ae5b5d0c7fd89

Saikyun08:09:41

or wait, sorry @andy.fingerhut I now saw that reverse turned it into a seq, wait a minute

Saikyun08:09:33

nvm @andy.fingerhut, you're absolutely correct. I must be doing something else wrong

kautsig08:09:10

hey, i'm currently trying to consume a rest service from clojure which provides a swagger spec. is there any library to assist with that? i'm thinking of generating client methods, records or similar. all the things i can find are about providing rest services, not consuming them. i'd appreciate a pointer...

kautsig08:09:22

or maybe the question also makes no sense, because a clojure solution would follow a totally different approach

kautsig09:09:40

at first glance this looks pretty much like what i was looking for! will give it a try, thx @U054W022G

ikitommi10:09:41

there is also swagger-codegen, which generates clients to multiple languages. js & java are supported, clojure not directly.

kautsig12:09:32

clojure in fact is supported, i tried that...

kautsig12:09:56

but it seems abandoned

kautsig12:09:22

or maybe it just works, so there are no commits needed 🙂

ikitommi12:09:45

oh, it is. Hope someone would have time for fixing/maintaining that.

ikitommi12:09:12

also, server-gens for clojure would be great

kautsig12:09:38

server-gens?

Meyer10:09:51

hello all,

Meyer10:09:14

and i got error on the last test

Meyer10:09:32

(= [:map :set :vector :list] (map __ [{} #{} [] ()]))

Meyer10:09:12

sorry, not an error but my code failed above test

Meyer10:09:28

all test passed when i test on repl

stardiviner10:09:29

Can somebody tell me how to use this function? https://github.com/gfredericks/org-editor/blob/master/src/com/gfredericks/org_editor.clj#L53 I can't understand how to use it (especially the writer parameter)

henrik10:09:37

@stardiviner Do you specifically want to deal with streams? If you just need to put some data on disk, spit is easier to deal with.

henrik10:09:28

Otherwise, you’ll have to pass in a writer: https://clojuredocs.org/clojure.java.io/writer

stardiviner11:09:17

@henrik I'm using this library org-editor which is written by others. I'm confused how to use this function write-file about what parameter to pass to it? Usually I will will think (org-editor/write-file <data> ""). But the first argument is writer. In the source code definition, I'm confused where is the data passed in?

Ramzi15:09:04

How come when I call (list) on something I'm getting a LazySeq back?

noisesmith15:09:10

that makes it sounds like you are calling list on a single item?

Ramzi15:09:35

When I go to a rest endpoint, I see lots of data like [][][][][][]

Ramzi15:09:46

I wanted to turn that into a seq. So I tried seq and list.

noisesmith15:09:02

list only returns clojure.lang.List, it wraps the items you pass in into a new list

Ramzi15:09:08

Now when I do an alert for k in n, I get two alerts. The first alert says LazySeq, and the second alert says (nill)

noisesmith15:09:30

Clojure 1.9.0
(ins)user=> (def a [1 2])
#'user/a
(ins)user=> a
[1 2]
(ins)user=> (list a)
([1 2])

Ramzi15:09:58

(list (select-all-from table-name)) is returning a LazySeq

noisesmith15:09:04

no, it isn't

Ramzi15:09:47

(GET "/database" [] (get-database-info "asdf"))

noisesmith15:09:53

that is what you get if someone calls str on a lazy seq

noisesmith15:09:06

if you want to see the contents, call pr-str instead of str

Ramzi15:09:26

Okay, what about my two alerts problem

noisesmith15:09:42

calling seq on a lazy-seq just gives you the lazy-seq back again, calling list on it just puts it inside a new list

Ramzi15:09:44

I want an alert for every k in n, but I am getting two alerts where the first alert has everything and the second alert has nil

noisesmith15:09:05

then you have two items, one is a collection and the other is nil?

Ramzi15:09:48

i dont know why. i just wanted the one list or seq that i get back from my end point

noisesmith15:09:53

alternatively, if you use vec instead of list or seq, it will turn it into a vector and those do str nicer than lazy-seq

noisesmith15:09:20

ins)user=> (def lazy (take 10 (iterate inc 0)))
#'user/lazy
(ins)user=> (str lazy)
"[email protected]"
(ins)user=> (pr-str lazy)
"(0 1 2 3 4 5 6 7 8 9)"
(ins)user=> (str (vec lazy))
"[0 1 2 3 4 5 6 7 8 9]"
(ins)user=> (pr-str (vec lazy))
"[0 1 2 3 4 5 6 7 8 9]"

Ramzi15:09:56

Now it looks like every character of what I get back is being looped over.

noisesmith15:09:58

so it's a back end error, they are sending you the string of a lazy-seq (which is useless) instead of the contents

Ramzi15:09:19

The first alert looks like ({}{}{}) and the second is (nil)

john15:09:45

Try apply

noisesmith15:09:50

what? there are no characters there

noisesmith15:09:42

@its.ramzi when you have this level of confusion about what's going on, maybe try breaking the problem down into smaller parts. You can use type to find out what kind of data you are looking at, then pr-str to see a repl readable version (if possible), count to see the size, keys to see the keys of a hash, etc.

noisesmith15:09:22

also you can use def or swap! with an atom to make the data accessible in your cljs repl

noisesmith15:09:32

(which makes exploring the data easier)

Ramzi15:09:42

Alright I'll try that.

Ramzi15:09:59

I tried to do an alert with type and i didnt see anything

noisesmith15:09:48

what does the code that makes the alert look like?

Ramzi15:09:23

I just got: function String() { [native code] }

Ramzi15:09:31

(defn change-dom [content] (js/alert (type content)) )

noisesmith15:09:35

OK, that's not nothing, that's a type

noisesmith15:09:39

content is a function

Ramzi15:09:52

I thought content would have my data in it

noisesmith15:09:14

OK - it could be that is how the type of String prints

noisesmith15:09:25

(now that I look closer)

Ramzi15:09:51

so it's a String, not a collection

noisesmith15:09:53

So it's a string, I think. Which means iterating over it just gives you characters.

noisesmith15:09:22

if the content of the string contains clojure.lang.LazySeqblahblah in it, that's an error on your back end,

noisesmith15:09:51

you need to ensure the back end is generating the data properly, I suspect it should be json encoding

Ramzi15:09:42

Now I am getting three alerts. Please look at this code and tell me how I could possibly be getting three alerts.

Ramzi15:09:45

(defn make-table-from-string [n] (js/alert n) ) (defn change-dom [content] (js/alert (type content)) (-> js/document (.getElementById "some-div") (.-innerHTML) (set! (-> js/document (.getElementById "some-div") (.-value) (str "<h2>Hello</h2>" (make-table-from-string content)))))) (defn ajax-input [id endpoint] [:input {:id id :on-change #(.send goog.net.XhrIo endpoint (fn [event] (change-dom (make-table-from-string (.getResponseText(.-target event)))))) } ] )

dadair15:09:51

What does the browser network tab show for the request response from the GET /database call?

Ramzi16:09:10

({:id 1, :body "sdf", :created_at #inst "2018-08-31T18:02:00.922340000-00:00"} {:id 5, :body "asdf", :created_at #inst "2018-08-31T18:09:51.403570000-00:00"} {:id 7, :body "bye", :created_at #inst "2018-08-31T18:10:34.583642000-00:00"} {:id 9, :body "vv", :created_at #inst "2018-09-04T14:17:53.290623000-00:00"} {:id 8, :body "What should it say CHris? ", :created_at #inst "2018-08-31T18:11:44.118170000-00:00"})

Ramzi16:09:36

yay dadair is typing

dadair16:09:59

Well you have make-table-from-strong throwing an alert, and that is called from multiple places

Ramzi16:09:18

hmm, that does explain the 3. thanks.

dadair16:09:10

The argument to change-dom has a call to make-table-from-string, and then change-dom also has alert, and then it calls make-table-from-string again, which has alert...

Ramzi16:09:45

But I'm not getting: function String() { [native code] } anymore

dadair16:09:43

I don’t know where that’s from

Ramzi16:09:59

The first alert has all the data, the second alert has null, and the third alert has undefined.

Ramzi16:09:58

I would expect (js/alert (type content)) to show the String thing

dadair16:09:26

Walk through your code. You know you have 3 calls to alert because of how you’ve written the code. Under what conditions are the arguments to the alert those things? Is that correct? Is it what you expect? Should you even have 3 calls to alert? Is your code maybe incorrect?

dadair16:09:15

A very simple question to answer is: why are there three calls to make-table-from-string? Do you think it should be called multiple times?

dadair16:09:47

Why is it done as an argument to change-dom, and then called again inside change-dom?

Ramzi16:09:48

Let me just try removing make-table-from-string entirely

noisesmith16:09:20

also you can combine alerts with the kind of exploration I was describing above: (js/alert (str "type: " (type x) " x: " (pr-str x))) etc.

Ramzi16:09:56

All of my data is getting printed to a div.

Ramzi16:09:11

But it's coming in as one large chunk. I can't loop through it.

Ramzi16:09:26

So if "([] [] [])" is a string, how can I make that into the list i want

Ramzi16:09:45

or should i not be sending it from the server as a string

Ramzi16:09:48

but as a list

Ramzi16:09:56

that way the type should say list or vec

dadair16:09:33

It shouldn’t be a string, it should likely be JSON or EDN

Ramzi16:09:45

well it's definitely not those

dadair16:09:38

The very value of “([] [] [])” is a red flag to me that your backend code/query is likely wrong, but that’s another separate issue

dadair16:09:56

(You would have to make it be JSON or EDN)

Ramzi16:09:12

So, how do I go from the sql query to making the results JSON?

dadair16:09:38

Look into the Cheshire library

noisesmith16:09:45

usually the ring wrap-json middleware is used, and if your query sets the right content-type on the request it just works

deliciousowl16:09:11

I'm using luminus queries.sql file, anyone know what's wrong with this query? SELECT * FROM USERS WHERE ip = (:ip)

deliciousowl16:09:14

updating the ip field works using the same syntax which i think is weird, but when I do this it just gets all of them indiscriminately

dadair16:09:08

@coinedtalk don’t wrap :id with parens

deliciousowl16:09:43

doesn't make a difference

dadair16:09:33

Are you sure the change propagated through? Not sure how luminous works, but depending on how the queries.sql file is loaded changes only within that file may not result in those changes being loaded

dadair16:09:30

Eg., in my own app I need to touch the clj file that includes the sql file for sql changes to be reflected (if I’m resetting the app through the repl)

dadair16:09:59

Safest bet for a sanity check is full restart of the application (down the whole repl)

deliciousowl16:09:28

Yep, you are spot on. I'm having trouble with the DB overall it seems. (migrate) usually doesn't work, and (rollback) entirely breaks the app. I have to close all of it, migrate, and then restart to use it. Thanks

dadair16:09:13

Glad to see it resolved. If you don’t have many migrations, I’d be happy to see if I can tell why they are failing. Send me a DM if you’re interested.

dadair16:09:54

How are you calling that query function? What’s the value of :ip?

deliciousowl16:09:17

(db/save-message! (assoc params :ip (:remote-addr req)))

(defn home-page [{:keys [params] :as req}]
  (layout/render
    "home.html"
      (merge {:messages (db/get-messages (assoc params :ip (:remote-addr req)))}
             (select-keys (:flash req) [:id :errors]))))

deliciousowl16:09:07

its supposed to show only messages (users) for that ip, instead it shows them all (but ip, id, and message data are all successfully read/passed)

deliciousowl16:09:45

:ip is localhost but I added a "user" manually to the DB which has a different one to try and filter it out

ralf16:09:53

Does clojurians have a mentorship program?

ralf17:09:15

Looks intriguing but I'm looking for a partner who is above my skill level to discuss my solutions

seancorfield17:09:45

@gold88 Not a specific one, no, but folks in this channel sometimes step up and volunteer for 1:1 stuff.

seancorfield17:09:22

You're in Europe somewhere, based on your TZ? When are you most likely to be trying to learn Clojure -- your day or your evenings?

ralf17:09:52

Right now I'm working a JavaScript job during the day, so my clojure sessions are mostly in the evening

seancorfield17:09:11

OK, well, I don't might having a couple of people on my 'Starred' list in Slack for DMs about learning Clojure -- and I've got enough bandwidth for one more if you want?

seancorfield17:09:39

I'm based in California so it's almost 11am for me right now -- your evenings would be my mornings.

ralf18:09:17

I'd be more than happy to take that spot @seancorfield thanks for the offer :)

johnj19:09:30

would having a ns called main.clj cause trouble?

noisesmith19:09:28

do you mean file or ns? either way is fine, but it's good practice to be precise

johnj19:09:37

@noisesmith both, ex: src/blog/main.clj is blog.main

johnj19:09:11

by precise you mean in the naming?

noisesmith19:09:20

the .clj is not part of the ns, it's part of the file name

noisesmith19:09:36

you could have an ns called main.clj, the file would be eg. src/main/clj.clj

noisesmith19:09:42

which would be weird, but it would work

noisesmith19:09:16

so the real answer is no, there is no problem with using that name

noisesmith19:09:26

with a side note about the difference between file name and ns name

johnj19:09:32

yeah, that is what meant, my file is main.clj and my ns is main

johnj19:09:02

just wondering if main was reserved or something

noisesmith19:09:12

no, it's not

johnj19:09:52

what about single namespaces, like src/blog.clj where ns is just blog (ns blog) ?

johnj19:09:08

is that fine too?

seancorfield19:09:07

For an app of your own, single segment namespaces are OK. For a library that you expect anyone else to use, multi-segment namespaces mean you're less likely to clash with another library's namespaces.

seancorfield19:09:40

But, in general, it's probably a good mindset to always use multi-segment namespaces.

Ramzi19:09:09

I think I am sending back JSON, but when I do type, it still says String. How do I know if I have JSON, and how can I loop through JSON?

noisesmith19:09:44

is the json automatically parsed on the client side or do you need to call (.parse js/JSON ...) by hand?

Ramzi19:09:58

i think I have to parse it. thanks for the idea

Ramzi19:09:46

So if I have the cheshire source in my src/my-app/clj folder, and I require it in my handler.clj file, then my cljs file can just call functions from it without having to require it at the top of the cljs file?

Ramzi19:09:37

Guess not

noisesmith19:09:28

you shouldn't be able to use cheshire in the frontend, you also don't need it

noisesmith19:09:57

you can literally use the parse method on js/JSON as I showed above (or something very similar, it's been a while)

Ramzi20:09:14

oh i thought i needed to use decode from cheshire

Ramzi20:09:05

can you show me how to do JSON.parse() in clojurescript

Ramzi20:09:24

is it like (.JSON parse content)

Ramzi20:09:05

(.parse js/JSON content)

Ramzi20:09:45

Sweet! I got [object Object],[object Object],[object Object],[object Object],[object Object]

Ramzi20:09:59

That's one step closer to parsing completely.

noisesmith20:09:13

that's what I'd expect the results to look like actually, if you use (.log js/console o) for those objects I think you'll find all the data inside

fel-mazo22:09:47

Hey ! I'm sorry if this question seems stupid. I'm learning clojure and on the official website there is an exercise where you re implement complement. I don't understand why it's implemented the way it is instead of (defn complement [f] (fn [& args] (not (apply f args))))

dadair22:09:08

I believe it is defined to be multi-arity for performance considerations

fel-mazo22:09:27

Can you point me somewhere I can read more about this ?

hiredman22:09:42

there isn't much to read about, varargs have a performance hit, so for core combinators in clojure.core that may be used often as build blocks, for maximal performance it is useful to unroll the low arg count common cases

Cheese Cake Aficionado23:09:12

Could someone help me with seesaw

Cheese Cake Aficionado23:09:12

I want to update a list box when the list is updated

Cheese Cake Aficionado23:09:19

The list is An atom by the way