Fork me on GitHub
#clojure
<
2018-07-13
>
justinlee00:07:11

I was watching Stuart Halloway’s repl driven development and he mentioned that he keeps a big file of his repl interactions. Do others do this, and if so, how do you deal with libraries? I typically stick a comment in my existing programs so that I can switch to that namespace and use the libraries that are already loaded.

john03:07:42

I think also Stu (or somebody) came out with a lib that records repl interactions for you, in some way, to make that workflow easier. Sounds interesting.

justinlee03:07:43

I have thought it would be cool to have a mode where you actually express dependencies down to the artifact level in a single file so that you could fire it up and interact with any libraries you want

john04:07:51

Yeah, the whole repl history and IDE change history should be stored in GIT. I'm not yet used to committing my changes every 2 minutes and sometimes I just want to "scroll back" to glance at the working state 10 changes/edits ago. git-repl 😉

hiredman00:07:10

I keep a couple of files named scratch.clj around with something similar

hiredman00:07:49

one on my laptop, one on my work vm, and sometimes a project specific one in the checkout of a project

hiredman00:07:06

the one on my laptop is just over 6k lines now (I think that is after 3 or 4 years)

justinlee00:07:21

and is that file just generic enough that you don’t interact with libraries?

hiredman00:07:28

some big chunks of it are actually macroexpanded core.async code that there is no reason for me to be saving from debugging the go macro

hiredman00:07:07

that is my personal scratch.clj, the one I keep for work projects in my work vm is much smaller these days, mostly because I am less involved in debugging stuff in production

hiredman00:07:51

a previous version of it is full of code that assumes it is running in a work project's repl, and pokes and prods at this and that

hiredman00:07:51

it isn't exactly what stuart is describing, because I will write stuff directly in scratch.clj without trying it in the repl

hiredman00:07:03

and we do also have comments in our work code base containing code to do things like spin up different things in the repl

vigilancetech01:07:26

I know this is a really stupid question but I can't seem to recall how to do something like this:

(defn foo [x y] (prn "x = " x " y = " y))

(map #(apply foo % "none") '(1 2 3 4))
Where I want the '(1 2 3 4) fed in succession as the first argument to (foo). Any ideas?

hiredman01:07:41

get rid of the apply

hiredman01:07:27

map is very likely not want you want there, because you don't care about the result

hiredman01:07:36

so maybe run!

vigilancetech01:07:53

yeah, ok. I see. Thanks!

hiredman01:07:08

and then get rid of the #() and replace run! with doseq

vigilancetech01:07:50

ok, trying to follow the clojure docs examples I try:

(doseq [[x] (map '(1 2 3 4))] (foo x "none"))
and it gives me:
java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.core$map$fn__4781

vigilancetech01:07:09

oops, I forgot to pass a function to map, but I did it with identity and its still erroring

vigilancetech01:07:29

with identity it says:

java.lang.UnsupportedOperationException: nth not supported on this type: Long

sveri14:07:30

I using clj-http to make a post request inside a test (deftest). Now the request returns status 500 which is expected and to be tested, but the test framework reports an exception and therefor an error, no matter what I do in the test.

(deftest ^:rest user-can-login
  (let [res (c/post (str s/test-base-url "api/user/signup")
                    {:body "{\"json\": \"input\"}"
                     :content-type :json
                     :accept :json})]))

(defn signup-user [email password config db]
  (if-let [errors (valid-register? email password db)]
    (resp/internal-server-error errors)
    (with-try
      (db/create-user db email (hashers/encrypt password))
      (resp/ok {:token (sign-token email config)
                :email email :role "none" :is_active true}))))

:reloading (de.sveri.adimov.routes.user de.sveri.adimov.components.handler de.sveri.adimov.components.components de.sveri.adimov.setup de.sveri.adimov.system de.sveri.adimov.core de.sveri.adimov.user)

ERROR in (user-can-login) (support.clj:201)
Uncaught exception, not in assertion.
expected: nil
  actual: clojure.lang.ExceptionInfo: clj-http: status 500
 at slingshot.support$stack_trace.invoke (support.clj:201)
    clj_http.client$exceptions_response.invokeStatic (client.clj:241)
...
When I run the server and do a request with postman I get my json response back as expected. Any ideas what is going on here?

jonahbenton14:07:06

clj-http throws exceptions on 4xx/5xx responses by default, which are not caught in the deftest. add

:throw-exceptions false
to the post call to change that behavior

Timo Freiberg14:07:31

am i the only one that was bitten several times by accidentally closing *in* (or *out*)? for example, when writing a function that uses input/outputstreams with slurp or with-open and testing that function in the repl with *in* or *out*? after fixing https://github.com/clojure-emacs/cider/issues/2317, this seems like my personal nemesis...

Timo Freiberg14:07:10

if not, the problem is that (slurp *in*) closes the inputstream, which makes *in* unusable until you restart the repl.

sveri14:07:45

@jonahbenton Awesome, exactly what I was looking for, thank you.

kennytilton15:07:57

So I have this huge CLJ/S reactive library and I like small source files so my application code using said library is a nightmare of requires. I have now seen a couple of libraries simply relaying symbols from “internal” namespaces out of core.clj (def fubar myinternalns/fubar). Is that the way to go?

noisesmith15:07:33

what's the advantage of a small source file? pragmatically, the annoying thing about (def foo bar/foo) is that when reading code to figure out how something works I run out of mental space for understanding the problem or design in all the breadcrumbs I'm chasing down

noisesmith15:07:29

(that said, it's better than putting a thing into ns foo from code in a completely different file - spooky action at a distance makes debugging extremely difficult)

🙂 4
noisesmith15:07:25

of course, if your code and docs are good enough that I can use your library without having to read source, go for it - that's not the common case in my experience

bendlas15:07:59

@hiskennyness have a look at webnf's autloading macro, which transfers metadata from forwarded vars: https://github.com/webnf/webnf/blob/0.2.x/base/src/webnf/base.cljc

kennytilton15:07:38

“Non-framework”! I love it, I call my web framework the “Un-framework” in honor of the 7-Up “un-cola” campaign before you were born. Thx, I’ll check it out. A macro is a good idea.

joefromct18:07:44

hi, how can i have a spec for a value that can be either one spec or another? This is for composing in another spec... I think i want the s/or but i don't want the key that comes back with it in the parent spec.

Alex Miller (Clojure team)18:07:37

there is an undocumented s/nonconforming that you can wrap around the s/or if you like

👍 4
Alex Miller (Clojure team)18:07:17

(s/nonconforming (s/or ...))

joefromct19:07:11

ok great thank you.

joefromct19:07:15

also thank you for strange loop.

😜 8
bwstearns21:07:30

So I'm working on a macro and was looking at the -> macro source for a bit of understanding, can someone explain what the deal is with the (loop [x x, forms forms] line? It doesn't seem sensical to have the duped bindings.

(defmacro ->
  "Threads the expr through the forms. Inserts x as the
  second item in the first form, making a list of it if it is not a
  list already. If there are more forms, inserts the first form as the
  second item in second form, etc."
  {:added "1.0"}
  [x & forms]
  (loop [x x, forms forms]
    (if forms
      (let [form (first forms)
            threaded (if (seq? form)
                       (with-meta `(~(first form) ~x ~@(next form)) (meta form))
                       (list form x))]
        (recur threaded (next forms)))
      x)))

rwilson22:07:35

Take a look at the docs for loop. The bindings take the form of [form1 initial-value1 ... formN initial-valueN]. Here, the forms in the loop happen to shadow the forms in the -> macro signature, which is I suspect is the source of confusion. Put another way, in (loop [x x, forms forms] ...) the first x is the bound form within the loop, and the second x is initial value, which in this context refers to the outer x in the fn signature. Make sense?

bwstearns14:07:30

Thanks. That does make sense now (although as an idiom it's rather unintuitive).

euccastro23:07:13

@bwstearns: those are only the initial bindings. x and forms will get new assignments in each iteration of the loop. in particular, they'll get the values passed in the recur

bwstearns23:07:51

@euccastro But why is is x x, forms forms and not x forms like in ->>?

euccastro23:07:21

because unlike in ->> the names are bound in the body

euccastro23:07:18

you could say (loop [x 1 y 5] (if (= y 0) x (recur (dec y) (inc x))))

euccastro23:07:18

the "repetition" in the body of that defmacro is a choice by whoever wrote it, not a feature of loop

euccastro23:07:05

@bwstearns i.e., loop doesn't require, in general, that the initial values are bound to the same name in the enclosing scope. the first x is the name you want to use in the loop body, and the second x is the value you want to assign to it in the first iteration. the fact that both are the same symbol is arbitrary. the only thing special about this setup is that within the loop body the x bound in the argument list is not accessible. it is shadowed by the x in the loop bindings

euccastro23:07:52

sorry, I see @rwilson had already replied (I need to learn to use and pay attention to this thread feature in Slack)