Fork me on GitHub
#clojure
<
2019-12-13
>
knubie01:12:39

anyone know how to write circularly dependent specs? E.g. (s/def ::foo ::bar) (s/def ::bar ::foo)

1
hiredman03:12:44

Circular dependencies work fine, as long as there is some case to bottom out to, but your example is just nonsensical

deas08:12:08

Trying to log in at http://clojure.atlassian.net and raise an issue. Getting "<my-e-mail> does not have access to Jira at http://clojure.atlassian.net" after logging in. What am I missing?

deas08:12:03

A forum? 😲

p-himik08:12:55

To alleviate your shock a bit, it looks more like StackOverflow than a regular phpBB forum. 🙂

😰 1
andy.fingerhut09:12:33

For the particular situation you mention, you can send a message to Alex Miller in the #clojure-dev channel here, and he will likely notice it fairly soon, and is the person who typically handles these things.

deas09:12:38

The issue at hand is indeed likely to be addressed at Alex. However, I'd be truly surprised if you see what's coming ... hold my 🍺 😉

andy.fingerhut15:12:40

I mean, Alex can handle the permissions issue you are experiencing, at least. Whether he has time to improve one of the Clojure contrib libraries that isn't already on his list of jobs, I have no idea 🙂

holyjak11:12:37

Hi! Given a tree data structure, what is the best way to drop all siblings after a particular node? Zippers? Prewalk? Thanks!

p-himik12:12:05

How do you store this tree? If it's a map of maps, do you use ordered maps?

holyjak12:12:05

Enlive data for a DOM. Each node is a map with :children list

vemv12:12:47

AFAIK, prewalk doesn't inform you of your current position, nor it allows you to 'look' at nodes other than the current one So zippers seem more apt

holyjak12:12:03

I can look at the children and change them though?

vemv12:12:41

I think so. You can always make a new zipper out of an old one. Take a look at https://clojure.github.io/clojure/clojure.zip-api.html , it has 'verbs' for the things you mention (my experience is limited to rewrite-clj, an analog but different API)

p-himik12:12:02

If you know indices of the relevant children in the path, you can just use update-in and subvec since vectors are associative containers from indices to values. Note that subvec does not copy the data - it just keeps a reference to it. So if you want to trim down a huge tree and throw the rest away, you probably want to turn each subvec into a proper vector.

p-himik12:12:39

E.g. (update-in tree [1 2 2] subvec 0 7).

holyjak12:12:33

Thx folks! I try zippers, it's time to learn them finally!

p-himik12:12:36

Just make sure to not overcomplicate things just because you want to learn something. 🙂 There's no sense in calling (repeatedly n zip/down) if the case is so simple that you can just use n with update-in directly.

holyjak19:12:14

It is not. I need to find a particular node in the tree - a <--more-->, comment - and drop everything after it.

👍 1
Hi14:12:44

Hello! How to push Timbre's logs stright to Systemd or Journald?

vemv15:12:47

Creating your own appender. The README should get you started

vemv15:12:15

You might also try luck via the log4j route, see e.g. https://github.com/bwaldvogel/log4j-systemd-journal-appender Might be more 'effortless' in some ways, but making sense of all the parts (timbre -> timbre adapter -> java lib) might be painful

1
erwinrooijakkers15:12:32

I would recommend switching to clojure.tools.logging and use an existing logback appender to route traffic to it:

<configuration>

  <appender name="journal" class="org.gnieh.logback.SystemdJournalAppender" />

  <root level="debug">
    <appender-ref ref="journal" />
  </root>
</configuration>

erwinrooijakkers15:12:01

Deps:

;; Logging
                 [ch.qos.logback/logback-classic "1.2.3" :exclusions [org.slf4j/slf4j-api]]
                 [org.slf4j/slf4j-api "1.7.26"]
                 [org.slf4j/jul-to-slf4j "1.7.25"]
                 [org.slf4j/jcl-over-slf4j "1.7.25"]
                 [org.slf4j/log4j-over-slf4j "1.7.26"]
                 [org.clojure/tools.logging "0.4.1"]

erwinrooijakkers15:12:19

Add a logback.xml with the right appenders

erwinrooijakkers15:12:03

E.g.,

<!-- Logback configuration. See http://logback.qos.ch/manual/index.html -->
<!-- Scanning is currently turned on; This will impact performance! -->
<configuration scan="true" scanPeriod="10 seconds">
  <statusListener class="ch.qos.logback.core.status.NopStatusListener" />

  <include resource="logback-gcloud-appender.xml"/>
  <include resource="logback-sentry-appender.xml"/>

  <root level="INFO">
    <appender-ref ref="GCLOUD" />
    <appender-ref ref="SENTRY" />
  </root>

  <!-- For loggers in the these namespaces, log at all levels. -->
  <logger name="user" level="ALL" />

</configuration>

erwinrooijakkers15:12:10

And in your case the one above

erwinrooijakkers15:12:19

+ the dependency for the appender

erwinrooijakkers15:12:33

Now you have all Java logging rerouted to it

erwinrooijakkers15:12:41

And you can use the Java ecosystem’s logging tooling

erwinrooijakkers15:12:53

Proper logging is a solved problem there

vemv15:12:36

I concur - Timbre is bit of an anti-java solution, which isn't necessarily bad, but for certain needs it will probably imply reimplementing solved problems as @U2PGHFU5U says

Hi16:12:15

thank you for answers

jmckitrick15:12:20

Has anyone ever seen lein compile just hang, while cider can run the code with no issues?

andy.fingerhut15:12:49

If you have any top level forms in your code that execute long-running (or forever-running) code, they will be evaluated during lean compile IIRC.

andy.fingerhut15:12:13

If the code in question is a server process that runs indefinitely, for example, and is started when loading the file ...

jmckitrick15:12:49

:thinking_face:

amalantony15:12:33

Hello, how can I invoke the ring-oauth2 middleware for every compojure-api route? The middleware takes this syntax:

(wrap-oauth2
  handler
          {:google
          {:authorize-uri ""
            :access-token-uri ""
            :client-id "some-id"
            :client-secret "some-secret"
            :scopes [""]
            :launch-uri "/api/oauth/google"
            :redirect-uri "/api/oauth/google/callback"
            :landing-uri "/"}})
And my compojure-api handler is of the form:
(def app
  (api
   (context "/api" []
     :tags ["api"]
     :middleware []

     (GET "/roll/:n/:s" []
       :path-params [n :- s/Int
                     s :- s/Int]
       :return Result
       :summary "Rolls :n dice of sides :s"
       (ok (roll-dice n s))))))
The problem I'm facing is that I want this middleware to work across all my routes, not just for any specific route/context. I don't see an option in the documentation to make a middleware work across all routes.

alexbaranosky15:12:38

Wrap the compojure handler in the middleware.

misha15:12:17

greetings! is there a way to make a class instance not directly from class (symbol?), ~like this:

(let [x String]
  (new x))
Syntax error (IllegalArgumentException)
Unable to resolve classname: x

vemv16:12:16

maybe accomplishable by doing the work within a defmacro either that, or resorting to java reflection... no other way I think - new is a Clojure special form

p-himik16:12:37

(.newInstance x)

1
misha16:12:51

then next question is: is there an example of wrappers around java data records with good UX? trying to "prettify" something like this:

(case pick-var-type
    :largest-domain (LargestDomain.)
    :largest-max (LargestMax.)
    :largest-min (LargestMin.) ...

misha16:12:25

(let [x String]
  (.newInstance x))
=> ""
!

sh16:12:55

What is Java data records?

misha16:12:28

"value object" :D

p-himik16:12:28

In general, if you don't know if something can be done in Clojure, it makes sense to first check how it could be done in Java.

misha16:12:54

good point.

ghadi16:12:24

.newInstance is deprecated @U051HUZLD @U2FRKM4TW

p-himik16:12:23

Not in Java 8. 🙂 Still, there is Constructor.newInstance() which is a non-deprecated replacement.

p-himik16:12:18

But that would be what vemv has mentioned initially - resolving to Java's reflection.

misha16:12:50

(let [x String
      ca (into-array java.lang.Class [])]
  (-> x (.getDeclaredConstructor ca) (.newInstance ca)))

ghadi16:12:44

why not just use eval?

👍 1
ghadi16:12:51

not sure what the use-case is here

p-himik16:12:02

Thanks for bringing it up. I keep forgetting that it exists, probably because I've never had any use for it. But it definitely looks better than the reflection.

valerauko17:12:06

eval parrot

(let [x String]
  (eval (list 'new (-> x .getName symbol))))

p-himik17:12:56

(let [x String]
  (eval (list 'new x)))

parrot 1
ikitommi16:12:30

@amalantony you can add :middleware to api options too.

amalantony16:12:25

Thanks @U055NJ5CC. But how do I pass the second param:

{:google
    {:authorize-uri ""
      :access-token-uri ""
       :client-id "some-id"
       :client-secret "some-secret"
       :scopes [""]
       :launch-uri "/api/oauth/google"
       :redirect-uri "/api/oauth/google/callback"
       :landing-uri "/"}}
to the middleware array. It looks like the middleware array only takes middleware names.

ikitommi16:12:34

I think it takes names or vector of name + args

ikitommi16:12:03

[mw1 [mw2 args] mw3]

amalantony17:12:07

@U055NJ5CC that worked. Thank you!

misha18:12:43

is there a way to typehint arrays of non-primitives?

bfabry18:12:52

yes, but it looks gross 🙂

hiredman18:12:23

yes but it doesn't do much of anything

seancorfield18:12:41

An example ^{:tag (class (into-array String []))}

misha18:12:12

oh, I got flashbacks now, thank you

bfabry18:12:50

you can also do ^"[Ljava.lang.String;"

💯 1
misha18:12:09

^"[Lopennlp.tools.util.Span;" (into-array Span spans)

misha18:12:29

this is what I ended up doing ~6 months ago

andy.fingerhut18:12:19

Do you know whether this type hint actually causes the code to perform better, or function correctly with the type hint, and be worse without it?

alexmiller18:12:20

there are places where it can avoid reflection and thus be better

seancorfield18:12:59

That example above is from next.jdbc.prepare and is there to avoid reflection.

dvingo22:12:02

clojure.test question: I have a repl open, I eval the test file, eval run-tests, things are fine, tests are executed. I comment out some of those deftests , re-eval the file and eval run-tests, those commented out deftests are still executed. Anyone seen this before?

alexbaranosky01:12:42

(deftest my-old-test nil) Do that, then delete the code.

vemv11:12:36

@danvingo: deftest simply creates vars. there's nothing special about it with https://github.com/clojure/tools.namespace those vars would be gone, just like it happens wiith non-test namespaces

alexbaranosky15:12:16

My solution works out if the box. no need to pull in any deps.

vemv15:12:15

It's also a manual one, and that still creates a var.

dvingo22:12:43

I don't want to kill the repl

lukasz22:12:38

@danvingo (remove-ns 'your.test.ns) and require it again

hiredman22:12:53

evaling doesn't remove existing definitions

hiredman22:12:02

evaling is additive, it just adds definitions

dvingo22:12:30

ah perfect, thank you!

bostonaholic22:12:24

if you comment out the body of those deftest it might have the intended behavior you’re after. effectively running empty tests

dvingo23:12:13

that's a good idea as well!

Eduardo Mata23:12:03

What does the following exception mean?

Eduardo Mata23:12:04

Java.lang.IllegalStateException: Attempting to call unbound fn: #'namespace-in-here/function-name

bfabry23:12:19

that you have (something/function-name somewhere but that var does not have a function bound to it

bfabry23:12:47

could also be (map something/function-name or a few other things

bfabry23:12:08

maybe you could paste the code where function-name occurs

andy.fingerhut23:12:58

If you tried to def function-name earlier, but an exception or perhaps some other kinds of errors occurred while evaluating the value you were attempting to "assign", then the Var function-name can end up in an intermediate unbound state.

andy.fingerhut23:12:09

attempting to call it in that unbound state causes the exception message you see

Eduardo Mata23:12:12

(def processors
  {:processor1 [function-name]
   :processor2 [function-name]
   :processor3 [function-name]
   :processor4 [function-name]
   :processor5 [function-name1 function-name2]
   :processor6 [function-name]
   :processor7 [function-name1 function-name3]
   :processor8 [function-name1]})

; FUNCTIONS
(defn- run
  "Wrap the processor function in a try/catch to prevent crashes."
  [f entity]
  (timbre/info "RUNNING:" f entity)
  (try (f entity)
       (catch Exception e
         (timbre/error e))))

(defn- router
  "Route a `data` map to the correct processor based on the `:processor` key."
  [data]
  (let [delay (:delay data)
        processor (:processor data)
        processors (get processors processor)]
    (if (some? delay) (Thread/sleep delay) :default)
    (cond (nil? processors)
          (timbre/info {:message (str "NO PROCESSOR FOUND: " processor)})
          :else
          (doseq [processor processors]
            (run processor data)))))

Eduardo Mata23:12:59

It works fin however, there is something going on when I remove some of the logic that gets in to the router function

andy.fingerhut23:12:02

Does the exception you actually see contain #'namespace-in-here/function-name , or does it have one of the names you pasted above?

👍 1
Eduardo Mata23:12:43

is with the functions I paste above

Eduardo Mata23:12:46

I just changed the names

andy.fingerhut23:12:57

What name do you see in the exception, exactly?

Eduardo Mata23:12:21

#'namespace-in-here/function-name which is basically almost every processor

Eduardo Mata23:12:34

I need to recreate the issue because above code works

Eduardo Mata23:12:01

I did something different before calling the function router, and this same router code. and I had that exception

andy.fingerhut23:12:48

Is there code before what you pasted that tries to assign a value to function-name

seancorfield23:12:37

@UM0E0PZ41 Are you working with an editor that tries to reload namespaces? I've seen that cause problems similar to what you reported. I recommend turning off all auto-reloading in editors until you really understand the "reloaded" style workflow.

seancorfield23:12:24

(and even then I still recommend against it -- I agree with Eric Normand and Stu Halloway that such workflows are unnecessary at best and can be really confusing/problematic at worst)

alexbaranosky15:12:54

What that exception means is that the var you tried to call the function from never had a function assigned to it.

alexbaranosky15:12:47

(def f) (f) ;; should give a similar exception