Fork me on GitHub
#beginners
<
2018-02-19
>
noisesmith00:02:42

you can configure nginx or apache to forward a request to a specific port - it's called "reverse proxy"

noisesmith00:02:25

then you can say /foo/ forwards to port 8080, /bar/ forwards to port 8082 etc.

zlrth00:02:49

that's totally great. thanks @noisesmith

seancorfield00:02:59

@mfm We have half a dozen domains served from Apache proxying to half a dozen different Clojure web processes on different ports, like @noisesmith suggests. Happy to answer questions...

Pedro00:02:13

Howdy. I just started with clojure and I'm having trouble with the following:

(into [] {"key1" "value1" "key2" "value2"})

Pedro00:02:21

It just doesn't work as I would expect. How should I be doing it?

Pedro00:02:26

yeap, should have explaned better i would expect the resulting vector to have the map

noisesmith00:02:50

oh, the role of into is to empty one contents into another collection

noisesmith00:02:59

if all you want is to put the collection into the other, just use conj

Pedro00:02:17

that makes so much more sense

noisesmith00:02:23

(conj [] {"key1" "value1" "key2" "value2"})

Pedro00:02:27

i can't belive i spent 1 hour in this

noisesmith00:02:50

but really you can also just put the map inside a [] pair, depending on if you have anything else in there

noisesmith00:02:36

@pedrohjordao if you haven't seen it yet, http://4clojure.com has some good example problems which help with some of the language basics

Pedro00:02:07

actually, what I have is something more like:

(loop [remaining-data json-data
         processed-data {:open-jobs [] :free-agents [] :pending-requests [] :schedualed-jobs []}]
    (if (empty? remaining-data)
      processed-data
      (let [[head & tail] remaining-data]
        (recur tail
               (match (first (keys head))
                 "new_job" (assoc processed-data :open-jobs (conj (:open-jobs processed-data) (get head "new_job")))
                 "new_agent" (assoc processed-data :free-agents (conj (:free-agents processed-data) (get head "new_agent")))
               ...
I'm using the match library because i'm used to using matching stuff from other languages. Is there's anything more idiomatic in the core language that I should know about? Also, how idiomatic is what I'm doing in general?

Pedro00:02:14

thanks, I'll take a look

noisesmith00:02:00

loop/recur to process a collection one item at a time is low level

noisesmith00:02:42

generally you'd use map (if you output one item per input), mapcat (for 0 or more items per input but still distinct), reduce (to build up some result(s) based on consuming the input in order)

noisesmith00:02:14

your case looks like reduce to me

Pedro00:02:20

yeah, I guess I'm just doing what I'm more familiar with, but I probably should be using reduce

noisesmith00:02:36

speaking of "case" that match call can be replaced with case, which is built in

Pedro00:02:11

nice, i'll take a look

noisesmith00:02:27

and those assoc calls would be much simpler as assoc-in / update-in

noisesmith00:02:40

actually yeah those look like update-in with conj

noisesmith00:02:12

user=> (update-in {:c 0 :a {:b ["foo"]}} [:a :b] conj "bar")
{:c 0, :a {:b ["foo" "bar"]}}

noisesmith00:02:52

in your case it would be more like (update processed-data :open-jobs conj (get head "new_job"))

Pedro00:02:49

you are saving my life man

noisesmith00:02:36

@pedrohjordao another small thing - if you change (let [[head & tail] remaining-data] ...) to (let [[mkey mval] & tail] remaining-data] ...) you can use the key and the value of that map entry directly instead of having to look up by key or look at the first item

Pedro00:02:20

hum, so, i tried that and got an error earlier

noisesmith00:02:32

so (get head s) becomes mval

noisesmith00:02:48

you might have gotten an error, but that kind of destructure does work if done correctly

Pedro00:02:56

something about nth not implemented for the map

noisesmith00:02:05

then call seq on the map

noisesmith00:02:44

(let [[[mkey mval] & tail] (seq remaining-data)] ...)

Pedro00:02:07

I'm trying to use reduce instead of loop right now, so I'm having a different problem

noisesmith00:02:16

the only big change there is that the accumulator comes in first, opposite of the order of your bindings (unless there's something tricky you didn't show in your other code)

Pedro00:02:31

would you mid taking a look at it?

Pedro00:02:32

(reduce #(match (first (keys %2)
                 "new_job" (update %1 :open-jobs conj (get %2 "new_job"))
                 "new_agent" (update %1 :free-agents conj (get %2 "new_agent"))
                 "job_request" (update %1 :pending-requests conj  (get %2 "job_request"))
                 :else %1))
          {:open-jobs [] :free-agents [] :pending-requests [] :schedualed-jobs []}
          json-data))
it complains about "ArityException Wrong number of args (9) passed to: core/first--4339 clojure.lang.AFn.throwArity (AFn.java:429)" the data is something like this: [ { "new_job" {"key1" "value1", "key2" "value2"}} {"new_agent" {"key1" "value1", "key2" "value2"}} ...}

noisesmith00:02:33

notice where the close paren is that matches the open paren by first on that first line

Pedro00:02:30

yeap, I guess I'm really tiread, hahaha

noisesmith00:02:31

your next problem will be that with reduce, you only see one key/value pair from json-data at a time

noisesmith00:02:59

so instead of treating it like a hash-map, you need to treat it like a two element vector, or a map-entry

noisesmith00:02:37

so (first (keys %2)) becomes either (key %2) or (first %2)

noisesmith00:02:59

a few other changes similarly (using second or val on %2 instead of get)

Pedro01:02:17

huum, maybe I'm not getting what you are saying. After fixing the closing paren it is working as expected

noisesmith01:02:07

oh, is json-data a hash-map or a vector full of hash-maps each one having exactly one key?

noisesmith01:02:15

I might have made an incorrect assumption here

Pedro01:02:20

second one

noisesmith01:02:30

that's weird, but OK 😄

Pedro01:02:41

yeah, i though it so, but it's not my data

noisesmith01:02:04

so basically it's a series of tagged events

noisesmith01:02:18

cool, so that should just work then

Pedro01:02:10

to tell it the truth I still think (first (keys ... )) looks weird

Pedro01:02:31

but it works, so... :face_with_rolling_eyes:

noisesmith01:02:34

so instead of (first (keys %2)) and (get %2 s) you can use a destructure of the seq of %2

noisesmith01:02:35

#(let [[[k v]] (seq %2)] ...) - rest of the code can just use k and v instead of using get / first / keys etc.

noisesmith01:02:06

k and v are idiomatic names for the values in a single map entry, standing for key and value of course

Pedro01:02:24

huh, after doing that I get CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/case, compiling:

noisesmith01:02:56

where are you using case?

Pedro01:02:32

in place of match, but before that i had the same error with match

noisesmith01:02:04

sounds like you forgot the opening paren

noisesmith01:02:14

(let [...] (case ...))

Pedro01:02:25

just fould that out

noisesmith01:02:31

in clojure there are very few ways to invoke something without an open paren

Pedro01:02:17

hum, I don't think clojure is too happy with the key/value idea

Pedro01:02:39

oh, no, that's me being dumb

Pedro01:02:11

yeap, everything works

noisesmith01:02:04

so I think we eliminated half of your lines of code and 3/4 of your parens from your original

Pedro01:02:16

I'm way too tired to keep going today, but I made good progress Thank you very much!

Pedro01:02:24

yeap, looks much clearer

Pedro01:02:18

it seems like a cool language, but damn these errors are obscure

noisesmith01:02:29

@pedrohjordao another thing to consider is that (apply merge-with conj {"new_job" [] "new_agent" [] "job_request" []} json) does almost everything you need, aside from renaming some keys in a hash-map

noisesmith01:02:48

haha, but get some sleep and coffee before considering that probably

Pedro01:02:52

that looks really good, but I can't think anymore

Pedro01:02:11

again, thank you

pablore02:02:21

Just learned about transducers. All of this time I was just using a lot of threaded macros with map, filter, etc. Should I refactor them to comp instead of ->> ?

noisesmith02:02:11

It depends, the transducer would perform better, but unless you measure and see a problem at that point just go with what's easiest to read

fmn07:02:59

Anybody here that uses mount for cljs and experiencing an issue where a state starts multiple times?

Naylyn10:02:22

How can I tell which method will be called when I call a function which is a multimethod on a value?

val_waeselynck10:02:23

by calling dispatch-fn on that value maybe?

Naylyn11:02:41

It looks like https://clojuredocs.org/clojure.core/get-method pretty much does it. I don't really know what to do with the information I get out of it though.

Naylyn11:02:25

e.g. #function[clojure.core/fn--7019]

val_waeselynck11:02:38

@U86J7B0VD not much I guess - maybe look at the class name, or perform identity comparison. It's not surprising to me that you can't do much - after all, the whole point of polymorphism is that the caller knows little about the implementation

val_waeselynck11:02:03

@U86J7B0VD why do you need to know the implementing function?

Naylyn11:02:02

I'm really just looking at it for curiosities sake, while trying to understand the language and the problems it solves better.

Naylyn11:02:11

Your point about polymorphism is well taken, thanks.

Serge10:02:47

What is the AOT? Ahead-of-time?

Serge11:02:59

What does it mean?

danm12:02:30

Now you've got me 😉

danm12:02:03

https://clojure.org/reference/compilation probably does a better job than I can of explaining it

justinlee16:02:59

@funyako.funyao156 i’m not sure what you are asking but maybe defonce will help you?

timo17:02:10

anyone knows an example or a tutorial or something like that about material-ui? I am thinking about using it because I need to improve ux especially a form. I am using reagent.

Will18:02:50

Using this piece of code

(->> receiptItems (map #(merge % {:guid (str "12343efidsli3o4203") :receipt_guid guid :user "WILL" :ts "Date"})))
I’m creating a new vector of maps from a vector of maps called receiptItems. How would I add the index / number the item is in the receiptItems vector to the new map?

manutter5118:02:44

You might be looking for map-indexed

Will18:02:26

What is the right way to use map-indexed? I’ve tried

(->> receiptItems (map-indexed index #(merge % {:guid (str "12343efidsli3o4203") :receipt_guid guid :item_num index :user "WILL" :ts "Date"})))
to no avail

sundarj18:02:48

@josmith2016

user=> (map-indexed #(assoc %2 :index %1) [{:a 1} {:b 2}])
({:a 1, :index 0} {:b 2, :index 1})

steven kent19:02:53

How do you split but keep the item you split on in the resulting string? I am using (clojure.string/split item #"[.?!]") and it is splitting, but dropping any .?! I need to keep those in the result. Thanks!

seancorfield19:02:35

@stevenpkent You'll need to use lookahead in the regex, like this: (clojure.string/split "stuff.nonsense?and!?more" #"(?=[\.\?\!]+)")

seancorfield19:02:07

That produces ["stuff" ".nonsense" "?and" "!" "?more"] which might be close enough to what you're looking for?

manutter5119:02:20

I tried this:

(map rest (re-seq #"([^.?!]*)([.?!])" "Hi. How are you? I'm great! Cool"))
=> (("Hi" ".") (" How are you" "?") (" I'm great" "!"))

sundarj19:02:35

@stevenpkent can also do

user=> (map clojure.string/join (partition-by #{\! \? \.} "foo! bar? baz. qux"))
("foo" "!" " bar" "?" " baz" "." " qux")
(in this particular case)

sundarj19:02:08

user=> (clojure.string/split "...a" #"\.")
["" "" "" "a"]
user=> (map clojure.string/join (partition-by #{\! \? \.} "...a"))
("..." "a")
doesn't quite work the same as split

steven kent19:02:17

thanks all, I will try all these out

sundarj19:02:07

if you replace the map in @manutter51's with mapcat you get this:

user=> (mapcat rest (re-seq #"([^.?!]*)([.?!])" "Hi. How are you? I'm great! Cool"))
("Hi" "." " How are you" "?" " I'm great" "!")

noisesmith20:02:25

wonder if there’s a simple way to get the rest of the input

sundarj23:02:35

@noisesmith making the last group optional gives you this:

user=> (mapcat rest (re-seq #"([^.?!]*)([.?!])?" "Hi. How are you? I'm great! Cool"))
("Hi" "." " How are you" "?" " I'm great" "!" " Cool" nil "" nil)

sundarj23:02:40

little messy but it's all there 😛

steven kent00:02:40

I ended up getting this as the intermediate response

[[["this is a file" " this is the second sentence"] ("." ".")] [["i am trying to capitalize the first word of every sentence, using Clojure"] (".")] [["will this work" " will this work"] ("?" "!")] [["i hope i can get this to work"] (".")]]

steven kent00:02:19

so if I can associate each punctuation mark with the sentence it goes with, it should be done. I already have trim and capitalize working. i just need to get the the punctuation associated in.

noisesmith01:02:11

something like (apply map (partial apply map vector) ...)

gmercer20:02:06

I was using compojure.api and it was displaying the standard swagger interface, after an unexpected machine restart - it now sends a gzip payload. I have clean every cache I can think of, and even copied just the source of the project to a new directory, same gzip result. I may have upgraded a library prior to machine crash without re-starting the repl - Any ideas on how to debug this and get back to my sweet swagger page?

manutter5120:02:45

Do you know what's in the gzip?

manutter5120:02:30

I'd also try a different browser. Using DevTools in Chrome, I see a standard request header of Accept-Encoding: gzip, deflate, br, so it's possible the server thinks your browser wants gzip compression just as an encoding

gmercer20:02:02

I got a bit further downloaded ModHeader chrome plugin - changed accept-encoding to empty and now I get the swagger header. My new problem is GET http://localhost:8080/api-docs/config.json 404 (Not Found)

manutter5120:02:40

Hmm, not sure what to make of that.

gmercer20:02:56

compojure was set to :spec "/swagger.json" tried changing to :spec "/config.json", no luck

gmercer20:02:13

I should mention compojure-api is servicing the api correctly, I just don't have the swagger part of the config working ...

ikitommi20:02:54

@gmercer did you try to update to latest deps? that 404 sounds like a bug that was fixes in latest ring-swagger.

ikitommi20:02:35

the swagger-ui changed radically from 2.0 to 3.0, here’s the commit to support them both: https://github.com/metosin/ring-swagger/commit/a9c6efcc77855f303bffbde4beb838baf1ce63df (the conf.js is not found if the version don’t match)

gmercer21:02:48

I am sorta back now, [metosin/compojure-api "2.0.0-alpha16"]

gmercer21:02:38

but I am relying on the empty accept-encoding from ModHeader I have vague library upgrade memory of bumping buddy-auth and which depends on cheshire 5.8.0, and failed to start until I added explicit dependency for cheshire, downgraded to something in my ~/.m2 I must have kept fighting deps and not re-checked swagger

gmercer21:02:05

dropping http-kit back from 2.2.0 to 2.1.0 got rid of the gzip issue, which has now turned to a CORS issue - which should be easy to solve - not back online for 10hrs (I doubt anyone is in suspense though)