https://github.com/tomekw/cdeps
Clojure + deps.edn, a basic guide.
https://github.com/tomekw/cdeps
clojure edn
Last synced: about 2 months ago
JSON representation
Clojure + deps.edn, a basic guide.
- Host: GitHub
- URL: https://github.com/tomekw/cdeps
- Owner: tomekw
- Created: 2019-07-05T12:51:07.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2020-06-09T07:39:07.000Z (about 5 years ago)
- Last Synced: 2025-04-19T23:31:50.602Z (2 months ago)
- Topics: clojure, edn
- Language: Clojure
- Homepage: https://tomekw.com/clojure-deps-edn-a-basic-guide/
- Size: 3.91 KB
- Stars: 21
- Watchers: 1
- Forks: 2
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
Awesome Lists containing this project
README
# cdeps
Clojure + deps.edn, a basic guide.After a rather long break from programming and Clojure I decided give them another go. When it comes to managing Clojure
projects, [Leiningen](https://leiningen.org/) is de-facto standard tool. Recently,
[Clojure CLI tools](https://clojure.org/guides/deps_and_cli) are becoming more and more popular, though. Switching to
yet-another-build-tool doesn't have any pragmatic value, but it's perfect for learning purposes.From a build tool I expect it to perform certain tasks:
1. Creating a project.
1. Managing source and tests paths.
1. Managing dependencies.
1. Running tests.
1. Building a self-contained JAR, a.k.a. uberjar.
1. Managing outdated dependencies.Let's see how it's performed using Clojure CLI tools, a.k.a. deps.edn.
## Creating a project
Leiningen allows to generate a project structure simply by invoking:
```bash
$ lein new [template] [project-name]
```
We get a lot for free, but is it really needed? How is it done with Clojure CLI tools?Imagine a simple project. It allows add and divide numbers, it also prints some example calculations when invoked.
We can start by simply creating a new directory:
```bash
$ mkdir cdeps && cd cdeps
```
Now, let's add an empty `deps.edn` file:
```clojure
;; /deps.edn
{}
```
And now we can start adding some actual code to the project.## Managing source and tests paths
To demonstrate the feature of managing source paths we will put our code at `src/main/clojure`.
```bash
$ mkdir -p src/main/clojure
```
`deps.edn` is no magic so we can just set the path in the file:
```clojure
;; deps.edn
{:paths ["src/main/clojure"]}
```
Now, we can write the calculator code:
```clojure
;; src/main/clojure/com/tomekw/cdeps/calculator.clj
(ns com.tomekw.cdeps.calculator)(defn plus [a b]
(+ a b))(defn divide [a b]
(/ a b))
```## Managing dependencies
In such a simple project there is no real need to add external dependencies. We can always specify the Clojure version
we would like to use, though:
```clojure
;; deps.edn
{:paths ["src/main/clojure"]
:deps {org.clojure/clojure {:mvn/version "1.10.1"}}}
```
Clojure CLI tools allow to specify local and git dependencies too, see
[documentation and more examples](https://clojure.org/guides/deps_and_cli#_using_local_libraries).## Running tests
The calculator we wrote is super simple but we can still write some tests:
```clojure
;; test/main/clojure/com/tomekw/cdeps/calculator_test.clj
(ns com.tomekw.cdeps.calculator-test
(:require [clojure.test :refer :all]
[com.tomekw.cdeps.calculator :refer :all]))(deftest adding-numbers
(is (= 4 (plus 2 2))))(deftest dividing-numbers
(is (= 2 (divide 4 2))))(deftest dividing-numbers-by-zero
(is (thrown? ArithmeticException (divide 1 0))))
```
Now we need to run them to make sure they pass. We have to add an alias (a command we will run), and a test runner,
as an extra dependency. I picked [kaocha](https://github.com/lambdaisland/kaocha). Also, we need to tell the runner
where the tests are located:
```clojure
;; deps.edn
{:paths ["src/main/clojure"]
:deps {org.clojure/clojure {:mvn/version "1.10.1"}}
:aliases {:test {:extra-paths ["test/main/clojure"]
:extra-deps {lambdaisland/kaocha {:mvn/version "0.0-529"}}
:main-opts ["-m" "kaocha.runner"]}}}
```
Here is the test report:
```bash
$ clj -Atest
[(...)]
3 tests, 3 assertions, 0 failures.
```## Building a self-contained JAT, a.k.a. uberjar
Presume, we would like to print example calculations to the console. Let's add the code to do that:
```clojure
;; src/main/clojure/com/tomekw/cdeps/core.clj
(ns com.tomekw.cdeps.core
(:gen-class)
(:require [com.tomekw.cdeps.calculator :refer :all]))(defn -main [& args]
(do (println (format "2 + 2 is %s" (plus 2 2)))
(println (format "4 / 2 is %s" (divide 4 2)))))
```
To run the main function we can invoke the following command:
```bash
$ clj -m com.tomekw.cdeps.core
2 + 2 is 4
4 / 2 is 2
```
It could be burdensome for the users of our calculator to install Clojure. To avoid this, we can package our project
as a standalone Java JAR. There is number of tools to do that, like [cambada](https://github.com/luchiniatwork/cambada),
but I've decided to try out [uberdeps](https://github.com/tonsky/uberdeps). Let's add a proper configuration first:
```clojure
;; deps.edn
{:paths ["src/main/clojure"]
:deps {org.clojure/clojure {:mvn/version "1.10.1"}}
:aliases {:test {:extra-paths ["test/main/clojure"]
:extra-deps {lambdaisland/kaocha {:mvn/version "0.0-529"}}
:main-opts ["-m" "kaocha.runner"]}
:uberjar {:extra-deps {uberdeps {:mvn/version "0.1.4"}}
:main-opts ["-m" "uberdeps.uberjar" "--target" "target/cdeps-0.1.0.jar"]}}}
```
To package the project we simply run:
```bash
$ clj -Auberjar
[uberdeps] Packaging target/cdeps-0.1.0.jar...
+ src/main/clojure/**
+ org.clojure/clojure 1.10.1
. org.clojure/core.specs.alpha 0.2.44
. org.clojure/spec.alpha 0.2.176
[uberdeps] Packaged target/cdeps-0.1.0.jar in 567 ms
```
And now we can run the project with Java:
```bash
$ java -cp target/cdeps-0.1.0.jar clojure.main -m com.tomekw.cdeps.core
2 + 2 is 4
4 / 2 is 2
```## Managing outdated dependencies
It's often needed to manage the versions of all dependencies we put into our `deps.edn` file. There is a tool named
[depot](https://github.com/Olical/depot):
```clojure
;; deps.edn
{:paths ["src/main/clojure"]
:deps {org.clojure/clojure {:mvn/version "1.10.1"}}
:aliases {:test {:extra-paths ["test/main/clojure"]
:extra-deps {lambdaisland/kaocha {:mvn/version "0.0-529"}}
:main-opts ["-m" "kaocha.runner"]}
:outdated {:extra-deps {olical/depot {:mvn/version "1.8.4"}}
:main-opts ["-m" "depot.outdated.main" "-a" "outdated"]}
:uberjar {:extra-deps {uberdeps {:mvn/version "0.1.4"}}
:main-opts ["-m" "uberdeps.uberjar" "--target" "target/cdeps-0.1.0.jar"]}}}
```
Everything should be up to date:
```bash
$ clj -Aoutdated
All up to date!
```## Summary
This guide covers basic use-cases in the daily workflow with Clojure. Of course there is alwats more than I presented
here, like deploying the project to [Clojars](https://clojars.org). The process is still not fully automated and I will
try to cover it with the next post.