Fork me on GitHub
#beginners
<
2021-01-30
>
caumond19:01:42

Hi, I started clojure using leiningen for everything, managing my dependencies, and setuping my repl, packaging my app at the end... But I find it very rarely mentionned there, for the profit of deps.edn format. For a beginner like me, should I spend time to learn from deps also?

andy.fingerhut19:01:15

As a beginner, I would say that if Leiningen is doing what you need it to, there is no compelling reason to learn deps right away. It is worthwhile if you get to the point of contributing to a project that uses deps.edn, or you hit a project whose needs are not well served by Leiningen.

andy.fingerhut19:01:05

For basic managing of dependencies, there is a subset of what they both do that is nearly identical, i.e. listing project group/artifact names and versions published as JARs. Starting a REPL is also simply a little bit different, but quick to learn for both.

dpsutton19:01:35

Honestly I think deps.edn is super useful particularly for beginners. Spinning up a simple repl and experimenting is so easy and low cost with deps.edn. I haven’t made a new lein project in years. Any experiment or play around or real project is deps.edn for me

caumond19:01:29

I sum up @U0CMVHBL2’s answer and yours as: both are doing the job for simple projects. But target is deps.edn. Is it only because it is the standard? or some advanced features are available only in deps.edn?

caumond19:01:41

When I checked by myself I noticed no major difference, except that deps.edn is more "alive"

andy.fingerhut19:01:46

One property of Leiningen that is sometimes given as a reason to prefer deps.edn is that Leiningen has a lot more hidden conventions that must be learned, that are not explicit until you learn about them. deps.edn does less in that regard. So in that sense deps.edn is simpler with fewer behaviors to work around, when you don't want those behaviors.

👍 2
andy.fingerhut19:01:57

For small starter projects, I have a hard time imagining enough of a difference between their capabilities that one is strongly preferable.

andy.fingerhut19:01:23

When a project gets medium or large in complexity or needs, if those desires/needs differ from what Leiningen provides, it can be more challenging to learn to customize Leiningen to do what you need.

andy.fingerhut20:01:02

Caveat: This is me repeating things I've heard, not from personal experience. I have not worked on any projects that had complex needs for build/deploy/test/etc.

seancorfield20:01:34

I started with Leiningen a decade ago because it was the only choice. I switched to Boot just over five years ago because I wanted more programmability in my build tooling but Boot was always pretty niche. I switched to the CLI / deps.edn pretty much as soon as it appeared -- partly because it was the "official" tooling and partly because we were running into bugs and performance issues with Boot, given our very large codebase.

seancorfield20:01:07

I find the CLI / deps.edn tooling to be both very simple and very powerful. I recommend it to beginners because it's documented directly on http://clojure.org and it's likely to be the basis of more and more things that come out of Cognitect/Nubank.

seancorfield20:01:06

But, yes, if you're happy using lein -- and working with lein-based projects and books/tutorials -- you might as well keep using it. You'll probably still need to learn the CLI / deps.edn stuff at some point though: more and more libraries/projects are adopting it.

caumond20:01:49

ok, I will continue with leiningen with my current project as it is already set. I'll move the project to CLI/`deps.edn` some times before production delivering, and before the next project. Thx

caumond06:02:36

I read the documentation for deps edn yesterday. Its not difficult at all to learn. I still need to practise but it did not cost me the time I expected. Maybe the reason is that Ihave more experience and deps edn is more focused.

Jamie Rumbelow19:01:16

Hi Clojurians - I’m struggling to get my repl to see a github-based java package. The package is here (https://github.com/whelk-io/flesch-kincaid) and I’m using git-down to get lein to import the dependency:

:dependencies [[org.clojure/clojure "1.10.0"]
                 [edu.stanford.nlp/stanford-corenlp "4.0.0"]
                 [io.whelk.flesch.kincaid/whelk-flesch-kincaid "0.0.31-RELEASE"]]
  :git-down {io.whelk.flesch.kincaid/whelk-flesch-kincaid {:coordinates whelk-io/flesch-kincaid}
             io.whelk.hy.phen/whelk-hy-phen-a-tion {:coordinates whelk-io/hy-phen-a-tion}}

Jamie Rumbelow19:01:15

lein pulls down the package just fine; when I try to import:

(import '(io.whelk.flesch.kincaid ReadabilityCalculator))
I get a ClassNotFoundException exception. I can see the package in ~/.m2 so i suspect the problem is with leiningen

hiredman19:01:10

You should ensure that whatever makes you think that class exists in that library matches the version of that library that you are using

hiredman19:01:14

And I assumed you restarted your reply since adding that to your project.clj, but if you haven't you need to do that

hiredman19:01:19

It looks like you might be using some weird lein plugin to add git dependency support

hiredman19:01:48

That almost certainly only works with clojure code

hiredman19:01:24

You can't use java straight up out of git, java needs to be compiled to classfiles first

Jamie Rumbelow20:01:57

that’s the thing - the jars definitely exist:

l ~/.m2/repository/io/whelk/flesch/kincaid/whelk-flesch-kincaid/0.0.31-RELEASE/
total 72
drwxr-xr-x  7 jamierumbelow  staff   224B 30 Jan 19:30 .
drwxr-xr-x  4 jamierumbelow  staff   128B 30 Jan 19:27 ..
-rw-r--r--  1 jamierumbelow  staff   250B 30 Jan 19:30 _remote.repositories
-rw-r--r--  1 jamierumbelow  staff    19K 30 Jan 19:30 whelk-flesch-kincaid-0.0.31-RELEASE.jar
-rw-r--r--  1 jamierumbelow  staff    40B 30 Jan 19:30 whelk-flesch-kincaid-0.0.31-RELEASE.jar.sha1
-rw-r--r--  1 jamierumbelow  staff   2.7K 30 Jan 19:30 whelk-flesch-kincaid-0.0.31-RELEASE.pom
-rw-r--r--  1 jamierumbelow  staff    40B 30 Jan 19:30 whelk-flesch-kincaid-0.0.31-RELEASE.pom.sha1
and were put there by lein

andy.fingerhut21:01:08

I am trying to reproduce what you are doing with a test Leiningen project on a Linux VM of mine, but when I include the :dependencies and :git-down keys in my project.clj file, plus these line which the Leiningen git-down docs recommend (I haven't used it before, so I could be missing something:

(defproject try1 "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url ""
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url ""}
  :dependencies [[org.clojure/clojure "1.10.0"]
                 [edu.stanford.nlp/stanford-corenlp "4.0.0"]
                 [io.whelk.flesch.kincaid/whelk-flesch-kincaid "0.0.31-RELEASE"]]
  :git-down {io.whelk.flesch.kincaid/whelk-flesch-kincaid {:coordinates whelk-io/flesch-kincaid}
             io.whelk.hy.phen/whelk-hy-phen-a-tion {:coordinates whelk-io/hy-phen-a-tion}}
  :plugins [[reifyhealth/lein-git-down "0.4.0"]]
  :repositories [["public-github" {:url ""}]
                 ["private-github" {:url "" :protocol :ssh}]]
  ;;:repl-options {:init-ns try1.core}
  )

andy.fingerhut21:01:20

When I try lein repl in the directory of such a project, it fails to download the whelk-flesch-kincaid code, with messages like this:

Retrieving io/whelk/flesch/kincaid/whelk-flesch-kincaid/0.0.31-RELEASE/whelk-flesch-kincaid-0.0.31-RELEASE.pom from public-github
Retrieving io/whelk/flesch/kincaid/whelk-flesch-kincaid/0.0.31-RELEASE/whelk-flesch-kincaid-0.0.31-RELEASE.pom from public-github
Retrieving io/whelk/flesch/kincaid/whelk-flesch-kincaid/0.0.31-RELEASE/whelk-flesch-kincaid-0.0.31-RELEASE.jar from public-github
Retrieving io/whelk/flesch/kincaid/whelk-flesch-kincaid/0.0.31-RELEASE/whelk-flesch-kincaid-0.0.31-RELEASE.jar from public-github
Could not find artifact io.whelk.flesch.kincaid:whelk-flesch-kincaid:jar:0.0.31-RELEASE in central ()
Could not find artifact io.whelk.flesch.kincaid:whelk-flesch-kincaid:jar:0.0.31-RELEASE in clojars ()
Could not transfer artifact io.whelk.flesch.kincaid:whelk-flesch-kincaid:jar:0.0.31-RELEASE from/to public-github (): : Authentication is required but no CredentialsProvider has been registered
Could not transfer artifact io.whelk.flesch.kincaid:whelk-flesch-kincaid:jar:0.0.31-RELEASE from/to private-github (): : Authentication is required but no CredentialsProvider has been registered
Could not transfer artifact io.whelk.flesch.kincaid:whelk-flesch-kincaid:pom:0.0.31-RELEASE from/to public-github (): : Authentication is required but no CredentialsProvider has been registered
This could be due to a typo in :dependencies, file system permissions, or network issues.
If you are behind a proxy, try setting the 'http_proxy' environment variable.
Could not resolve dependencies

andy.fingerhut21:01:46

Given I've never used lein-git-down, I am probably not configuring it correctly.

Jamie Rumbelow21:01:24

Strange - looks like you’ve configured it the same as I have

hiredman21:01:12

A jar existing doesn't mean anything

hiredman21:01:15

A jar is just a zip file, and can contain java source code just as easily as compiled class files

andy.fingerhut21:01:36

Well, it means something 🙂 Necessary, but not sufficient. The JAR needs to be on your JVM class path, which Leiningen often gets right, but might not be in your case. The JAR needs to contain compiled .class files defining the classes you are interested in, if it does not contain Clojure source code.

hiredman21:01:50

I haven't used this git down plugin, and I am not familiar with how it works, but my guess is it checks out the git repo, bundles it up as a jar, and sticks in m2 where leins normal dependency mechanism will find it

hiredman21:01:40

Which won't work if the project needs a "build" step like compiling java source to classfiles

andy.fingerhut21:01:52

You can use a command like unzip -v foo.jar to see the contents of a jar file. I don't have it installed on the system I have handy at the moment, but most JDKs also install a command jar that can be used for this purpose, perhaps with different command line options.

hiredman21:01:12

This code is a whole thing, but has a nice comment suggesting it does exactly as guessed https://github.com/reifyhealth/lein-git-down/blob/develop/src/lein_git_down/git_wagon.clj#L173

hiredman21:01:00

Although it does look like they do actually attempt to do a build step, but that seems like it could fail in all kinds of ways

Jamie Rumbelow21:01:09

This is really useful, thanks all

hiredman21:01:46

They may only handle build steps with maven in projects that use the clojure maven plugin

Jamie Rumbelow21:01:37

Okay – I’ve unzipped the jar and you’re correct, it’s just a handful of source files, nothing compiled

Jamie Rumbelow21:01:59

I guess then I need to compile the source separately. If I do that locally (say, in the directory above my clj project), can I tell lein to pull the dependency from there?

andy.fingerhut21:01:00

It is possible that library only distributes Java source files, and not pre-compiled JAR files.

Jamie Rumbelow21:01:18

Yep, I think that’s exactly what’s happened

Jamie Rumbelow21:01:59

I didn’t realise jars were (potentially) uncompiled!

andy.fingerhut21:01:11

If you find a way to compile and create a JAR file from that project, e.g. using the mvn command, its install subcommand will typically create a JAR file containing compiled .class files in some place within your .m2 directory, and tell you the name of that JAR file near the last line of output.

andy.fingerhut21:01:03

Clojure JAR files often contain uncompiled Clojure/ClojureScript source code. For Java libraries, pre-compiled JAR files containing .class files are definitely most common. JAR files are like zip or tar files -- they can contain any kinds of files inside.

Jamie Rumbelow21:01:12

Is there a community-driven ‘interop’ site that compiles and wraps common Java libraries, similar to eg cljsjs, or definitely-typed in typescript-land? I’m surprised that lein can’t compile this stuff for me

alexmiller21:01:56

It’s very unusual not to distribute Java libs as compiled jars in Maven repos

andy.fingerhut22:01:11

Yes, this library does not have any pre-compiled JARs on Maven Central according to search at Maven Central: https://search.maven.org/

andy.fingerhut22:01:13

That is unusual.

andy.fingerhut22:01:36

It is also an extra step for the publisher of the Java code to go through, which many do, but it isn't automatically done for them.

dharrigan21:01:29

Say I have a map, {:a 1 :b 2 :c 3}, I was wondering if one of the cond variations would destructure and test if the value is null, so that I could execute a branch of code once the first non-nil value is hit. A bit like this

dharrigan21:01:32

(def foo {:a 1 :b 2 :c 3})

(condp not nil? foo
      a (branch-1 a)
      b (branch-2 b)
      c (branch-3 c))

dharrigan21:01:48

natch, that's bad code, but is there an idomatic way of doing that in Clojure?

seancorfield22:01:11

@dharrigan Given that hash maps are inherently unordered, you'd have to provide an ordered list of keys to check, no?

seancorfield22:01:00

(although, in this case you also have an inherent order of functions to call on specific keys' values)

dharrigan22:01:43

You're absolutely right! I keep forgetting they are unordered!

dharrigan22:01:43

I can do something like this

dharrigan22:01:47

(def foo {:a nil :b 2 :c 3})

(when-let [{:keys [a b c]} foo]
  (cond
    a "x"
    b "y"
    c "z"))

seancorfield22:01:51

That said, if you have a hash map of data and a hash map from keys in that data to functions to apply to them and a vector of keys in order to check... then a reduce would work...

dharrigan22:01:56

(def foo {:a nil :b 2 :c nil})

(when-let [{:keys [a b c]} foo]
  (cond
    c "z"
    a "x"
    b "y"
    :else "bedtime!")) ;; "y"

dharrigan22:01:00

that seems to work nicely! 🙂

seancorfield22:01:53

(def foo {:a nil :b 2 :c nil})
(def foo-fn {:a branch1 :b branch-2 :c branch-3})

(reduce (fn [_ k] (when-let [v (k foo)] ((k foo-fn) v)))
        nil
        [:a :b :c])
That was the generalization I was suggesting.

dharrigan22:01:46

I like that too

dharrigan22:01:00

going to save that in my "Sean's Snippets" folder... 🙂

seancorfield22:01:55

I guess another option is first of for: (first (for [k [:a :b :c] :let [v (k foo)] :when v] ((k foo-fn) v)))

dharrigan22:01:25

🙂 Another useful one. Thank you Sean. For me bedtime!