What specifically do project.clj :dependencies do and are they required? - clojure

I am asking this question to straighten out a confusion I have about project.clj :dependencies and modules specified using :use/:require.
I use lein to build. I want to write a Clojure project and perhaps other than its being dependent on a particular Clojure release, do not want the project to be dependent on any module's particular version.
For example:
(defproject bene-csv "1.0.0-SN"
:description "A csv parsing library"
:dependencies [[org.clojure/clojure "1.3.0"]
[clojure-csv/clojure-csv "1.3.2"]])
I don't particularly need to be dependent on clojure-csv 1.3.2. My code will will work with whatever version there is.
Am I required to specify a dependency so a version is fetched locally?
If not, what other mechanisms are there to get the modules I need and where would they
be located?
Thank You.

I believe leiningen uses the same versioning system as maven. See Keeping dependency versions up to date in Leiningen projects and How do I tell Maven to use the latest version of a dependency?.

Telling Leiningen "just pull in whatever version you like; I don't care" is just asking for trouble down the road. Repeatability the foundation of automation: https://github.com/technomancy/leiningen/wiki/Repeatability

Related

How to add libraries in clojure?

Everywhere I see, it is suggested that I add :dependencies in project.clj and run lein deps. Where are these downloaded? What is my CLASSPATH and how can I add my own JARs to my clojure project?
While the answer for
Dependencies in maven local repositories with leiningen
kind of solves my need, I am not marking it duplicate as what I am asking is much simpler (being a beginner, who does not have much experience with Java to know about Maven). I am still finding it hard to understand where clojure ends and leiningen begins.
The thing I was looking for is a way to add library like we do in most other languages (e.g. copy JAR to project directory and import in code).
This is great question since it's not clear at all. Leiningen is often a black hole and if something isn't working it's often hard to debug.
I just recently had to do some manual scripting and leiningen does help you with finding out these things.
Where are these downloaded?
The directory is in $HOME/.m2. This is Maven's: http://maven.apache.org/settings.html
What is my classpath?
The classpath is set depending on your :dependencies as well as your :source-paths and :resource-paths vectors.
You can find out your classpath like this:
lein classpath
This will print a huge list depending on your configuration.
You could --for instance-- then run a script:
java -cp cljs-1.7.xx.jar:scripts:$(lein with-profile +dev-cljs classpath) clojure.main scripts/cljs-build.clj dev
That has access to all your projects dependencies and loads them properly.
Although you could use lein run to achieve something similar:
lein with-profile +dev-cljs run -m clojure.main scripts/cljs-build.clj dev
How do I add my own JARs?
See: leiningen - how to add dependencies for local jars?
Run lein install from your library's project dir.
Add an entry to :dependencies in client's project.clj.
Make sure the lib name/version and its reference match (eg. [mylib "0.0.1-SNAPSHOT"]).
Hope this helps, forget about jar loc and cp for now.

Local dependencies in Leiningen without creating a Maven repo?

I'm building a Compojure web application, and I'd like it to use functions from another Clojure project I wrote. I'm not at all familiar with Maven, and from what I've heard, it has a very steep learning curve. Unfortunately, everything I've seen suggests using a private Maven repo as a dependency and doesn't suggest an alternative. I'd really like to avoid struggling with Maven if possible. Does anyone know of an alternative? I'm currently using the latest version of Leiningen.
If the other project is also a lein project, you just need to do a "lein install" and that will take care of creating all the local maven repo stuff. Then you can just depend on that project as you would do with any other lib. For example:
(defproject mylib "1.0"
....)
lein install
(defproject myotherproject "a.b.c"
:dependencies [[mylib "1.0"]]
.....)
If you are sharing "myotherproject" with other people and you want to remove some of the inconvenience of doing a "lein install" every time you change the mylib project, have a look at the lein checkouts feature and then use the equivalent of svn externals of your VCS of choice.
'lein checkout' appears to be another way to achieve the same goal. a lot more details here and here. In general, the idea is to create a symlink to the local copy of the dependency, but the process does require one lein install. I also found this lein plugin that might be even better, but I've yet to try it myself.

Installing libraries with leiningen without creating project

I am learning Clojure and coming from a Ruby background.
I am looking for something analogous to gem install <library>. The various incantations of lein install do not seem to fit this bill.
Is there a way to simply install a library locally so that it can be referenced in the REPL without the need to create a project?
Seems like, you want to install a library with lein. Here is the plugin, install it and use like
lein localrepo install <filename> <[groupId/]artifactId> <version>
If your aim is merely to load libraries in the REPL consider using alembic. It loads dynamically classpaths, resolve dependencies and automatically pulls libraries from the repositories.
Here is a use case:
(require 'alembic.still)
(alembic.still/distill '[enlive "1.1.1"])
It simply requires you to add the following entry to your .lein/project.clj:
{:dev {:dependencies [[alembic "0.1.1"]]}}
See this answer.
Java and thus clojure do not generally have the the idea of globally installed libraries. You should always be creating a classpath with the minimal set of dependencies. You need somehow to specify and manage this classpath and the easiest way to do this is with leiningen, which requires a project.
leiningen automates the process of retrieving the remote libraries and placing them in your local repository which is somewhat analogous to gem install, but these libraries do not become automatically available to a REPL.
The easiest way to have a set of libraries always available is to have a 'scratch' project which you use for REPL experiments before starting a new project. It's not too much of an overhead.
In lein 2 you can update profiles.clj with package you want to install:
~\user\.lein\profiles.clj
With the first run of any project with lein, the local repo will be updated with what was incereased in profiles.clj.
Sometimes I just run lein deps without being in a project folder, this will update the local repo for you.
This way you can add any library to your project.clj or call it from repl and it will be extracted from local repo.
If you don’t have a project, you add your dependencies in your global lein user profile instead located at ~/.lein/profiles.clj.
The doc isn’t great for lein to be honest. So this part is confusing. But you edit that file as such:
{:user {:plugins [[lein-pprint "1.1.1"]]
:dependencies [[slamhound "1.3.1"]]}}
In the :plugins vector you add whatever global lein plugin you want to have. And in the :dependencies vector you add whatever library you want available globally.
Then anywhere you start a lein repl you’d have those dependencies available to you. And everywhere you run lein you’ll have the additional plugin features available to you.
If you use tools.deps instead of lein, aka, the clj command instead of the lein command. Then it is a bit different. You instead want to modify your ~/.clojure/deps.edn file. Where you’d add dependencies there instead:
{:deps {clj-time {:mvn/version "0.14.2"}}}
So if you put the above in your user deps.edn whenever you run clj command the clj-time library will be available to you.

Creating & using libraries in both Clojure and ClojureScript

I've just written some ClojureScript code, only to find out that I couldn't access one of the libraries listed in my project.clj's dependencies. Is this correct, i.e. that you can't use Clojure libraries from CLJS unless they're specifically designed to allow it?
If so, how much extra work is required to take a Clojure library that doesn't use any Java interop, and would itself be valid ClojureScript code, and make it useable from ClojureScript? From looking around GitHub, many libs appear to have separate source directories for clj and cljs code. Can such a library be added to my project.clj and be used immediately from either platform?
There are some ClojureScript differences from Clojure.
Dependecies from "project.clj" can be applicable / visible / usable by ClojureScript, for example, take a look at "jayq". You would include it in "project.clj":
(defproject xyz/xyz "0.1.0-SNAPSHOT"
:dependencies [[clj-time "0.4.3"]
[jayq "2.2.0"]
....
And then use it in the ClojureScript file:
(ns xyz.some.cljs
(:require ...
...
[clojure.browser.repl :as repl]
[jayq.core :as jq])
While "jayq" is not a "Clojure" library in the "backend" sense since it just wraps JavaScript, it is an example of using a "project.clj" dependency on the ClojureScript side.
In addition most of the core and several non core libraries are already ported to the ClojureScript side:
clojure.set
clojure.string
clojure.walk
clojure.zip
clojure.core.reducers
fold is currently an alias for reduce
core.match
core.logic (in works)
Other Clojure libraries will have to conform to the ClojureScript subset in order to work in ClojureScript.
It is worthwhile to clone ClojureScript repo and get a sense of what it supported (plus add your own features if you feel adventurous :)
ClojureScript dependencies are usually "front end" based (included the ones ported from backend). In other words, the end goal is to be compiled by V8 and run as JavaScript, hence anything that can be compiled by the ClojureScript compiler (repo above) can be used.
I see that the answers were given in 2013, but as of 2020, this is still the case with CLJS version 1.10. Its still not possible to use just any Clojure library, unless the library has been made CLJS compatible.Building with shadow-cljs will give build error like:
The required namespace "clojure.data.json" is not available, it was required by "bharati/binita/frontend/demo3/main.cljs".
"clojure/data/json.clj" was found on the classpath. Should this be a .cljs file?
I could not see any solution to that,other than using any other alternative library that is CLJS compatible.

How to install a leiningen plugin?

How do I install a leiningen plugin?
For example, leiningen-run?
I see this thing called "clojars.org", and how to "push" to it, but I don't see anything about "pulling" from it.
If a plugin's available at Clojars, like lein run is, just add it to your project's :dev-dependencies in project.clj, then say lein deps in your project's directory to have Leiningen pull in all dependencies. An annotated excerpt from lein run's docs:
(defproject island-wari "0.1"
:description "Web application for playing the Island Wari game."
:main wari
:dependencies [[org.clojure/clojure "1.1.0-master-SNAPSHOT"]
[org.clojure/clojure-contrib "1.1.0-master-SNAPSHOT"]
[org.clojars.liebke/compojure "0.3.1-master"]]
:dev-dependencies [[org.clojure/swank-clojure "1.0"]
[leiningen-run "0.2"]]) ; <--- this bit makes it possible
; to use lein run
Having done the above, you should be able to say lein run in your project's directory to run your app.
Update: Should you want to write your own plugins for Leiningen, check out this tutorial on nakkaya.com. Even if you're not planning on writing lein plugins, still check out that blog, it absolutely positively rocks.
Depending on a plugin
With Leiningen 2.0 and greater you specify which plugins you want as values to :plugins in your project map. See the sample project.clj file. Note that "sample" is a bit of a misnomer, it's a reference for all possible (built-in) keys and documentation of their defaults.
lein-run
The lein-run functionality is now part of core leiningen and doesn't need to be specified as a plugin
clojars.org
Clojars is a repository of clojure libraries quite similar to maven central (or to some lesser extent, rubygems). You don't pull from it explicitly. Instead, Leiningen is configured to search through a standard set of repos for your :dependencies E.g. maven central and clojars. Maven uniquely identifies its dependencies (artifacts in maven parlance) by a triple (group-name, artifact-name, version). Leiningen leverages the exact same mechanism with the exception that the group name does not have the restriction of being a reverse URI the way it must be with maven central. In practice you'll tend to see many libraries published in clojars where the name nicely matches the clojure namespace and github project name without the annoying com.mydomain.awesomelib
You can set your own repos to be searched (or tweak various options) via :repositories in you project.clj. You can similarly set :mirrors if you have an in-house mirror of a maven repo.
"Installing" an unpublished plugin
Finally, though I don't think that's directly what you were asking but it's still interesting, If you're developing a plugin or what to depend on a plugin that hasn't been officially published, you can set :plugin-repositories