Using Clojure with org-babel and nREPL

When I first made the switch to nREPL, I just modified the code from my from Using Clojure with org-babel and inferior-lisp post, replacing lisp-eval-string with nrepl-interactive-eval, did a quick test and assumed it was all working fine.

Couple of days ago I had to go back and fix a literate program, that's when I figured out there are couple of problems with using nREPL with org-babel. nREPL does not respect :main from project.clj so unless the first thing you evaluate in the org file is a ns declaration it will evaluate all blocks in user namespace, to fix this we have to create a buffer local variable called nrepl-buffer-ns that points to the main namespace.

# -*- mode: org; nrepl-buffer-ns: "project.core"; -*-

When you try to edit the source block using C-c ' (org-edit-src-code), new buffer org-mode creates does not inherit the namespace so any expression evaluated there again goes to user namespace to fix this below snippet adds a hook that will grab the value of nrepl-buffer-ns from the base org file and set it in the edit buffer.

(require 'ob)

(add-to-list 'org-babel-tangle-lang-exts '("clojure" . "clj"))

(defvar org-babel-default-header-args:clojure 
  '((:results . "silent")))

(defun org-babel-execute:clojure (body params)
  "Execute a block of Clojure code with Babel."
  (nrepl-interactive-eval body))

(add-hook 'org-src-mode-hook
          '(lambda ()
             (set (make-local-variable 'nrepl-buffer-ns) 
                  (with-current-buffer 
                      (overlay-buffer org-edit-src-overlay)
                    nrepl-buffer-ns))))

(provide 'ob-clojure)