Fork me on GitHub
#clojure
<
2016-05-27
>
danburton02:05:56

What exactly are :exclusions in a clojure project dependency list? Is there a good blog post or document that explains it?

Alex Miller (Clojure team)02:05:45

@danburton they exclude transitive dependencies

Alex Miller (Clojure team)02:05:21

lein deps :tree will show you the tree

Alex Miller (Clojure team)02:05:43

exclusions let you chop parts of that tree (below the top)

Alex Miller (Clojure team)02:05:31

and searching for "maven dependency exclusion" should find you similar things if you can make the translation

danburton02:05:30

Exclude them from what? How can that dependency function if I cut off one of its dependencies?

Alex Miller (Clojure team)02:05:53

well two common reasons

Alex Miller (Clojure team)02:05:01

exclude from being part of your classpath

Alex Miller (Clojure team)02:05:17

sometimes two things you include both include different versions of the same dependency

Alex Miller (Clojure team)02:05:05

and then you need to iron that out - they will both be on your classpath, but the classpath is linear so one will shadow the other (and which that is is somewhat arbitrary)

Alex Miller (Clojure team)02:05:26

look up "lein pedantic" on how to have it detect these (potential) problems

Alex Miller (Clojure team)03:05:04

the second case is that a lib includes a dependency that you know you won't need - either because their deps are buggy, or you're not using the features that need that lib, or something else

vandr0iy07:05:13

hi, clojurians!

vandr0iy07:05:48

i wanted to ask you if there is an implementation of a map similar to json's concept. I need repeating keywords. Is this possible?

mccraigmccraig07:05:56

@vandr0iy: not sure i follow - how can a map have repeating keys ? what would getting from that map look like ?

vandr0iy07:05:03

I'd like to represent in memory an object - similar to json - that has a couple of repeating keys. Not exatly a map, though

mccraigmccraig07:05:40

@vandr0iy: if what you need is multiple values for a key, you can represent that with a vector of values for each key or similar

mccraigmccraig07:05:38

@vandr0iy: fnil can help make updating such a map easier - e.g. (update {} :key (fnil conj []) :val)

vandr0iy07:05:09

one more question:

vandr0iy07:05:21

is setting global read-only constant values a bad idea?

mccraigmccraig07:05:19

no, if they really are constants

vandr0iy07:05:24

for example: I find myself implementing a function that uses a particular array of values (it's a pattern of movement of a pawn in a game)

mccraigmccraig08:05:23

if they are pragmatic constants (i.e. they are helping you develop now, but are likely to become parameters later) then you could try and make as many of your functions as possible pure (i.e. take the values as params) and wrap them in a layer of impure functions which refer to the globals

vandr0iy08:05:30

They are fixed constants, that will never change. I'm implementing a challenge relative to chess, and I needed to save a couple of patterns in order to remember them and not reinstantiate them every time a function is fired (it's a combinatoric challenge, so it will happen very often and it has to eat as little memory as possible)

vandr0iy08:05:18

ex.: the knight steps

abdullahibra09:05:56

is there anybody tried flambo?

yogidevbear09:05:13

There is a #C0BV9GEN5 channel which you might find useful

edvorg13:05:50

Does anybody know where does tools.nrepl dependency comes from in leiningen projects? I removed it from profiles.clj and from project.clj but lein deps :tree still shows me tools.nrepl as it has been required on top level.

pesterhazy13:05:04

lein repl connects to the jvm process through an nrepl, doesn't it?

edvorg13:05:40

Yes, but where does does tools.nrepl appears from? Who pull it in?

edvorg13:05:33

Ah, so there is some tool.nrepl version that is shipped with leiningen.. Clear now. Thanks @pesterhazy

crimeminister13:05:35

@danboykis: I am porting a bunch of schema to spec right now to become familiar with it

crimeminister13:05:48

The experience so far has been nice!

danboykis14:05:41

@crimeminister: I am not sure how to structure my specs yet, this is a pretty large nested map (my config file is edn) and it's kind of a pain so for example

danboykis14:05:53

{:io {:http
       {:ignore-ssl-auth? true
        :pool {:socket-timeout 600000
               :conn-timeout 600000
               :conn-req-timeout 600000
               :max-total 500
               :max-per-route 500}}}}

danboykis14:05:24

that's not particularly fun to spec

crimeminister14:05:08

Probably easiest to start by creating a spec for each attribute (it's The Spec-ish Way)

crimeminister14:05:35

Then specs for each sub-collection

crimeminister14:05:03

And keep repeating that process until you reach the root

danboykis14:05:07

in this case they are all fairly generic the predicate is just integer?

danboykis14:05:27

yeah, I just wish I could do it declaratively

crimeminister14:05:44

Can always refine the specs to tighten them up

crimeminister14:05:16

I was in a similar boat

crimeminister14:05:40

Ended up creating a "core" namespace for shared attributes

crimeminister14:05:14

Most everything else was defined in nested namespaces reflecting the data structure being spec'ed

crimeminister14:05:46

Mainly because of the sheer volume of specs

crimeminister14:05:14

Wouldn't bother for a less hairy set of data types

crimeminister14:05:32

What do you mean by wishing it was declarative?

danboykis14:05:00

so right now this is how my spec'ing look like

danboykis14:05:20

(spec/keys :req-un [::io])
(spec/keys :req-un [::http])
(spec/keys :req-un [::pool] :opt [::ignore-ssl-auth?])
(spec/keys :req-un [::socket-timeout ::conn-timeout ::conn-req-timeout ::max-total ::max-per-route])

danboykis14:05:39

I wish I could say

{:socket-timeout integer?
 :conn-timeout integer?
 :conn-req-timeout integer?
 :max-total integer?
 :max-per-route integer?}

danboykis14:05:20

maybe it's because I am still getting used it

mpenet14:05:09

same experience here, it's very noisy, not especially readable atm

mpenet14:05:25

I guess it might change, or some libs could make it better

crimeminister14:05:56

The rationale document is worth a read if you haven't already

crimeminister14:05:28

It is reminiscent of Datomic

crimeminister14:05:49

I find that reassuring 😁

mpenet14:05:59

I dont 😆

crimeminister14:05:03

I have already started to adapt to the idea of using namespaced keywords

crimeminister14:05:23

Stick with it, you might like it!

mpenet14:05:24

Maybe it's also because I am still used to Schema a bit everywhere.

mpenet14:05:35

oh I dont mind namespaced kw

mpenet14:05:56

it's mostly the whole registry thing that feels like a smell imho

mpenet14:05:38

that + readability + a few other things. I might get used to it, we ll see.

viniciushana14:05:26

My take is that the resemblance that schemas bear with the actual maps is more appealing to the eyes - but I might be biased too due to being very used to schema

mpenet14:05:32

Schema also feels more "pure", it's just values you compose, no state (arguably declaring type could be considered as such, at least compared to putting stuff in a registry)

crimeminister14:05:08

Interesting, as a Datomic user it felt quite comfortable right away to me

viniciushana14:05:49

That’s interesting - Datomic user here too but don’t really feel the same

viniciushana14:05:15

My problem is not with namespaced keys, I like them - it’s more with the syntax for declaring specs

viniciushana14:05:47

Or perhaps I need something to click before fully comprehending. Gotta try spec out...

gtrak14:05:47

mpenet: the registry is there for edn's sake, you can't eval clojure symbols like code can

mpenet14:05:13

gtrak: I get that

gtrak14:05:17

this is part of the 'clojure needs to win at serialization' story

gtrak14:05:52

and i think the specs themselves are serializable

mpenet14:05:40

kinda, serializing a predicate is not so clear cut

gtrak14:05:04

yea, I saw the word 'evalable' being used, so it seems like it's best to stick with core functions if you're going to distribute/transmit specs

mpenet14:05:35

yeah, tradeoffs

mpenet14:05:22

I would guess that if you need to do that kind of stuff you'd have control over this. Same problem applies to other schema/contract systems

debug14:05:35

Is it possible to load dependencies from clojars via the repl directly?

sveri15:05:29

@debug: there is something called lein-try, not sure if that fits your needs?

debug15:05:00

Oh, will check that out

debug15:05:59

Trying to do a simple base64 encoding actually and it seems like something needs to be pulled from clojars

debug15:05:45

There's a core lib that needs to be added to project.clj, which how would one achieve from the repl directly?

debug15:05:27

Lein-try looks good, thanks @sveri

debug15:05:35

@cmcfarlen: the installation section of the readme mentions that pomegranate must be added to project.clj, can it be used as a plugin instead?

cmcfarlen15:05:22

I'm not sure. If I want to use it I add it to my dev dependencies

cmcfarlen15:05:38

Its definitely situational, but handy

debug15:05:28

Awesome, this works!

debug15:05:43

Will be dabbling more and I believe will find this very useful as I will discover new libraries to try out

cmcfarlen15:05:49

@debug: there is this too, but I haven't been able to use it with vim effectively

cmcfarlen15:05:26

And this too which I haven't tried: https://github.com/pallet/alembic

debug15:05:25

@cmcfarlen: refactor-nrepl looks useful, and alembic is built on top of pomegranate. Tried pomegranate and it indeed works. Successfully fetched the library from the network and loaded it to the classpath.

debug15:05:21

Thank you, those are great options

cmcfarlen15:05:39

@debug: You're welcome!

payal16:05:45

Hello all, I am trying to make some async calls and getting this exception No implementation of method: :take! of protocol: #'clojure.core.async.impl.protocols/ReadPort found for class: clojure.lang.PersistentList

payal16:05:05

Can someone tell me when do we get this

ghadi16:05:24

you're trying to <! from a list accidentally, not a channel

payal16:05:36

ahh ..ohh got it.. I am using <?

crimeminister18:05:35

@mpenet @danboykis @viniciushana On the off chance anyone is interested, I think I will use this as my repo dumping grounds for potentially re-usable specs: https://github.com/clojurist-ca/clj-specs

danboykis18:05:44

@crimeminister: i'll take a look, good idea!

crimeminister18:05:32

@danboykis: not much there yet, but maybe it will grow. Feel free to contribute anything you feel others might have use for!

fasiha18:05:19

Anyone ever used Pollen (a typesetting language/system in Racket for HTML & other things)? I'd like to try to make something really simple based on that in Clojure, where, in essence, a string like "◊[:p hi there ◊[:b Ahmed]! How are you?]" gets turned into a Hiccup/HTML vector [:p "hi there " [:b "Ahmed"] "! How are you?"]. The first roadblock towards this is how to parse a string, character by character, waiting to get a complete Clojure expression?

ddellacosta18:05:13

so, banging my head against the wall trying to figure out how to get a basic Slack integration via Incoming WebHooks working using clj-http. I can run their curl example just fine, but when I use clj-http and pass in the information via :form-params {:payload (json/generate-string msg)} then I get missing_text_or_fallback_or_attachments. Same for :body (.getBytes (json/generate-string msg)). Has anyone tried this before? Seems like I’m doing something really obvious wrong but I’m completely confused as to what that is.

zmaril18:05:41

@fasiha: haven’t used pollen, but for parsing, check out https://github.com/Engelberg/instaparse

ddellacosta18:05:14

FWIW the slack docs say: > You have two options for sending data to the Webhook URL above: > > Send a JSON string as the payload parameter in a POST request > Send a JSON string as the body of a POST request

jjfine19:05:53

Here's what I'm using:

(post [webhook-url text]
    (client/post webhook-url {:form-params
                              {:payload (json/generate-string {:text text})}}))

jjfine19:05:57

client is clj-http.client

fasiha19:05:25

@zmaril you hit my achilles’s heel—I have no idea how parsing/grammar works 😛 hitting the books…

zmaril19:05:23

@fasiha: I was the same way before instaparse.

ddellacosta19:05:24

fasiha it’s pretty simple, spend a bit getting the hang of BNF and you’re good to go

ddellacosta19:05:33

instaparse makes it easy

zmaril19:05:55

The books make it out to be harder than it needs to be

ddellacosta19:05:56

bet you’ll find yourself writing up a grammar in no time

fasiha19:05:59

@ddellacosta: I should study BNF first/simultaneously with Instaparse? Not just try and go to Instaparse directly?

fasiha19:05:11

@zmaril: thanks, that's really good to know…

ddellacosta19:05:12

@fasiha: I would start playing with instaparse right away

ddellacosta19:05:21

as I think he gives a bit of an introduction in the docs

ddellacosta19:05:26

and you can fill it out as you need to

ddellacosta19:05:36

or yeah, there’s that 😄

fasiha19:05:55

@zmaril: reading that, and a couple of other google results now. I'm getting a little worried looking at these examples at having to write a grammar for Clojure code tho?

ddellacosta19:05:58

either way, don’t think you’ll need to go back and read a book/take a course or anything that intensive

ddellacosta19:05:06

you can definitely pick it up pretty quickly

ddellacosta19:05:14

and it’s fun!

zmaril19:05:29

If you have any questions circle back around here and we can help out

fasiha19:05:38

¡! thanks I will 😄

zmaril19:05:20

I’ve written a sql parser or two in instaparse, it’s quite fun

zmaril19:05:14

That one is the crazy one. Postgres docs provide a grammar in a markup language inside the source code. So I built a parser for the grammar in the docs and then generated instaparse combinators based off of that.

zmaril19:05:14

It’s not done yet, but it parses a surprising fraction of all the postgres tests.

ddellacosta19:05:07

wow, cool stuff

zmaril19:05:14

yeah someday I’ll try and finish that out

sashton19:05:47

in the spec guide, one of the examples has:

(s/def ::email-type (s/and string? #(re-matches email-regex %)))
(s/def ::email ::email-type)
Is there a reason for the second definition? I don't see an obvious one.

danburton19:05:42

I don't see an obvious reason. I would assume it's just a poorly chosen example of how you can define one schema to be the same as another in this way.

fasiha19:05:19

@sashton: I just learned about it and must share: there's #C1B1BB2Q3 !

Alex Miller (Clojure team)19:05:43

@sashton: yes, there is a good reason!

Alex Miller (Clojure team)19:05:03

the ::email-type spec is a reusable definition for an email attribute "type"

Alex Miller (Clojure team)19:05:23

whereas the ::email is a key attribute expected to be used in a domain entity map

Alex Miller (Clojure team)19:05:34

you might also have ::work-email ::company-email or whatever

Alex Miller (Clojure team)19:05:06

by separating the part defining what an email is, it can then be reused to form the basis for many attributes

sashton19:05:04

is it more of a convention being used? are they functionally the same?

Alex Miller (Clojure team)19:05:06

from working on some domain examples, I see this kind of split come up often - it's totally reasonable that we (as a community) could develop shared primitive specs like ::email-type that are reusable across projects (where the domain attributes may not be)

Alex Miller (Clojure team)19:05:37

on use, spec will "chase" the keywords to find the actual definition so there is no practical difference - this is about creating reusable semantics

noonian19:05:33

Can you reuse the ::email-type inside another expression? I would guess not because they are just keywords and not predicates i.e. (s/def ::company-email (s/and ::email-type #(re-matches some-other-more-restrictive-regex %)))

danburton20:05:06

wrt reusability... why not this instead?

(def email-type (s/and string? #(re-matches email-regex %)))
(s/def ::email email-type)
I don't see the benefit of attaching the email-type to that particular key, rather than just a def.

sashton20:05:47

@danburton: one thought I have is that everywhere you want to refer to that email-type in other namespaces, now you've got to refer its namespace, rather than just referring to the qualified keyword:

(require '(some.place :as place))
(s/def ::company-email place/email-type)

; vs

(s/def ::company-email :some.place/email-type)

Alex Miller (Clojure team)20:05:06

one possible benefit would be that you could attach a custom generator to the registered version

Alex Miller (Clojure team)20:05:25

I'm not doing that there, but I could have

Alex Miller (Clojure team)20:05:39

then the generator would be created once instead of many times

frank20:05:26

does anyone know how to implement an empty route with compojure? (e.g. (GET "" [] handler))

frank20:05:59

it doesn't seem to handle this properly since it creates a regex out of "" which becomes #"", and this doesn't match against anything at all

samuelf20:05:31

Ignorant novice question: Android apps are coded in Java and Clojure runs on the JVM, does this mean that Clojure can be used to develop native Android apps?

sashton20:05:34

@frank, I'm not sure, but does (GET "/" [] handler) work?

frank20:05:53

that works, but I don't want to have a trailing slash

frank20:05:16

reason being, this route is wrapped with compojure.core/context

frank20:05:50

so this route is one of many mounted on /foo/bar

frank20:05:59

but I want one that just handles /foo/bar

sashton20:05:05

if its your last route defined, could you use "*"?

Lambda/Sierra20:05:37

@samuelf: In principle, yes. It's not ideal, because Clojure(JVM) load time is problematic for mobile apps, but people have successfully built Android apps with Clojure.

curtis.summers20:05:39

@fasiha: If you're parsing Clojure forms, then clojure.tools.reader might be enough for your purposes: https://github.com/clojure/tools.reader

frank20:05:27

@sashton: I'd rather not since I'd still want /foo/bar/doesntexist to 404 😕

sashton20:05:42

i'm not sure, but at a minimum, you could just define a custom handler which checked that it is a :get and the url is ""

sashton20:05:48

well, i guess the url wouldn't be blank in that case. you'd have to know what the root path was, i think

frank21:05:03

I ended up writing a middleware that checks to see if :context and :uri values are equal on the request

ddellacosta21:05:57

instaparse is so fun to play with

fasiha21:05:04

My next question is—I seem to need to do char by char parsing of the strings (non-Clojure), so I get [:p "h" "i" " " "t" "h" "e" "r" "e" …]

fasiha21:05:33

Is there a canonical smart way to merge adjacent strings inside a vector into a single string, when that vector may contain other non-strings (which it should leave alone), including sub-vectors?

fasiha21:05:09

I can write a tricky & inscrutable recursive reduction, just wondering if there's either (1) a better way to merge runs of strings, or (2) a better way to parse (and I think it may be hard to improve on the parser, I messed with it a good bit, but then again, I've only been parsing for an hour)

ddellacosta21:05:20

fasiha, I'm probably missing something as I haven't touched instaparse in a while and I'm not super clear on what you're trying to do, but if you are using a regex for <string>, can't you simply adjust it to use the \w character class with a quantifier?

adambrosio21:05:03

@fasiha: (apply str (filter string? the-seq)) ?

adambrosio21:05:31

oh am i ignoring your earlier conversation?

fasiha21:05:41

Yeah this (and its intellectual parent, Pollen) is a really unusual use case. I want to use to indicate the start of a Clojure expression but things outside Clojure exprs are free text, and will eventually be surrounded by quotes (making them strings). So the string target is for anything non-Clojure-expr (i.e., not following a ), and I need to parse that char-by-char because the input could hit a ◊ at any time. Also, \w is insufficient because the free text could literally be anything

fasiha21:05:51

@adambros: nope, my question there was pretty self-contained. Let me see now

adambrosio21:05:43

ah you want to merge the 1 char strings while keeping them in place

fasiha21:05:49

@adambros: (apply str (filter string? [:p "hi" " there"])) returns "hi there", but I need [:p "hi there"]

ddellacosta21:05:06

oooh, I see fasiha

adambrosio21:05:02

specter might have something, let me take a look

noonian22:05:01

not pretty, but can always brute force it:

(reduce (fn [acc ele]
          (if (and (string? (last acc))
                   (string? ele))
            (conj (vec (butlast acc)) (str (last acc) ele))
            (conj acc ele)))
        []
        [:p "foo" "bar" :bar "baz" "quux"])

;=> [:p "foobar" :bar "bazquux”]

fasiha22:05:08

Thanks @noonian 😄 I'll use these and make a recursion that'll handle subvectors

adambrosio22:05:24

(keep identity (specter/transform [(specter/filterer string?)] #(vector (apply str %)) data))

adambrosio22:05:32

might not handle recursive data

adambrosio22:05:22

ah doesnt work for [:p "h" "i" " " "t" "h" "e" "r" "e" " " [:h1 "f" "b" "r”]] => (:p "hi there " [:h1 "f" "b" "r”])

adambrosio22:05:19

could do a postwalk over all vectors and use that function

dragosboca22:05:46

I have a problem: for some obscure reason I have to call a javascript hmm... script from clojure (not clojurescript). So I'm using clj-rhino. Everything's fine if that javascript returns a string or an integer. If I want (and I want 😄 ) to return a JSON I don't know how to translate/parse/transform it into something usable in clojure.

noonian22:05:33

could return a string of the json and use something like Cheshire to parse it into a Clojure map: https://github.com/dakrone/cheshire

dragosboca22:05:57

yeah... unfortunately I have too little control over the javascript part. must be a \"regular\" json. Or maybe Y have to wrap that javascript into another one... that's an idea