Clojurians
#clojure
<
2017-01-13
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

qqq01:01:59

Input: a string output: for each character in the string, if it's in [a-zA-Z0-9] leave it as is; otherwise, convert it to _

qqq01:01:04

how do I solve the above?

sgrove01:01:52

Hey all, I’m clj-http is throwing an exception because the site I’m making a request against is returning a bad set-cookie header: MalformedCookieException Invalid 'expires' attribute: session org.apache.http.impl.cookie.BasicExpiresHandler.parse (BasicExpiresHandler.java:63)

sgrove01:01:52

I’ve been looking around the web and in the code, and I don’t see any clear way to get clj-http/apache HTTP client to just silently store the malformed cookie value (I only need to make two requests, I don’t care about the cookie expiry date)

qqq01:01:07

(clojure.string/replace "some%url info%%23" #"[^a-zA-Z0-9]" (fn [& rst] "_")) ^^ @williewillus : good suggestion; I think this works; any suggested changes?

qqq01:01:17

the one func call per char is ab it annoying, but not sure how to get rid of it

williewillus01:01:59

the function isn't necessary I don't think?

qqq01:01:11

@williewillus how would ou do it instead?

williewillus01:01:14

user=> (clojure.string/replace "abcABC123$%^" #"[a-zA-Z0-9]" "_")
"_________$%^"

qqq01:01:43

in cljs, to get the string namespace, do I import "clojure.string" ?

seancorfield02:01:46

@sgrove do you have :throw-exceptions false in your clj-http call? (edited to remove ? — oops)

seancorfield02:01:21

I see invalid Expires format warnings from the Apache http client library (interacting with PayPal) but I don’t get exceptions.

qqq03:01:13

this appears to work, so I'm double checking for sanity: is :foo/bar a perfectly keyword? is there anything I should be aware of?

bfabry05:01:19

:foo/bar is a perfectly reasonable keyword with a namespace of foo and a name of bar

qqq05:01:14

@bfabry: you mean it's perfectly vaild for src/fruits/apple.clj to define a keyword :foo/bar ?

qqq05:01:22

or tthat it's valid if it's in src/foo.clj

bfabry05:01:24

it can be defined wherever, it is the keyword :foo/bar with a namespace of foo and a name of bar, if you were in the namespace foo you could refer to it simply as ::bar and if you were in a namespace that aliased the namespace foo to the name baz you could refer to it as ::baz/bar

bfabry05:01:56

but :foo/bar, the fully qualified form, will mean the same thing no matter where you write it :slightly_smiling_face:

qqq05:01:46

@bfabry: so src/foo.clj's ::bar == src/fruits/apple.clj's :foo/bar ?

qqq05:01:55

where can I read up more on this because I clearly do not understand keywords

bfabry05:01:18

you likely understand keywords perfectly well and it's not something to be concerned about, you probably just haven't learned about namespaced keywords yet, which is what happens when you start adding slashes. but yes, src/foo.clj's ::bar == apple.clj's :foo/bar

qqq05:01:57

is there anything more to 'namespaced keywords' other than src/foo.clj's ::blah = :foo/blah from anywhere else?

bfabry05:01:03

there's also aliases, so if foo.clj aliases the namespace apple to the name banana then foo.clj's ::banana/bar == :apple/bar

bfabry05:01:51

very brief rules of namespaced keywords. https://clojure.org/reference/reader#_literals but there's also been a whole heap of useful syntax for working with them added in clj 1.9 in terms of destructuring. if you're on 1.9 and want to learn more then I'd dive into the spec documentation and the 1.9 alpha release notes. if not then the information on the reader literals page is really all you need to know

qqq05:01:12

@bfabry: thanks!

nidu06:01:10

Hello. I have a small question about web apps with websockets. For example if you need websockets and decide to go with sente, do you use sente for all you communication of use sente only when it's really applicable (e.g. norifications) and use clj-http (of similar) for everything else? I wonder what may be the drawbacks of going full sente

zentrope06:01:37

nidu: It's up to you. I use websockets only for a lot of small, UI projects.

zentrope06:01:35

@nidu: But I could imagine you'd want to use http posts if your service supports a general API, or if you have two separate servers, one for the API, and another for notifications. Maybe depends a bit on your scaling needs?

nidu06:01:25

@zentrope you're right. API is intended to be used only by application (and media is transit which is not very friendly for public i guess)

nidu06:01:55

but new clients may appear in future

zentrope06:01:02

@nidu You could also put the actual decision behind a module/namespace facade and just re-implement it if you have to change.

zentrope06:01:08

One nice thing about a web socket is that it's persistent, so you just have to auth it once.

nidu06:01:24

@zentrope agree though it sounds like a redundant layer, especially taking into account that sente may work over traditional http with polling as well

zentrope06:01:28

I just mean something like comm.cljs, then you have a (create-comm) which returns an opague value, then (comm/send-whatever comm) and (comm/get-other-thing comm).

zentrope06:01:51

"comm" itself could be sente stuff, or just an HTTP endpoint, as far as the rest of your code is concerned.

nidu06:01:39

@zentrope agree about that. One issue i found is that one may start to rely on connection lifecycle which complicates code a lot. Yeah, maybe i'm just trying to run away from inherent problems :smile:

nidu06:01:29

@zentrope yeap, you're right!

zentrope06:01:03

You could even create a comm-layer protocol if you wanted to get fancy. ;) Might even facilitate testing.

nidu07:01:34

@zentrope could you explain it a bit?

zentrope07:01:56

You make a protocol (defprotocol MyComm (get-products [...]) (save-login [...])) etc, etc, then implement it using Sente (say).

zentrope07:01:18

Your code just does the (comm/save-login comm "user" "pass").

zentrope07:01:37

But for testing, you can re-implement the protocol so that you don't have to have an actual server on the other side.

zentrope07:01:38

(defrecord MockServer (get-products [_] [{:id 1 :name "Chips"}]) ....) and so on.

zentrope07:01:18

I don't know if it's worth it, but it's a thing you could do.

zentrope07:01:43

The .read method returns -1 when there's no more bytes to read, so you could loop until n = -1.

zentrope07:01:34

@danielgrosse Also, http://clojure.java.io has a copy function that might work.

nidu07:01:19

@zentrope oh, you mean clojure protocol. I thought you meant some communication protocol :smile:

qqq08:01:58

I need to make ajax calls from cljs to clj; I am considering tusing cljs-ajax; anyone have comments/sugestions ?

dominicm08:01:15

@qqq I've used cljs-http on projects which might also be worthwhile looking at

mavbozo08:01:12

@qqq I try goog.net.XhrIo first which is provided by closure library http://www.closurecheatsheet.com/net

blackawa08:01:40

@qqq I also prefer to use goog.net.XhrIo. This is enough if you want simple ajax client.

dominicm10:01:44

@gfredericks https://github.com/gfredericks/debug-repl is it possible to use this for web requests instead of only breakpoints inside a repl eval?

dominicm11:01:58

I tried with no success, wondering if there's a secret incantation I need though

gfredericks12:01:42

@dominicm in theory it's definitely possible

gfredericks12:01:56

I've wanted to do that before

dominicm12:01:16

@gfredericks might prompt you: I got an NPE when I tried.

gfredericks12:01:47

a big difficulty is that your repl is not doing anything when you make that request

gfredericks12:01:55

so it's not expecting anything to happen

dominicm12:01:28

I guess you'd need the break! to use a known session, and then have your repl client run inside that session?

gfredericks12:01:51

do you mean http session or nrepl session?

dominicm12:01:55

nREPL session

gfredericks12:01:32

I bet you could wire up something where

gfredericks12:01:38

you do a two step thing

gfredericks12:01:10

1) call a function in your repl that blocks, sitting around watching some global queue waiting for functions to execute

gfredericks12:01:35

2) make the web request, which hits a high-level middleware that submits the request to that global queue and waits for the response

gfredericks12:01:51

so you have a middleware that redirects the request to be executed by your repl thread

gfredericks12:01:54

I could cobble together a prototype of that if that'd be helpful

dominicm12:01:09

That's a very easy way to connect them. Does debug-repl not operate within a particular session then?

gfredericks12:01:22

it's very involved in nrepl sessions

dominicm12:01:39

ah, okay. Wasn't sure how the implementation would work.

gfredericks12:01:39

I'm not sure exactly what you're imagining so can't answer your question directly

gfredericks12:01:54

but I think you could do what I'm describing without knowing much about how debug-repl works

dominicm12:01:02

No, that's okay. I figured it was either one or another.

gfredericks12:01:21

the only thing you have to know is that ./break! only works if your repl's thread is calling it

dominicm12:01:37

That would be great. I'm happy to round it off & such, but you'd likely be quicker at putting it together than I. But if you're short on time, I can give it a go.

gfredericks12:01:58

I have a bit, I'll give it a try

gfredericks12:01:30

@dominicm I added the can-break? function so that requests don't break when the repl isn't intercepting them; so you'd just have to wrap your break! calls in that check

gfredericks12:01:02

I could imagine debug-repl having a break!? macro or something of that sort so you wouldn't have to worry about it

gfredericks12:01:26

oh I'm having trouble breaking out of the intercept call

gfredericks12:01:26

I'll modify it to quit if it doesn't get a request in 10 seconds

dominicm12:01:34

@gfredericks I'll give it a spin soon

gfredericks12:01:07

pushed up that change; good luck with it

kevinbheda13:01:22

is there a way to run the same deftest with different test data ? like junit parameterized test

shooodooken13:01:32

@kevinbheda have used something like this before

(deftest equal-to-five-test
  (dorun (map #(is (= 5 %))
              [1 2 3 4 5])))
Ran 1 test containing 5 assertions. 4 failures, 0 errors.

gfredericks14:01:05

are is good sometimes

martinklepsch14:01:42

Anyone some go-to libraries to suggest for object pools?

martinklepsch14:01:01

Currently looking at ztellman/dirigiste and apache commons pool

lmergen14:01:33

we're using dirigeste for this, and are very happy with it

martinklepsch15:01:45

@lmergen if you don’t mind a quick question about it: my objects don’t have a defined key/id, most of the usage will just be “get me one from the pool”. With dirigiste it seems I need to provide the key but I don’t see a way to get a list of available keys or similar which makes it a bit harder for me to see how I would support my kind of usage...

martinklepsch15:01:27

Do all of your objects have an id?

lmergen15:01:25

I think so yes. It might be because of the way that dirigeste is instrumented, and collects data about this pool

lmergen15:01:47

In our case, all our objects have ids yes. Don't forget, dirigeste used to be called Lamina's "executor". Which might explain why it's not really suitable for a connection pool. It's meant more as a way of distributing work.

martinklepsch15:01:55

@lmergen may I ask what kind of objects you’re managing? My objects aren’t connections but resources that need to be prepared in order to complete some process. Maybe this is closer to a connection than it is to what dirigiste had in mind

lmergen16:01:18

did you see that dirigeste allows multiple objects per key ?

lmergen16:01:33

it's more or less meant to group different resource types

lmergen16:01:53

so you can choose to have a single key "db1"

lmergen16:01:20

in our case, we're moving work from one bucket to another, etc

martinklepsch16:01:22

I think I got confused by the fact that the generator also gets a key. But it seems that that is mostly a means to support some kind of polymorphism for the generator function(?)

nikki18:01:42

is it part of the idea to have clojure.specs for basic things in the language itself

nikki18:01:00

one of the projects i want to get at later is a GUI place to edit clojure code, and it could give you suggestions etc. based on the specs of things

nikki18:01:34

this could be nice for like (if <cond> <then> <else>) if that autofills or is checked when you drag an if block in

nikki18:01:55

is nice if that comes from inherent-in-the-lang stuff rather than adding some accidental extra description for the editor

dominicm19:01:08

@gfredericks I had a play with your implementation, worked mostly well. unbreak! seemed to not work wthout causing an NPE, but that might be a mistake on my part. I think you were quick to tie it to http though. This pattern worked inside the handler itself (although, maybe this is why it NPE'd?):

(when-let [e com.gfredericks.debug-repl.http-intercept/the-executor]
  (e #(com.gfredericks.debug-repl/break!)))

dominicm19:01:58

This could probably be part of the core debug-repl namespace with some kind of function which is essentially http-intercept and break/unbreak always tried to execute within the executor if possible.

gfredericks20:01:53

@dominicm unbreak definitely worked for me

dominicm20:01:38

@gfredericks just hooked up your middleware, it worked. But I got an NPE if I hadn't already run intercept-http! in vim

alexmiller21:01:46

@nikki yes, there will be specs for many of the core macros/fns

gfredericks21:01:11

@dominicm did you wrap the break call with the check I included?

dominicm21:01:17

@gfredericks I only wrapped it with the code I pasted above ^^ did I miss a bit?

dominicm21:01:15

@gfredericks I basically tried to decouple wrap-http-intercept from being a ring middleware. So it could theoretically work with any block of code (I tend to work on projects with a lot of background tasks for example)

gfredericks21:01:05

okay so you want to pack all of the work into break!, which I think makes sense and is certainly easier

gfredericks21:01:34

if that works then it has nothing to do with http or middleware, and would fit a lot better in the core library

dominicm21:01:19

It almost worked, just caused the unbreak! to NPE for some reason I can't quite figure out why.

dominicm21:01:41

I think the msg was missing or maybe t I guess

gfredericks21:01:17

I'm trying it out now

gfredericks21:01:49

oh yeah I made a boog

dominicm21:01:48

Yeah, works fine when the break! is nested within another layer of function. But it looks like you've figured it out :stuck_out_tongue:

gfredericks21:01:19

yep I got it now; I think this could definitely be a new feature

richiardiandrea21:01:27

maybe I am doing it wrong, but is there a function like merge-with that does notify even when there is no key clash?

gfredericks21:01:19

@dominicm I pushed up a fixed version with a special break!; I think the biggest improvement would be to figure out how to make it respond to C-c

dominicm21:01:37

@gfredericks I actually use vim. :smile: multi-editorial here.

dominicm21:01:42

What action is C-c bound to?

gfredericks21:01:38

oh um I don't know

gfredericks21:01:46

how do you interrupt an eval that hangs?

gfredericks21:01:00

if you're not capable of doing that normally then this wouldn't be an issue for you :)

dominicm21:01:19

I \tear\ cannot. If I do that, my editor is stuck like that. Currently discussing with people how to take advantage of the interruptible eval op, but it's part of a big rewrite of fireplace.

gfredericks21:01:02

okay; I won't worry about that unless this gets pushed into core debug-repl

dominicm21:01:17

I think the 10s-type thing is a decent solution really.

dominicm21:01:34

I don't see anything new pushed up to the http-intercept branch.

gfredericks22:01:07

Um. I'll check

gfredericks22:01:24

okay there it is, sorry

dominicm22:01:48

That's no problem, I was just confused :slightly_smiling_face:. Testing now.

dominicm22:01:09

@gfredericks this is absolutely awesome.

dominicm22:01:49

@gfredericks this works really well, already have some bindings set up to quickly insert breakpoints and such. Thanks for this.

gfredericks22:01:10

np, glad it worked out

dominicm22:01:55

@gfredericks completion even works, this is literally going to be a massive productivity boost for me. Can't thank you enough.

gfredericks23:01:01

like vim autocompletes locals or something?

dominicm23:01:31

@gfredericks My vim completion plugin doesn't, normally. I haven't added contextual awareness yet, it's on the todo. I think your method must but the bindings into "global" scope as far as completion is concerned.

gfredericks23:01:34

It's just regular let bindings. Maybe normal evals in your workflow never have those in place