Could not locate clojure/data/json: How do I get my REPL to see this (and similar) dependencies - clojure

I am using lein repl without a project so there is no project.clj.
I am running Leiningen 2.8.1 on Java 1.8.0_191 OpenJDK 64-Bit Server VM.
When I require a Clojure dependency that I assume should just work - like clojure.data.json - I notice that it is not in my .m2 directory. Is that why I am getting a FileNotFoundException Could not locate clojure/data/json__init.class or clojure/data/js
on.clj on classpath? I can't find my other Clojure dependencies there either so I don't know where they reside and if this dependancy should be in .m2 or not.
I understand the error message but without knowing its location or even knowing how to properly add it to the CLASSPATH for the REPL to see it, I remain stuck.
Is this a dependency that I still need to install? If so, how do I install it without going through a project?
I don't understand the JVM as I am new to it, so add a little extra information in your answer.
I have looked at this, this, this, this and this. I don't know if I am overlooking anything so your help will really be appreciated.

I am using lein run without a project so there is no project.clj.
If you're using Leiningen, this'll be much easier if you create a project.clj file that declares your dependencies. Leiningen will read project.clj and handle fetching any missing dependencies to your local Maven repository, and add them to your classpath when you start your REPL/application. (lein run doesn't work for me in a directory without a project.clj; I get an error: No :main namespace specified in project.clj.. Did you mean lein repl?)
When I require a Clojure dependency that I assume should just work - like clojure.data.json - I notice that it is not in my .m2 directory.
clojure.data.json doesn't ship with Clojure — it's a separate dependency that must be fetched and added to your classpath in order to use it. The classpath tells the JVM where to look when it loads class files. Leiningen will do both of these things for you if you declare the dependency in project.clj:
:dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/data.json "0.2.6"]]
You can also use the lein deps command if you only want to fetch dependencies.
You can create a new/blank Leiningen project with lein new project_name_goes_here. It will have a project.clj with a few boilerplate entries and a :dependencies key where you can declare dependencies.
I understand the error message but without knowing its location or even knowing how to properly add it to the CLASSPATH for the REPL to see it, I remain stuck. Is this a dependency that I still need to install? If so, how do I install it without going through a project?
You could manually download it from the internet, then manually add its path to your classpath, but if you're already using Leiningen it's much easier to add a line to a project.clj file and have Leiningen handle this for you.
If using a project.clj file w/Leiningen isn't an option, there are other ways to use Clojure and resolve dependencies/build a classpath at runtime. Boot accommodates this workflow, you can use Leiningen like this with a little added effort, as well as the newer tools.deps tooling. There are examples of each in this ClojureVerse thread, but note that some of these approaches are doing essentially the same thing as declaring the dependency in a file — instead declaring them as CLI arguments.
For example, using Clojure CLI tooling:
$ clj -Sdeps "{:deps {org.clojure/data.json {:mvn/version \"0.2.6\"}}}"
Clojure 1.9.0
user=> (require '[clojure.data.json :as json])
nil
user=> (json/write-str {:foo "bar"})
"{\"foo\":\"bar\"}"
user=> (System/getProperty "java.class.path")
"src:
/Users/me/.m2/repository/org/clojure/clojure/1.9.0/clojure-1.9.0.jar:
/Users/me/.m2/repository/org/clojure/data.json/0.2.6/data.json-0.2.6.jar:
/Users/me/.m2/repository/org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.jar:
/Users/me/.m2/repository/org/clojure/core.specs.alpha/0.1.24/core.specs.alpha-0.1.24.jar"
You could create a deps.edn file containing {:deps {org.clojure/data.json {:mvn/version \"0.2.6\"}}} in the same directory, and clj would read that, resolve the dependencies if necessary, and build the classpath accordingly.

This is a great opportunity to use lein try. Once you add it to your ~/.lein/profiles.clj, you'd simply run: lein try org.clojure/data.json and you'll be greeted with a running REPL with that dependency just a require away.

Related

Leiningen compile does nothing

(leiningen v 2.5.1)
Leiningen compile seems to be doing absolutely nothing, even with a new project. My steps are
lein new default foo
cd foo
lein compile
ls | grep target # nada
lein jar # does create a target, but with an empty .jar. Still no .class files
EDIT
I also tried with the :all :aot flags, still no dice.
What next?
You need to add :aot :all into your project.clj (Note, you have it vice-versa in your edit). After that compile task will compile all your namespaces. You can also name only those namespaces you want to compile.
As a side note, also in resulting jar the Clojure namespaces does not need to be in compiled form. This is the role of :aot key to control which namespaces will get compiled.
Have a look in your project.clj file. You will see there is very little there. The lein command your using to setup the project is a bare minimum definition. It has very little in it. You might do better with the 'app' template to start with. You also need to look at the lein documentation to see what goes into the project.clj file. Google for some lein templates to see what other templates are available. I would then select one and an initial simple project to play with.
Note that you don't need to run lein compile to just get started with clojure and writing some codes/expressions to play with - run lein repl instead.

How do I add a library to LightTable so that when I use instarepl it will always have said library?

I'd like to add certain library dependencies to LightTable as a whole so that when I am messing around learning new stuff, I don't have to create a new project as a whole.
Let's say I want to always have access to these libraries: math.combinatorics and math.numeric-tower.
Lighttable seems to be calling a repl from leinigen, so am I really needing to add something there?
See https://github.com/LightTable/LightTable/blob/master/project.clj
It will be calling a repl of Leiningen. Rather than adding the dependencies to LightTable you could add them to your Leiningen Profile (~/.lein/profiles.clj)
The file would probably look something like this with your dependencies:
{:user {:dependencies [[math.combinatorics "x.x.x"]
[math.numeric-tower "x.x.x"]]}}
Generally this is not a very good idea. It will be a global thing and will probably cause you problems in the future. If you create an application you might find that these two libraries are available when they won't be for other people or on difference computers.
What would be a better option would be to create a new project using Leiningen. You can then edit your project.clj file to look something like this
(defproject math-thing "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:dependencies [[org.clojure/clojure "1.6.0"]
[math.combinatorics "x.x.x"]
[math.numeric-tower "x.x.x"]])
Then when editing your clj file LightTable uses your project.clj file to start instrepl and will resolve any needed dependencies.
Use the leiningen profile e.g. ~/.lein/profiles.clj and define a :injections [ ... ] node which performs the (require '[ ]) and import, refer-clojure and other items you have. I generally prefer to have at least Alembic present in my dev profile (wrapping Maven/Sonatype) so I can download, install in maven then classpath and project reload in one go using a macro/function wrapper around distill* to prevent a long load time due to too many libraries included in the user space. Pretty much this is the only function I usually want present in any REPL or LT InstaRepl and I put development and debugging snippets in project ./dev/user.clj to keep most of the messy stuff project specific.

Any way to add dependency to lein project without REPL restart?

What I do now is open project.clj, add dependency there, run lein deps restart repl, then use, require and so on.
The thing is that I don't really like to restart repl because the startup time is slow and I have to reload my files again.
So is there a better way to add dependency to lein project? without restarting the repl?
You can use Alembic, a dynamic classpath loader and dependencies resolver. The good thing is that it doesn't load all pomegranate dependencies.
Add the following to your .lein/profiles.clj:
{:user
{:dependencies [[alembic "0.3.2"]]}}
Then in your Repl just load the classpaths you need, they will be pulled from the repositories by leinif need:
(require 'alembic.still)
(alembic.still/distill '[enlive "1.1.5"])
(require 'net.cgrand.enlive-html) should now work.
for quick testing you can use pomegranate to add dependencies on the fly
=> (use '[cemerick.pomegranate :only (add-dependencies)])
nil
=> (add-dependencies :coordinates '[[incanter "1.2.3"]])
for actually adding a dependency I ususally hit
Alt-x nrepl-restart
ctrl-cctrl-k to reload the file,
ctrl-calt-n to get back to the namespace i in the buffer
The whole process takes the jvm startup time (which i agree is a touch painful) plus five seconds. It helps to keep your project in a state where loading a file does all the require initialization.

Display loaded dependencies in leiningen REPL

I'm running into problems because the library I have appears to conflict with the published documentation. I had a few problems with getting the right version of things installed before, and I'm wondering if this is the cause.
Is there any way to print out which jars were loaded in the repl so I can check?
You can also use query lein for
the classpath with lein classpath
a dependency tree printout with lein deps :tree
This might also help:
lein deps :tree - shows a tree of dependencies that get pulled in
[library "version" :exclusions [some-other-lib "version"]] - exclude the some-other-lib that gets pulled in by some library.
You can then manually pull in the right version of some-other-lib by defining your own dependency vector.
(System/getProperty "java.class.path")
There are several options:
using java interrop: (System/getProperty "java.class.path"), (println (seq (.getURLs (java.lang.ClassLoader/getSystemClassLoader))))
clojure/java.classpath contains useful functions: like system-classpath
lein: lein classpath and lein deps :tree
boot: boot show -p, as well as useful function in boot environnement. Maybe have a look at martinklepsch/boot-deps.
For boot, I also wrote nha/boot-deps that helps managing dependency conflicts.

upgrading lein project from clojure 1.2.1 to 1.3.0-beta1

I have a leiningen project that uses clojure 1.2.1. I would like to add a dependency to a package that requires clojure 1.3.0-beta1. So I decided to upgrade my project to the newer version.
To be honest I was not sure what that involved but I did the following..
In my project.clj I changed my dependency from
[org.clojure/clojure "1.2.1] to [org.clojure/clojure "1.3.0"]
I use swank so I changed my swank clojure dependency to [swank-clojure "1.3.2"].
I then ran
lein deps
Lastly I manually edited my /usr/bin/lein file to change the CLOJURE_JAR variable to point to the newer clojure jar.
When I start swank with 'lein swank'. It starts fine and I now get the following warning messages
like so..
Warning: default-javac-options not declared dynamic and thus is not dynamically rebindable, >but its name suggests otherwise. Please either indicate ^:dynamic default-javac-options or >change the name.
Which I think has to do with clojure 1.3.0.
I then fire up Aquamacs and run slime-connect. The REPL starts fine but when call clojure-version
if get "1.2.1".
; SLIME 20100404
user> (clojure-version)
"1.2.1"
Is there something else I need to do?
I think, that you need to add :exclusions list to swank-clojure specification, something like:
:dev-dependencies [[swank-clojure "1.3.2"
:exclusions [org.clojure/clojure]]]
although, I just checked my installation, and clojure 1.3 worked out of box. I think, that you just forgot to call lein clean before lein deps...