Fork me on GitHub
#clojure
<
2016-09-27
>
dadair02:09:43

Hi, I’m trying to specify a lib’s fn as a config value in an edn-based configuration (duct-framework). I’m successfully able to specify vars directly in the map, such as {:components {:app duct.component.handler/handler-component}}, but one specific var (`fixtures.adapters.jdbc/jdbc-adapter`) returns a no class found exception. However, I’m able to use that var if I do the following in the REPL: (require ‘[fixtures.adapters.jdbc]) (fixtures.adapters.jdbc/jdbc-adapter). I haven’t had to specifically require other vars in the map. Does anyone know why this one var would have an issue?

dadair04:09:38

found a solution 😄

ul06:09:43

Hi! What is the best way in Clojure to have atom with overridden IDeref implementation? Like what I achieve by ClojureScript's specify!:

(defn wrap-atom [x & m]
  (specify! (apply atom x m)
    IDeref
    (-deref [this] ...)))

niwinz06:09:40

Creating a new type (with deftype or reify) that wraps your atom, and implement all atom methods...

niwinz06:09:02

no specify! like functionality is available in clj as fas as I know

ul06:09:12

Thanks, reimplementing all stuff is the thing I wanted to avoid, but if it's not possible I'll do...

bfabry06:09:12

@ul you could possibly extend clojure.lang.Atom using proxy so that you only need to override the one specific method. I've not actually tried doing that though so y'know

ul07:09:15

Sadly it fails with CompilerException java.lang.VerifyError: Cannot inherit from final class

bfabry07:09:31

doh, yes that would be a problem

dominicm09:09:32

@currentoor Just an fyi, you can put hiccup into html mode to get the exact behaviour you want, e.g:

boot.user=> (html {:mode :html} [:script {:src "demo_async.js" :async true}])
"<script async src=\"demo_async.js\"></script>"

witek11:09:48

Hi. Does Clojure include a Clojure parser? One which converts a Clojure file in a data structure which can be analysed? The data structure needs to be complete, which means it needs to have all the used whitespace characters and comments. So that the originally parsed source file can be restored exactly as it was. Is there something like this included in Clojure oder do I have to look for libraries?

witek11:09:19

@rarous Do you mean the read-string function from tools.reader? Or is there anything else included which would provide me the desired behavior?

witek11:09:18

Because (read-string (1, 2)) provides (1 2). But I need a data structure which gives me information what was parsed and also the , separator I have used...

reefersleep11:09:10

Do you need to analyze the whitespace and comments?

reefersleep11:09:25

I would guess that most of the parser functionality you'll find will ignore stuff like that. If you need to "restore" the originally parsed source file, can you not just persist the source itself? 🙂

witek11:09:46

I need to read a Clojure file, make some changes and then write back the whole file. For doing the changes I need a parser which understands EDN. But it must preserve the file layout, which includes all the whitespacing an comments. All the readers I found so far loose all the file layout 😞

witek11:09:22

Input: (1, 2) ;; test. Desired output (something like this): [{:type :list :elements [{:type :number :value 1} {:type :whitespace :value ", "} {:type :number :value 2}]} {:type :whitespace :value ";; test"}]

witek11:09:04

@dominicm Exactly! Thank you!

dominicm11:09:45

There's also https://github.com/rundis/rewrite-cljs which has less features. Depends on the environment you're in. 🙂

pesterhazy12:09:17

Q about naming conventions: a common recommendation is to call fns the noun they represent. However, if I call the fn that returns a product (defn product []), what do I call the let bindings that I assign products to?

pesterhazy12:09:41

- product: shadowing, dangerous when refactoring, surprising bugs - product*: works but strange - prdct (intentional misspelling): even stranger - a-product: I guess that works but I feel a bit uneasy

pesterhazy12:09:17

which way out of this dilemma (quadrilemma) do you prefer?

slipset12:09:48

I just really wish he would finish his frontend-server https://www.youtube.com/watch?v=_1rh_s1WmRA, so he could finish up the book, I’m so looking forward to the next chapters 🙂

slipset12:09:13

@pesterhazy from your (minimal) example, I do believe @ztellman would say that if your product function pulls data from another scope (like a database) it should be called get-product (or if defined in a foo/bar/baz/product namespace, just get)

slipset12:09:35

if it on the other hand converts something to a product, it should be called ->product

slipset12:09:26

@pesterhazy but the whole first chapter, which is on the topic of naming, is downloadable for free.

misha13:09:07

@pesterhazy p? if let is not that huge, that works most of the time for me. (and products would be pp) on the other hand I'm not entirely comfortable having a product function in the first place.

dominicm13:09:35

I think convention is [shorthand]s for a sequence of things, so ps would perhaps be more idiomatic there @misha

dominicm13:09:48

I also second Elements of Clojure!

misha13:09:27

@dominicm true, however I find myself stumble upon xs a lot, and xx goes much smother. but I'd say "follow project's existing style guide, unless it is outrageous"; and in your private repo no one will hear you scream

dominicm13:09:14

@misha I don't understand what you mean by: > stumble upon xs a lot and xx goes much smoother

misha13:09:24

it takes me longer (than xx) to realize xs - is a collection, when I read code

dominicm13:09:48

Ah. I see. Worth learning xs for the clojure.core code though.

misha13:09:15

that is true as well

pesterhazy14:09:37

@slipset, I did read (and liked) the first chapter of the @ztellman book, but you still run into issues with naming clashes

pesterhazy14:09:11

so the solution would be not to use simple nouns as fns?

pesterhazy14:09:44

interesting...

josh_tackett19:09:19

https://github.com/dakrone/clj-http Is there a way with this library to view the request that is being made? I am making a request successfully in postman but the same request with this library isn’t working

dunn.mat19:09:24

@josh_tackett If the library doesn’t support it, you could always look at the requests using something like wireshark

josh_tackett19:09:42

@dunn.mat that’s a good point

josh_tackett19:09:52

I’m just trying to figure out the difference between postman and this lib

josh_tackett19:09:55

postman works well

josh_tackett19:09:58

but the lib doesn't

dpsutton19:09:26

i want to say postman does some hackery to work around CORS things so it won't be doing the same request in both instances

josh_tackett19:09:34

postman:
GET /sap/c4c/odata/v1/c4codata/ HTTP/1.1
Host: 
Authorization: Basic <user>:<pass>
x-csrf-token: fetch
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 2381b22d-8330-040d-139c-3fb4fd31deb8

dpsutton19:09:03

i had a vagrant machine running a service that postman was hitting but i couldn't hit from my local machine because of CORS. Is there any way to check the response? My suspicion is the error message might be instructive

josh_tackett19:09:10

(http/request
                          {:method :get
                           :url (str "")
                           :headers {"Authorization" (str "Basic " (base64/encode “<user>:<pass>"))
                                     "x-csrf-token" "fetch"
                                     "Content-Type" "application/json"}
                           })

dpsutton19:09:39

Cross-Origin Resource Sharing

dpsutton19:09:53

can you curl the endpoint? it should more easily show the error

josh_tackett19:09:25

@dpsutton there is no error, postman works

josh_tackett19:09:33

just a difference between my request and postman

josh_tackett19:09:47

{:user-info nil,
 :use-header-maps-in-response? true,
 :body-type nil,
 :debug true,
 :headers
 {"Content-Type" "application/json",
  "x-csrf-token" "fetch",
  "Authorization" "Basic QURNSU5JU1RSQVRJT04wMTpXZWxjb21lMQ==",
  "accept-encoding" "gzip, deflate"},
 :server-port nil,
 :http-url
 "",
 :uri "/sap/c4c/odata/v1/c4codata/",
 :server-name "",
 :query-string nil,
 :body nil,
 :scheme :https,
 :request-method :get}

dpsutton19:09:54

you said its not working in clojure, right?

josh_tackett19:09:57

GET /sap/c4c/odata/v1/c4codata/ HTTP/1.1
Host: 
Authorization: Basic QURNSU5JU1RSQVRJT04wMTpXZWxjb21lMQ==
x-csrf-token: fetch
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 2381b22d-8330-040d-139c-3fb4fd31deb8

josh_tackett19:09:24

/sap/c4c/odata/v1/c4codata/ HTTP/1.1

josh_tackett19:09:30

must be this extra HTTP/1.1

josh_tackett19:09:19

not sure how to get that into a request those with clj-http

richiardiandrea19:09:09

Hello folks, does anybody know if there is a lib out there using log4j2 as logger already?

bfabry19:09:13

I actually think I've had a surprising thing where it turned out postman was using cookies and I didn't realise it before

richiardiandrea19:09:56

Might be worth adding it to clojure.logging maybe

bfabry19:09:06

tried using this stuff https://github.com/dakrone/clj-http/blob/master/README.org#basic-auth instead of rolling your own basic auth params?

jr19:09:45

what’s the response code of cljs-ajax request?

josh_tackett19:09:10

@bfabry they don’t use basic auth though

josh_tackett19:09:30

they use a base 64 encoded request

josh_tackett19:09:06

@bfabry any way to add the HTTP/1.1 at the end of the url?

josh_tackett19:09:09

I think that’s my issue here

josh_tackett19:09:17

its the difference between the requests

bfabry19:09:47

I'd be surprised if it was, that's just the normal get request scheme afaik, clj-http should be sending it the same

josh_tackett19:09:43

{:requestLine
 #<BasicRequestLine GET https://my307174.crm.ondemand.com/sap/c4c/odata/v1/c4codata/ HTTP/1.1>,
 :protocolVersion #<HttpVersion HTTP/1.1>,
 :params
 #<BasicHttpParams [email protected]>,
 :method "GET",
 :config nil,
 :class org.apache.http.client.methods.HttpGet,
 :allHeaders
 [#<BasicHeader Connection: close>,
  #<BasicHeader Content-Type: application/json>,
  #<BasicHeader x-csrf-token: fetch>,
  #<BasicHeader Authorization: Basic <user:pass>>,
  #<BasicHeader accept-encoding: gzip, deflate>],
 :aborted false,
 :URI
 #<URI https://my307174.crm.ondemand.com/sap/c4c/odata/v1/c4codata/>}

josh_tackett19:09:50

Ah you’re right it is sending it that way

josh_tackett19:09:13

it is getting a response, but the token is not valid to do a write

josh_tackett19:09:10

this doesn’t make any sense

josh_tackett19:09:22

post man is working and clj-http is not

josh_tackett19:09:26

and the requests look the same

jr19:09:28

what’s the response code?

josh_tackett19:09:23

@jr response looks good

josh_tackett19:09:27

it’s XML though

bfabry19:09:02

fwiw, my guess is still that postman is sending an auth'd cookie

josh_tackett19:09:21

@bfabry how do you test that?

bfabry19:09:04

try the postman request from an incognito window

josh_tackett19:09:25

@bfabry Postman doesn’t have incognito

josh_tackett19:09:31

I just have the app downloaded

bfabry19:09:48

oh not the chrome extension

bfabry19:09:55

I've never used the app sorry =/

josh_tackett19:09:17

@bfabry do you know how to send a curl request from clojure

bfabry19:09:57

no, that'd be a cool tool though, something that translated clj-http requests into a curl request line

dpsutton19:09:51

i've used it before and postman will go out of its way to make requests succeed

dpsutton19:09:07

so i would agree with bfabry that the requests are not the same

dpsutton19:09:12

do a curl from command line

dpsutton19:09:38

wait, what's the problem?

dpsutton19:09:50

that xml is in your code. does that mean success? everything has worked?

dpsutton19:09:54

what are you expecting back?

josh_tackett19:09:31

I am getting a successful response. Then when I try to use the toke from the reponse to make a write request, I get a 403 @dpsutton

dpsutton19:09:52

and you can successfully reuse the token from postman to make a write request?

josh_tackett19:09:25

and even if I take the token from the GET in clojure and use it for the write POST in postman, it doesn’t work

dpsutton19:09:36

is it possible it is deserializing the token incorrectly? perhaps when stringifying it or turning it into the map with keys, it is incorrectly doing something with the key?

dpsutton19:09:54

also, when making the write request with the token from clojure but sending the request from postman, what was the response? how did you know that it did not work?

josh_tackett19:09:46

@dpsutton is it possible it is deserializing the token incorrectly? perhaps when stringifying it or turning it into the map with keys, it is incorrectly doing something with the key? I bet this is the problem!!! also, when making the write request with the token from clojure but sending the request from postman, what was the response? how did you know that it did not work? I got a 403

josh_tackett19:09:18

I bet the response is reading the token incorrectly

josh_tackett19:09:36

now the question is how to get the write one

dpsutton19:09:38

can you ask for the raw response?

dpsutton19:09:48

i think if you don't pass true to the request, it won't turn it into a map

dpsutton19:09:55

it'll just return the json string? or is that cheshire

josh_tackett19:09:08

pass true where?

bfabry19:09:08

that's cheshire

josh_tackett19:09:17

ya cheshire is for JSON

dpsutton19:09:28

yeah i was mistaken. hmm.

dpsutton19:09:37

will the service return the same token ever?

dpsutton19:09:51

like if you ask for the token from both clj and postman, would it show the same token?

dpsutton19:09:57

then you could compare the deserialization

josh_tackett19:09:10

so postman keeps sending back the same token

josh_tackett19:09:19

but clj is a different token everytime

dpsutton19:09:31

hmmmm. weird that there's difference results

josh_tackett19:09:31

4kesF5SwynJXyrrFMFsRdw==

josh_tackett19:09:42

4kesF5SwynJXyrrFMFsRdw==

josh_tackett19:09:45

yep postman there

josh_tackett19:09:53

WiH7ebper13BBPhCJQripg==

josh_tackett19:09:01

FJJmv1wuyca_mp123Mc2YA==

josh_tackett19:09:08

changes every time for clj

dpsutton19:09:18

yeah that sounds like what bfabry was saying

bfabry19:09:18

postman is sending a cookie, sure of it

dpsutton19:09:21

there's a cookie in there

josh_tackett19:09:38

how can I view that cookie?

dpsutton19:09:57

ostman v0.8.x can display browser cookies as it shares the same environment with the browser. For the packaged app, you’ll need to enable the Interceptor. You can then view response cookies in the “Cookies” tab of the response section. Refer to the sandbox documentation for info on how to access cookies in the pre-request/test scripts

dpsutton19:09:55

maybe view the raw response and see if there's something there as well

josh_tackett19:09:40

alright one sec

bfabry19:09:46

I don't know because this annoying stuff is why I stopped using postman 🙂

josh_tackett19:09:06

ah found some cookies…yum

josh_tackett19:09:21

where did these cookies come from though?

dpsutton19:09:10

initial request no doubt

dpsutton19:09:19

you authorize, get the token and then keep using the cookie?

josh_tackett19:09:40

but obv Postman is doing this on its own

josh_tackett19:09:46

so I need to do the same in clj

josh_tackett19:09:17

ok found the cookies

josh_tackett19:09:26

how do you add cookies to an http request?

josh_tackett19:09:23

let me give this a shot

dpsutton19:09:47

use a cookie store to store your cookies! of course haha

josh_tackett19:09:09

I’ve never really dealt with cookies

josh_tackett19:09:23

I’ll need to read about that bit myself before I ask you guys

bfabry19:09:57

I would humbly suggest cookies aren't generally considered a good way to interact with an api, so unless you're forced to use them I would try not to

josh_tackett19:09:37

@bfabry I am dealing with SAP and it seems that cookies are the only option right now haha

josh_tackett19:09:44

I just need to do a POC here

josh_tackett19:09:52

will pound out the production system after we get POC

bfabry19:09:53

oh gooooood sap? I'm out

josh_tackett19:09:06

great work guys

josh_tackett19:09:12

I really appreciate the help

josh_tackett19:09:17

time to pipe this baby through the system

josh_tackett19:09:27

@bfabry @dpsutton Thank you both, great work

dpsutton19:09:53

for sure! glad you got it working

jfntn20:09:54

hmm first time I run into this:

(-> (into (sorted-map) {1 1})
    (get :foo)) ;; ClassCastException java.lang.Long cannot be cast to clojure.lang.Keyword

bfabry20:09:20

that is surprising. I guess you can't have a sorted map of things are are incomparable so you can't look in a sorted map for a thing that could not be in it

jfntn20:09:43

precisely my use-case

kenny21:09:51

Shouldn't setting *print-namespace-maps* to true cause namespaced maps to print without the reader shorthand or am I misunderstanding how *print-namespace-maps* should work? This is in a vanilla Clojure REPL

Clojure 1.9.0-alpha13
user=> (binding [*print-namespace-maps* true] 
  {:db/id 1 :db/ident :foo/bar})
#:db{:id 1, :ident :foo/bar}
I want it to print:
{:db/id 1 :db/ident :foo/bar}

idiomancy22:09:23

okay, so im back to the ongoing task of wrapping my head around channel logic. I am again running into a situation where I feel like I would be well served by a "closed?" function. But I am vaguely aware that this is a frowned upon concept, because querying a channels open/closed state leads to bad design. However, there's this concept of a "timeout" channel in the api, which automatically closes after n milliseconds. How else would one use such a construct other than by querying whether or not the channel has yet closed? This is very relevant to what im currently doing: forwarding data from a socket connection with a timeout.

idiomancy22:09:30

tl;dr how do you use (timeout)?

jr22:09:45

I usually only use timeouts for a recur break or within an alts! clause

jr22:09:29

so either recur on this go-loop after N seconds or take the result of an async operation before N seconds or bail

idiomancy22:09:57

never used alts before

idiomancy22:09:21

so its like a load balancer?

jr22:09:08

it’s just a way to force an async operation to bail after a timeout has exceeded. I’m not sure what you mean like a load balancer

idiomancy22:09:45

im trying to figure out what alts does in general in order to figure out how you used it to implement a "bail after n milliseconds" situation

idiomancy22:09:03

if you want to just share with me some psuedocode on how you did that, i could also study it that way

idiomancy22:09:34

i just have never seen or used alts before, so im trying to catch up, lol

jr22:09:57

(let [[ch result] (alts! [channel-receiving-async-io (timeout 2000)])
  (do-something-with result))

jr22:09:14

that ensures that channel-receiving-async-io does not exceed timeout and if it does then will contiue computing

idiomancy22:09:59

because the value "nil" will be put on the returned channel of timeout

jr22:09:16

yeah and you can compare the returned ch with the timeout return value if you want

idiomancy22:09:23

and that will be the first to trigger the alt statement

idiomancy22:09:26

thats really cool

jr22:09:33

yeah exactly

idiomancy22:09:47

so alts is a race between channels to see who produces the first value

bfabry22:09:00

ya, that's why you don't need to check if it's closed?, in any place you're using it you're using blocking waiting for either it or something else

jr22:09:03

timeouts are a good way to not saturate a go routine and prevent it from context switching

idiomancy22:09:17

thats very cool

idiomancy22:09:08

thanks a bunch. thats excellent. Yeah, with the addition of alts to my repertoire, I can definitely see how polling status is not the best plan

jr22:09:57

Think of it more as a pipeline and when you try operating on a closed channel then nothing will be produced

jr22:09:43

channels are meant to be composed so when the pipeline stops, then processing will stop

jr22:09:53

without having to worry about the state of a particular channel

idiomancy22:09:05

yeah, thats how I sort of think about it, but then I saw another person in this thread https://groups.google.com/forum/#!topic/clojure/_KzEoq0XcHQ suggesting that operating on a closed channel was a programming error. which seemed incompatible with the idea that the producer is in charge of closing the channel

idiomancy22:09:12

and I got all confused

idiomancy22:09:21

and thought I'd come ask you guys

idiomancy22:09:13

ehh, actually, I see what he meant now, though

jr22:09:36

most core.async functions will “magically” stop producing when a channel is closed

jr22:09:50

so if you stick to the core functions and compose them then you will not receive a nil value from the channel

jr22:09:55

the consumer will just park until something is produced

idiomancy22:09:12

but isnt that what "alts" is depending on?

idiomancy22:09:24

the timeout function actually returning a value?

jr22:09:32

if you need to write a custom producer then watching for nil is an essential part of it

jr22:09:40

usually you won’t need to write a producer

jr22:09:07

I don’t look at the return value of alts! just the channel that was actually taken from

jr22:09:28

(in the case of timeout)

idiomancy22:09:04

interesting. ill toy around with it a bit to try to flesh out that philosophy in my head a bit more

jr22:09:20

examples are definitely easier to wrap your head around

idiomancy22:09:30

thanks for the help. Its super awesome of you to lend a hand. You too, @bfabry !

jr22:09:53

but generally if you’re sniffing for a nil coming through a channel (or want to know if it is closed) then you are using the wrong core.async functions

idiomancy22:09:13

makes sense. good to have that code smell handy

bcbradley22:09:21

hey guys i made a little function i kind of proud of

idiomancy22:09:44

lets see it!

bcbradley22:09:48

how do i upload code?

idiomancy22:09:01

begin and end your code block with `

jr22:09:01

github gist

jr22:09:15

depends on how long it is

idiomancy22:09:58

very cool! I like this a lot

idiomancy22:09:04

I will actually probably use this in some work I'm doing with directed graphs, actually, if you dont mind, @bcbradley

bcbradley22:09:16

sure go ahead

bcbradley22:09:30

i'm eventually gonna build a library out of this and a few other things i've got cooking

bcbradley22:09:46

i'm using it to order functions that depend on eachother

idiomancy22:09:03

yeah, thats what i'd be using it for too

bcbradley22:09:14

then taking those in the sets (those that don't depend on eachother at that stage in the pipeline) and exeucting them concurrently

bcbradley22:09:25

try it with this if you wanna see it in action: (organizer {1 #{2} 2 #{4 3}} [1 2 3 4])

idiomancy22:09:52

ahh, yes interesting. My use is actually in reactive programming. so, when a value changes, all values that depend on it are updated

bcbradley22:09:05

hey thats pretty cool

bcbradley22:09:09

let me know how it goes

idiomancy23:09:23

so @jr going back to the earlier stuff, how would i express the following idea: do this forever until in-chan closes: (>! out-chan (<! in-chan))

idiomancy23:09:42

heres what is going on here. I get stuff from socket a, and i put it into socket b until socket b gives me a response, then i take that response and put it in socket a

idiomancy23:09:03

bail on the above after a certain period

idiomancy23:09:40

so, its like

"connect returns two channels for input and output"
(let [[a-in a-out] (connect "a-host" "a-port")
      [b-in b-out] (connect "b-host" "b-port")]
  (go (>! a-out (alts! (timeout 1000) b-out (go-forever (>! b-in (<! a-in)))))))

idiomancy23:09:14

the imperitive description is "if we get a response from b, put that on a. if we timeout, put that on a. otherwise, keep putting stuff that shows up on a into b"

idiomancy23:09:16

but i think in the above scenario, doesnt this make that go-block run forever, even after the alt has completed? unless I tell the go-forever block to poll whether or not the a-in channel is closed?

idiomancy23:09:18

or maybe i just test the returned value of the <! operation, because that operation returns nil if the channel is closed?

idiomancy23:09:02

I still dont understand the concept of writing a go block pipeline that automatically terminates when the producer closes the channel

idiomancy23:09:21

oh jaysus, theres the pipeline function

idiomancy23:09:26

and its various forms

idiomancy23:09:59

what I really need is a "core.async functions explained using factorio"