= Hacking on nREPL

This section is dedicated to people, who're hacking on nREPL itself (e.g. to fix bugs or to enhance
existing functionality).

There are generally two approaches to hacking on nREPL - you can either make some changes, build a new server
and run it locally to test your changes (e.g. via `clj`) or you can hack on nREPL in the classic
interactive Lisp manner and just make some changes and test them directly from a running (n)REPL.

== Building nREPL

NOTE: Releases are available from Clojars, and SNAPSHOT builds from master's
HEAD are automatically deployed there as well, so manually building
nREPL shouldn't ever be necessary (unless you're hacking on it).

Building nREPL locally is a very simple process:

. Clone the repo
. Make sure you have Leingingen installed
. Run the build:

[source,shell]
----
$ lein install
----

Afterwards you can simply do something like:

[source,shell]
----
$ clj -Sdeps '{:deps {nrepl {:mvn/version "1.0.0"}}}' -m nrepl.cmdline --interactive
----

Now you can start playing the server you've built.

== Interactive Hacking

As nREPL is fundamental to the development workflows of many people it might be
unclear how exactly you can hack on it, while at the same time you're already
running an nREPL server, powering the REPL in which you're doing to hacking.

Developing nREPL while connected to nREPL is a classic example of eating your own dog food.

The development process is actually pretty simple - you just need to
connect to nREPL as you'd normally would (e.g. by using CIDER, vim-iced or Calva), make
some changes and test them by starting new nREPL instances from the
REPL and connecting to them to see how they are having.

In practice it might not be convenient to spin many nREPL connections
from your editor, so a combination of `nrepl.server/start-server` and
`nrepl.core/connect` is a very good alternative.

[source,clojure]
----
;; first we have to start a new server
=> (require '[nrepl.server :refer [start-server stop-server]])
nil
=> (def server (start-server :port 7888))
='user/server
=> (require '[nrepl.core :as nrepl])
nil
;; now you can connect to the server and send it some messages
=> (with-open [conn (nrepl/connect :port 7888)]
     (-> (nrepl/client conn 1000)    ; message receive timeout required
         (nrepl/message {:op "eval" :code "(+ 2 3)"})
         nrepl/response-values))
;; when you're done with a server you can stop it
=> (stop-server server)
----


NOTE: You don't really need an nREPL-powered REPL for this
workflow. It's going to work in exactly the same manner regardless of
the REPL you're using.

== Running the tests

The primary way to run tests is using Kaocha. The following command runs
the test suite on Clojure 1.10:

[source,shell]
----
$ bin/kaocha
----

The following command is useful while actively working on the codebase:

[source,shell]
----
$ bin/kaocha --watch --skip-meta :slow
----

as it will re-run tests on changes, but also skip a handful of slower tests.

=== Running test for Clojure 1.7 and 1.8

Kaocha only supports Clojure 1.9 and up. For earlier versions, we can still use
Leiningen's test runner. To run the tests only for a specific version of Clojure,
use a command like this:

[source,shell]
----
$ lein with-profile 1.8 test
----

To run tests for all Clojure versions from 1.7 to 1.10.

[source,shell]
----
$ lein test-all
----

=== Running tests on CI

For ease of use/consistency with other nREPL projects, tests are ran on CI
environments using a `Makefile`, with the command:

[source,shell]
----
$ make test
----

this will check the `VERSION` environmental variable, and switch between Kaocha
and Leiningen tests based on which is available.

== Running cljfmt

Our CI build enforces consistent indentation in all source files using `cljfmt`. You can run it
locally using:

[source,shell]
----
$ lein with-profile cljfmt cljfmt check
----

You can have cljfmt fix indentation problems like this:

[source,shell]
----
$ lein with-profile cljfmt cljfmt fix
----

== Running Eastwood

Our CI build enforces some lint checks via `Eastwood`. You can run it
locally using:

[source,shell]
----
$ lein with-profile eastwood eastwood
----

== Regenerating the Built-in Ops Documentation

If you've made any changes to the built-in middleware descriptors you can regenerate their documentation using:

[source,shell]
----
$ lein docs
----
