Clojure libraries and builds with Leiningen
Join the DZone community and get the full member experience.
Join For FreeLeiningen is an automation tool for Clojure projects: while you could in theory continue to use Ant and Maven directly to download JARs dependencies and to run tasks such as the project's test suite, Leiningen allows you to write just Clojure code, and generate on the fly everything else.
In short, Leiningen will use Ant and Maven under the covers, and follow the Maven model of downloading and caching dependencies globally instead of storing them along with your source code. But you won't see under the hood.
Installation
Assuming you're using a Linux system like Ubuntu and the shipped Clojure copy, installing the leiningen package will bring you the lein command.
Alternatively, you can download a single script from the bin/folder, place it on your path and make it executable. On the first execution it will bootstrap itself by downloading the missing dependencies.
There are also installation instruction for Windows boxes, both for the self-installing version and a standalone one.
A walkthrough: creating a new project
Leiningen can create a simple skeleton for our project:
[08:37:53][giorgio@Desmond:~/code]$ lein new clojure-midje-example Created new project in: /home/giorgio/code/clojure-midje-example [08:38:01][giorgio@Desmond:~]$ cd code/clojure-midje-example [08:38:29][giorgio@Desmond:~/code/clojure-midje-example]$ tree . ├── project.clj ├── README ├── src │ └── clojure_midje_example │ └── core.clj └── test └── clojure_midje_example └── test └── core.clj 5 directories, 4 files
We see a test and src folder, in the best Java/JVM tradition. The source file created as examples follow the folder structure as namespaces:
[09:00:17][giorgio@Desmond:~/code/clojure-midje-example]$ cat test/clojure_midje_example/test/core.clj (ns clojure-midje-example.test.core (:use [clojure-midje-example.core]) (:use [clojure.test])) (deftest replace-me ;; FIXME: write (is false "No tests have been written."))
You can already try to execute the failing test:
[09:02:52][giorgio@Desmond:~/code/clojure-midje-example]$ lein test Copying 1 file to /home/giorgio/code/clojure-midje-example/lib Testing clojure-midje-example.test.core FAIL in (replace-me) (core.clj:6) No tests have been written. expected: false actual: false Ran 1 tests containing 1 assertions. 1 failures, 0 errors.
And of course, write a real test:
[09:05:05][giorgio@Desmond:~/code/clojure-midje-example]$ cat test/clojure_midje_example/test/core.clj (ns clojure-midje-example.test.core (:use [clojure-midje-example.core]) (:use [clojure.test])) (deftest the-simplest-test-you-can-write (is 3 (+ 1 2))) [09:05:08][giorgio@Desmond:~/code/clojure-midje-example]$ lein testTesting clojure-midje-example.test.core Ran 1 tests containing 1 assertions. 0 failures, 0 errors.
Leiningen also produces a .gitignore file that allows you to ignore compiled classes, any kind of JAR, generated XML and Leiningen's own metadata.
Installing a library: Midje
Midje is a testing framework for Clojure, that I want to install both for being able to try it out later and for demonstrating how Leiningen can pull in a library.
The project.clj file contains all the definitions of dependencies that Leiningen will use to grab JARs. The format of :dependencies is a list of 2-element lists, where each 2-element list contains the name of the library and the required version as a string.
[09:06:11][giorgio@Desmond:~/code/clojure-midje-example]$ cat project.clj (defproject clojure-midje-example "1.0.0-SNAPSHOT" :description "FIXME: write description" :dependencies [[org.clojure/clojure "1.2.1"]])
By default, Leiningen will grab packages from Clojars, the main community repository for Clojure libraries, and from Maven Central.
Let's fix our project.clj to include midje and midje-lein, two JARs that will make Midje available to the current project. The first is the actual library, while the second provides the lein midje command, a nicer version of lein test.
[09:12:52][giorgio@Desmond:~/code/clojure-midje-example]$ cat project.clj (defproject clojure-midje-example "1.0.0-SNAPSHOT" :description "FIXME: write description" :dependencies [[org.clojure/clojure "1.2.1"] [midje "1.3.0"]] :dev-dependencies [[lein-midje "1.0.7"]])
I put midje in :dependencies just to show a different option for libraries, but it should actually be put in :dev-dependencies. The difference is in the latter case it won't be shipped in the JAR package of the project, nor being pulled into projects that depend on the current one.
To validate the availability of midje, let's write the simplest midje test:
[09:17:04][giorgio@Desmond:~/code/clojure-midje-example]$ cat test/clojure_midje_example/test/core.clj (ns clojure-midje-example.test.core (:use [clojure-midje-example.core]) (:use [clojure.test]) (:use [midje.sweet])) (deftest the-simplest-test-you-can-write (is 3 (+ 1 2))) (fact (+ 1 2) => 3) [09:16:55][giorgio@Desmond:~/code/clojure-midje-example]$ lein midje>>> clojure.test summary: Ran 1 tests containing 1 assertions. 0 failures, 0 errors. >>> Midje summary: All claimed facts (1) have been confirmed.
More lein commands
I have posted this example on Github, both for your and mine future reference.
For the ones of you that don't come from a JVM background, don't try to run .clj files in isolation: lein should always be used as a wrapper for him to be able to place the dependencies on the classpath.
Lein provides many other commands for this goal; for example:
- lein run will call the -main function in the namespace defined with :main in project.clj (it's easy to show than to explain: see the source code.)
- lein help run will display information about the run command; substitute your favorite command to learn all its options and how it interacts with project.clj.
- lein jar and lein uberjar will produce a JAR and a standalone JAR respectively for distributing your code.
Conclusions
You don't see it in this output sample, but lein midje also provides colors (a green bar), since it is a custom Leiningen task. The actual usage of Midje is out of the scope of this article, but I hope to have provided a simple way to grab dependencies inside your project.
Lein is easy to use, and provides enough documentation for basic use cases; in integrates testing as a first class task. However error messages are somewhat cryptic, and this is typical of Clojure: make sure to take small steps in order to easily locate any error in the last lines you wrote.
Opinions expressed by DZone contributors are their own.
Comments