Training camp for the new hope of Clojure. This is a pre-configured project that you can use to do exercises from the book:
Living Clojure by Carin Meier
Exercises are given in a weekly plan in Chapter 10.
Please have the following installed:
- Leiningen build tool
- IntelliJ IDEA + Cursive plugin
Fork this repo and clone.
The workflow is called "REPL Driven Development". REPL stands for Read-Evaluate-Print-Loop and means interpreter command line mode.
The goal of the workflow is to reduce the turnaround time (aka feedback loop) in the development microcycle:
Edit the code -> Run it -> Repeat
To prepare for work, do the following steps:
- Open the cloned folder in IntelliJ, it should automatically recognize the project type as Leiningen and load it.
- Right-click on the project name in the project pane and select "Run 'REPL for new-hope'"
- After the REPL loads, run
(refresh)
in it once.
This is your initial position. You have a code editor, you have a JVM instance running and a REPL session attached to it. All the project source code is loaded into the JVM.
Most of the time with REPL Driven Development you evaluate expressions and look at their results.
You can type commands into the REPL and press Ctrl-Enter (Cmd-Enter) to evaluate them in the context of the user
namespace.
(comment
(conj [1 2 3] 4)
)
It's just a scratchpad, a comment block containing code snippets. To evaluate a snippet, set the caret to the closing parenthesis and use REPL -> Send '...' to REPL context menu action. The expression will be evaluated in the context of the current source file namespace (e.g. new-hope.week1
).
New lines don't matter, any expression can be evaluated this way.
- If you set the caret after
4
, only4
will be evaluated, yielding4
. - If you set the caret on
]
, the vector[1 2 3]
will be evaluated, yielding[1 2 3]
. - If you set the caret on
)
, the entire(conj [1 2 3] 4)
form will be evaluated, yielding[1 2 3 4]
. - If you set the caret on the closing
)
of the comment block, the comment block will be evaluated (by doing nothing), yieldingnil
.
In real projects unit tests are kept separately from the production code, but for simplicity's sake here we put them right next to it.
Unit tests are expressions too, like any other Clojure code. When you evaluate a unit test, it returns true or false, and prints error messages if there are any issues.
(facts "about first"
(first [1 2 3]) => 1)
To execute a unit test, use REPL -> Send '...' to REPL context menu action.
The unit testing library is called Midje.
(def second-to-last
(fn [coll]
(second (reverse coll))))
Definitions are also expressions, when evaluated, they create a binding in the JVM between the name and the meaning, so that the name can be used afterwards in the code. Every time the definition is evaluated, the binding in the JVM is updated. Also can be executed with REPL -> Send '...' to REPL.
In order to avoid mouse clicking it's handy to set a key combination, like Ctrl-Shift-Cmd-R for the "REPL -> Send '...' to REPL" action.
There are actions in the Tools -> REPL menu or in the REPL context menu to evaluate every expression in the current file (Load file) or in every file that has changed since last reload (Sync files).
The same effect is achieved by running (refresh)
function in the REPL directly (in the user
namespace).
Contents of the comment
blocks are ignored.
When a file is reloaded, all the unit tests in it are automatically run.
Starting from Week 1 Day 4, the goal of every exercise is to write a funtction.
Correctness of the implementation can be checked on the exercise webpage, and the checker there expects it to be in the form of anonymous function:
(fn [<args>] <body>)
In order to keep like this, the recommended way of working on an exercise is:
;; Name that we use for unit-testing
(def second-to-last
;; The actual implementation that can be checked on 4clojure.org
(fn [coll]
(second (reverse coll))))
(comment
;; Some relevant snippets
(reverse [1 2 3 4])
)
(facts "about second-to-last"
;; Some unit-tests
(second-to-last [1 2 3 4]) => 3)
- Create an empty definition of the function.
- Use
comment
block to play around and experiment. - Write unit tests that check correctness of your implementation once you figure it out.
Press and hold Ctrl (Cmd) and hover your mouse cursor over a symbol — it will show the function signature.
Ctrl (Cmd) and click — it will go to definition.
To run all the unit tests without starting the REPL, run
$ lein midje
from the project directory.
Read this: https://github.com/bbatsov/clojure-style-guide and try to follow. Always format your code before checking in.
Copyright © 2016 Dmitrii Balakhonskii
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.