(defproject clojure-noob "0.1.0-SNAPSHOT"
Building and Developing with Leiningen
Writing software in any language involves generating artifacts, which are executable files or library packages that are meant to be deployed or shared. It also involves managing dependent artifacts, also called dependencies, by ensuring that they’re loaded into the project you’re building. The most popular tool among Clojurists for managing artifacts is Leiningen, and this appendix will show you how to use it. You’ll also learn how to use Leiningen to totally enhancify your development experience with plug-ins.
The Artifact Ecosystem
Because Clojure is hosted on the Java Virtual Machine ( JVM), Clojure artifacts are distributed as JAR files (covered in Chapter 12). Java land already has an entire artifact ecosystem for handling JAR files, and Clojure uses it. Artifact ecosystem isn’t an official programming term; I use it to refer to the suite of tools, resources, and conventions used to identify and distribute artifacts. Java’s ecosystem grew up around the Maven build tool, and because Clojure uses this ecosystem, you’ll often see references to Maven. Maven is a huge tool that can perform all kinds of wacky project management tasks. Thankfully, you don’t need to get your PhD in Mavenology to be an effective Clojurist. The only feature you need to know is that Maven specifies a pattern for identifying artifacts that Clojure projects adhere to, and it also specifies how to host these artifacts in Maven repositories, which are just servers that store artifacts for distribution.
Identification
Maven artifacts need a group ID, an artifact ID, and a version. You can specify these for your project in the project.clj file. Here’s what the first line of project.clj looks like for the clojure-noob
project you created in Chapter 1:
clojure-noob
is both the group ID and the artifact ID of your project, and "0.1.0-SNAPSHOT"
is its version. In general, versions are permanent; if you deploy an artifact with version 0.1.0 to a repository, you can’t make changes to the artifact and deploy it using the same version number. You’ll need to change the version number. (Many programmers like the Semantic Versioning system, which you can read about at http://semver.org/.) If you want to indicate that the version is a work in progress and you plan to keep updating it, you can append -SNAPSHOT
to your version number.
If you want your group ID to be different from your artifact ID, you can separate the two with a slash, like so:
(defproject group-id/artifact-id "0.1.0-SNAPSHOT"
Often, developers will use their company name or their GitHub username as the group ID.
Dependencies
Your project.clj file also includes a line that looks like this, which lists your project’s dependencies:
:dependencies [[org.clojure/clojure "1.9.0"]]
If you want to use a library, add it to this dependency vector using the same naming schema that you use to name your project. For example, if you want to easily work with dates and times, you could add the clj-time library, like this:
:dependencies [[org.clojure/clojure "1.9.0"]
[clj-time "0.9.0"]]
The next time you start your project, either by running it or by starting a REPL, Leiningen will automatically download clj-time and make it available within your project.
The Clojure community has created a multitude of useful libraries, and a good place to look for them is the Clojure Toolbox at http://www.clojure-toolbox.com, which categorizes projects according to their purpose. Nearly every Clojure library provides its identifier at the top of its README, making it easy for you to figure out how to add it to your Leiningen dependencies.
Sometimes you might want to use a Java library, but the identifier isn’t as readily available. If you want to add Apache Commons Email, for example, you have to search online until you find a web page that contains something like this:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.3.3</version>
</dependency>
This XML is how Java projects communicate their Maven identifier. To add it to your Clojure project, you’d change your :dependencies
vector so it looks like this:
:dependencies [[org.clojure/clojure "1.9.0"]
[clj-time "0.9.0"]
[org.apache.commons/commons-email "1.3.3"]]
The main Clojure repository is Clojars (https://clojars.org/), and the main Java repository is The Central Repository (http://search.maven.org/), which is often referred to as just Central in the same way that San Francisco residents refer to San Francisco as the city. You can use these sites to find libraries and their identifiers.
To deploy your own projects to Clojars, all you have to do is create an account there and run lein deploy clojars
in your project. This task generates everything necessary for a Maven artifact to be stored in a repository, including a POM file (which I won’t go into) and a JAR file. Then it uploads them to Clojars.
Plug-Ins
Leiningen lets you use plug-ins, which are libraries that help you when you’re writing code. For example, the Eastwood plug-in is a Clojure lint tool; it identifies poorly written code. You’ll usually want to specify your plug-ins in the file $HOME/.lein/profiles.clj. To add Eastwood, you’d change profiles.clj to look like this:
{:user {:plugins [[jonase/eastwood "0.2.1"]] }}
This enables an eastwood
Leiningen task for all your projects, which you can run with lein eastwood
at the project’s root.
Leiningen’s GitHub project page has excellent documentation on how to use profiles and plug-ins, and it includes a handy list of plug-ins.
Summary
This appendix focused on the aspects of project management that are important but that are difficult to find out about, like what Maven is and Clojure’s relationship to it. It showed you how to use Leiningen to name your project, specify dependencies, and deploy to Clojars. Leiningen offers a lot of functionality for software development tasks that don’t involve actually writing your code. If you want to find out more, check out the Leiningen tutorial online at https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md.