Fork me on GitHub
#beginners
<
2020-06-07
>
Chicão01:06:10

May someone can help? I have one problem when I stop my server in REPL. This is a project to study component.stuartsierr. https://github.com/xico-labs/budget-calculator-api/blob/master/src/budget_calculator_api/core.clj#L21

actual: clojure.lang.ExceptionInfo: Error in component :http in system com.stuartsierra.component.SystemMap calling #'com.stuartsierra.component/stop
{:reason :com.stuartsierra.component/component-function-threw-exception, :function #'com.stuartsierra.component/stop, :system-key :http, :component #
rver{:port 8080, :join false, :storage #budget_calculator_api.components.storage.InMemoryStorage{:storage #object[clojure.lang.Atom 0x4ce4c097 {:status :ready, :val [{:id 1, :bill-title "Gast
ei com remedio", :ammount "R$ 200 moedinhas"} {:id 3, :nome "Ola", :ammount "100 moedinhas"}]}]}}, :system #<SystemMap>}
When I (assoc system :http nill) my server stopped well but when i use (component/stop system) my server crashed

ludociel03:06:38

i'm back with another clojure / ring doubt:

(defn -main []
  (jetty/run-jetty (logger/wrap-with-logger app) {:port port-number}))
my project is dependent on apache tika parser, so prior to adding it as dependency i had information like running at 3000 port, jetty 9.0 blah blah and all now because i added tika parser and using it, i get this (warnings?) when i do lein run
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See  for further details.
Jun 07, 2020 9:04:15 AM org.apache.tika.config.InitializableProblemHandler$3 handleInitializableProblem
WARNING: J2KImageReader not loaded. JPEG2000 files will not be processed.
See 
for optional dependencies.

Jun 07, 2020 9:04:15 AM org.apache.tika.config.InitializableProblemHandler$3 handleInitializableProblem
WARNING: org.xerial's sqlite-jdbc is not loaded.
Please provide the jar on your classpath to parse sqlite files.
See tika-parsers/pom.xml for the correct version.
nothing else. also i added today logging functionality, i'm not able to see anything on the console other than the above text at this rate. thanks, let me know if you know anything about this.

seancorfield03:06:15

You can solve the SQLite warning by adding the org.xerial/sqlite-jdbc {:mvn/version "3.30.1"} dependency (that's deps.edn format -- lein is a different format).

seancorfield04:06:05

No idea about the J2KImageReader (but, again, that's just another set of dependencies to add).

seancorfield04:06:41

Does your server app still start on port 3000 @jaiimmortal?

ludociel04:06:29

@seancorfield yes yes it does. I honestly don't need sqlite dependency for my project.

seancorfield04:06:54

Then you can just ignore the warnings I guess.

ludociel04:06:16

Yeah but its hiding the jetty/ring logs and the information about it started and running on port and all

seancorfield04:06:09

@jaiimmortal Ah, I just went through this with next.jdbc in testing -- I added log4j2 and the log adapters and then a .properties file to control the logging, restoring what I wanted and suppressing what I did not..

ludociel04:06:47

so I should add log4j2 as a dependency to my project.clj? @seancorfield, and my problem will magically go away?

seancorfield04:06:43

See this commit https://github.com/seancorfield/next-jdbc/commit/9ea87afdd53e0cb3b39263b6d6f702e98a23ad42 (there's some other stuff in there but it should give you an idea)

seancorfield04:06:49

You get a lot of control over the format and it's easy to control configuration via JVM opts and/or environment variables -- so it can be tweaked for dev/test/prod as needed -- and with the log adapters, at least everything flows through the modern library, so you can control it all centrally.

seancorfield04:06:11

(Java logging is a big ol' nightmare, unfortunately)

seancorfield04:06:00

Because you have no other slf4j logging implementation on your classpath, it is defaulting to "no logging". A "simple" solution could just be to add the appropriate slf4j logging library, but you might as well learn how to control all logging at this point...

ludociel04:06:13

As you said it prefers sl4j over the other ones

seancorfield05:06:37

It's probably a simpler, more direct "fix" for this particular problem. But Java logging is a giant mess, whatever you do 😐

ludociel05:06:25

After two hours. I added [org.slf4j/slf4j-simple "1.6.2"] and it starts working as expected.

pmonks05:06:26

FWIW I prefer logback for logging over log4j, though most of my experience with log4j has been with v1. slf4j also provides ways to force calls to other Java logging libraries to pass through it instead, and IMLE those mechanisms seem to work well. You can see an example of how to set that up here: https://github.com/symphonyoss/bot-unfurl/blob/master/src/bot_unfurl/config.clj#L28-L30 and here: https://github.com/symphonyoss/bot-unfurl/blob/master/project.clj#L39-L43

pmonks05:06:00

As @seancorfield mentioned, the Java logging landscape is a radioactive dumpster fire (my words, not his!), and the best you can hope for is to punt to something like slf4j to do its best to corral disparate incompatible logging calls from your various dependencies into a single logging mechanism.

seancorfield05:06:56

slf4j treats fatal and error as the same level so that is an instant black mark in my book.

seancorfield05:06:45

(I'm going to sleep now!)

pmonks05:06:06

Can log4j2 intercept calls to other logging libraries though (`clogging`, jul, etc.)? That’s a substantially more important requirement in my book…

pmonks05:06:53

Also, the slf4j team have a reasonable argument as to why FATAL is a different concept than logging level: http://www.slf4j.org/faq.html#fatal. Not saying everyone has to agree with it, mind you, but it was a conscious choice.

ludociel06:06:25

i started with clojure/ring day before yesterday without prior experience in java for doing a quick project involving tika parser. didn't expect to go down such a rabbit hole

pmonks06:06:37

Sorry. 😞 Logging is one of those things in Java that’s just had a long and sad history…

pmonks06:06:59

The good news is that Clojure libraries like tools.logging (mostly) hide this mess at the level of your code. The complexity is (mostly) constrained to picking a logging implementation.

Joe09:06:00

I have a structure like this

[{:name "fred" :food "burger"}
 {:name "fred" :food "pizza"}
 {:name "fred" :food "apple"}
 {:name "jane" :food "kebab"}
 {:name "jane" :food "sandwich"}]
And I want to turn it into a structure like this
{"fred" ["burger" "pizza" "apple"]
 "jane" ["kebab" "sandwich"]}
Is there way to achieve this without needing to reduce?
(reduce (fn [m {:keys [name food]}]
          (update m name conj food))
        {}
        [{:name "fred" :food "burger"}
         {:name "fred" :food "pizza"}
         {:name "fred" :food "apple"}
         {:name "jane" :food "kebab"}
         {:name "jane" :food "sandwich"}])
(the observations in the sequence are guaranteed unique, so was thinking maybe using some set functions?)

afleck13:06:19

in re-frame is doing something like (rf/dispatch [:set-foo (js/setInterval #(bar) 1000)]) considered 'impure'?

afleck13:06:52

just wondering what the best way to do something like this is

dpsutton13:06:33

clojurescript is strict so that is equivalent to (rf/dispatch [:set-foo 42]) or whatever number setInterval will return. there's a dedicated #re-frame channel to give more tailored advice. But you most likely would want to create an effect which would take a function and interval and it would schedule the interval rather than doing it there. but perhaps there's a better way and describing more of the problem could help

afleck13:06:23

@dpsutton that's exactly what I want to do, I want to keep track of the interval id so I can clear it later. I'm using that event to both start the interval and save the id for later clearing. but I will ask in #re-frame, thank you

nick15:06:59

add-watch is firing on each swap! Is it normal? I'm trying to capture "real" state updates - any changes to :artist or :title ;; "-- Atom Changed --" ;; "key" :watcher ;; "atom" #atom[{:artist "Rammstein", :title "RADIO"} 0x1a37dc61] ;; "old-state" {} ;; "new-state" {:artist "Rammstein", :title "RADIO"} ;; ;; "-- Atom Changed --" ;; "key" :watcher ;; "atom" #atom[{:artist "Rammstein", :title "RADIO"} 0x1a37dc61] ;; "old-state" {:artist "Rammstein", :title "RADIO"} ;; "new-state" {:artist "Rammstein", :title "RADIO"} ;; ;; "-- Atom Changed --" ;; "key" :watcher ;; "atom" #atom[{:artist "Rammstein", :title "RADIO"} 0x1a37dc61] ;; "old-state" {:artist "Rammstein", :title "RADIO"} ;; "new-state" {:artist "Rammstein", :title "RADIO"}

dpsutton15:06:15

that sounds bad

dpsutton15:06:21

it is not normal

dpsutton15:06:05

what is making you think add-watch is firing on each change versus the function you added as a watch firing on each change?

dpsutton15:06:24

what do you expect to happen?

dpsutton15:06:13

oh i see. you expect add-watch functions to only fire when the old and new vals are not equal rather than on each change to the atom's value, even if that value is the same?

nick15:06:28

yep, exactly

nick15:06:52

perhaps I should compare old & new state inside that watcher?

dpsutton15:06:03

an easy way to accomplish this is leverage old-state and new-state in your function. (when (not= old-state new-state) (prn new-state))

dpsutton15:06:15

you could also look at clojure.data/diff to find what is different if you like

nick15:06:31

got it. Thank you!

Phil Hunt18:06:56

Hi there. I'd like to start exploring Clojurescript now. I'm using Emacs / Cider to do Clojure and am fairly comfortable with that setup. What's a good starting point? Most of the resources I've googled look old and/or assume you know current cljs ecosystem fashions. What I'm hoping to find is the equivalent of the first few chapters of 'Clojure for the Brave' ie something that says, when Cider offers you 12 different REPL choices, pick this one.

dpsutton18:06:21

walks through how to make and deploy a shadow-cljs site with npm deps.

Phil Hunt18:06:33

OK cool thanks.

dpsutton18:06:38

once you get how shadow works it should seamlessly cider-jack-in-cljs and just work

Phil Hunt18:06:58

looks slick, thanks 🙂

amirali18:06:35

hi guys. I'm trying to write a nested loop recur but then it seems like its not working or perhaps it just goes on cause my repl doesnt do anything anymore... could u find my mistake or suggest a better alternative for nested loop-recur? Thanks

(defn test-recur []
  (loop [i 0]
    (if (> i 3)
      i
      (loop [j 0]
        (if (> j 3)
          (recur (inc i))
          (recur (inc j)))))))

seancorfield18:06:00

recur always goes to the closest enclosing loop so both arms of your if will recur to the j loop

okwori18:06:53

Hi guys, is there a way around running Clojure code within IntellIj IDEA's notebook?

seancorfield18:06:41

@simon There's a #cursive channel that might be better able to help...

Michael W19:06:17

(def m {:one 1 :two 2})
How do I get to this:
(:one {:value 1} :two {:value 2}}

seancorfield19:06:25

Do you really mean a sequence in that result, or do you want a hash map?

Michael W19:06:44

Supposed to be a map I must have typoed it

seancorfield19:06:09

(reduce-kv (fn [m k v] (assoc m k {:value v})) {} m) I think

Lennart Buit19:06:33

Yep, thats true, also in my repl 🙂. You beat me to the punch

Michael W19:06:40

Thanks, reduce-kv is nice and works perfectly.

Michael W20:06:40

(def m {:one {:value 1} :two {:value 2}})
(reduce-kv (fn [m k v] (update m k #(assoc % :test "test"))) {} m)
;=> {:one {:test "test"}, :two {:test "test"}}
How do you append a key to a nested map? I tried assoc, update, assoc-in, update-in and they didn't add a key-value to the nested map the way I expected.

AC21:06:52

(reduce-kv (fn [m k v] (assoc m k (assoc v :test "test"))) {} m) ^ if i understand what you want (and you want to continue to use reduce-kv)

AC21:06:08

this would also work: (reduce #(assoc-in %1 [%2 :test] "test") m (keys m))

Michael W21:06:56

That's it exactly it's 2 assoc

adam21:06:29

Which is more idiomatic in Clojure: (if (= (get-in ctx [:request :request-method]) :get)) or (if (= :get (get-in ctx [:request :request-method]))?

seancorfield22:06:35

I don't know that one is more idiomatic than the other but I tend to put the constant/literal expression first, so that if I need to change it to match multiple versions I can just change it to a set:

2
🆗 1
seancorfield22:06:10

(if (= :foo (some-expression)) ...
(if (#{:foo bar} (some-expression)) ...

seancorfield22:06:14

and if I was filtering based on a value, I'd do the same order: (filter #(= :foo %) some-collection)

Michael W22:06:31

https://github.com/michaelwhitford/clojure-swapi/blob/master/src/swapi/core.clj#L93 I am getting a weird error trying to utilize the techniques we've discussed. I tried several ways to get it working, I have commented them out. Any help is appreciated.

seancorfield22:06:28

What error(s) are you getting @michael819?

Michael W23:06:46

Execution error (IllegalArgumentException) at swapi.core/add-schemas!$fn (core.clj:93).
Key must be integer

seancorfield23:06:56

And which of the four versions works and which gives that error? Or do they all give that error?

Michael W23:06:28

I got that error from another too but right now it's the uncommented one

seancorfield23:06:47

The error is basically saying that v in that assoc is a vector and :schema is not an integer...

seancorfield23:06:59

At least I think that's what it is saying.

seancorfield23:06:05

But what is r?

seancorfield23:06:24

I see :resources being added in a function above but what is it?

Michael W23:06:32

It's a a map from an atom

Michael W23:06:00

api! and add-api! functions add it

seancorfield23:06:17

[:url v] is a vector and that's what ends up in :resources and thus the v in line 93 is [:url "some value"] and you're expecting it to be a hash map instead.

seancorfield23:06:24

This would be a lot easier to debug if it was less imperative -- you have global mutable state and a top-level call to (add-api!) that is evaluated when you load the namespace which is not a good idea.

seancorfield23:06:47

Your functions are harder to reason about and harder to test because of the global mutable state.

seancorfield23:06:22

Are you writing tests for these functions, as you go?

Michael W23:06:45

no I haven't even looked at tests in clojure yet, just sitting at the repl and playing

seancorfield23:06:48

(I'm asking because I suspect if you were writing tests, you'd find they are hard to test because of the global mutable state)

seancorfield23:06:25

That's sort of a meta-issue, so back to line 31 -- should that be {:url v} there?

Michael W23:06:52

No, I was trying to append a new key to the nested map

seancorfield23:06:26

So you meant (assoc-in m [k :url] v) then?

Michael W23:06:13

I see where I got mixed up on assoc-in you have to specify the leaf in the vector.

Michael W23:06:58

In terms of state you are talking about the config atom?

seancorfield23:06:32

And then your functions are depending on it, rather than being passed it as an argument.

Michael W23:06:16

Thanks sean, I'll be on later and playing with it more. I really appreciate the feedback cuz I feel like I'm floundering when I should be soaring.