Tangling of Clojure code blocks is still broken when I test it on
Org 10.0-pre with Emacs 30.2.
Here is a test that should pass, but currently fails:
```
(ert-deftest ob-clojure/org-babel-tangle ()
"org-babel-tangle returns the exact body of the source block."
(org-test-with-temp-text-in-file
"#+begin_src clojure :tangle \"tangle.clj\" :results value\n
(+ 1 2)\n#+end_src"
(unwind-protect
(progn (org-babel-tangle)
(with-temp-buffer
(insert-file-contents "tangle.clj")
(let ((tangled (buffer-string)))
(should
(string-match-p "^(\\+ 1 2)\\\n$" tangled)))))
(delete-file "tangle.clj"))))
```
Ihor Radchenko <[email protected]> writes:
> Daniel Kraus <[email protected]> writes:
>
>> The problem is that or :results value (/the default) I only want the
>> result of the last expression and I do that `binding` of stdout to surpress
>> all other output.
>> But I guess during tangle this should just be ignored?
>> Is there a simple way to find out if `org-babel-execute:clojure` is
>> executed or tangled?
>
> You can just move this extra logic arranging :results to
> org-babel-execute:clojure.
To fix the issue for myself, I extracted the logic that wraps the body
in a print expression into its own function. Here is the code I'm
using. I can create a patch if that would help. Any suggestions for
improving the code would be appreciated.
```
(defun ob-clojure--prepare-for-evaluation (expanded-body params cljs-p)
"Wrap EXPANDED-BODY in a print expression, depending on PARAMS and CLJS-P."
(let* ((result-params (cdr (assq :result-params params)))
(output (if (member "output" result-params)
expanded-body
(concat
(if (or (member "code" result-params)
(member "pp" result-params))
(concat (if cljs-p
"(require '[cljs.pprint :refer [pprint]])"
"(require '[clojure.pprint :refer [pprint]])")
" (pprint")
"(prn ")
(if cljs-p
"(binding [cljs.core/*print-fn* (constantly nil)])"
"(binding [*out* (java.io.StringWriter.)]")
expanded-body "))"))))
output))
```
Then, org-babel-expand-body:clojure can be simplified to:
```
(defun org-babel-expand-body:clojure (body params &optional _cljs-p)
"Expand BODY according to PARAMS, return the expanded body."
(let* ((vars (org-babel--get-vars params))
(backend-override (cdr (assq :backend params)))
(org-babel-clojure-backend
(cond
(backend-override (intern backend-override))
(org-babel-clojure-backend org-babel-clojure-backend)
(t (user-error "You need to customize `org-babel-clojure-backend'
or set the `:backend' header argument"))))
(ns (or (cdr (assq :ns params))
(if (eq org-babel-clojure-backend 'cider)
(or cider-buffer-ns
(let ((repl-buf (cider-current-connection)))
(and repl-buf (buffer-local-value
'cider-buffer-ns repl-buf))))
org-babel-clojure-default-ns)))
(print-level nil)
(print-length nil))
(org-trim
(concat
;; Source block specified namespace :ns.
(and (cdr (assq :ns params)) (format "(ns %s)\n" ns))
;; Variables binding.
(if (null vars) (org-trim body)
;; Remove comments, they break (let [...] ...) bindings
(let ((body (replace-regexp-in-string "^[ ]*;+.*$" "" body)))
(format "(let [%s]\n%s)"
(mapconcat
(lambda (var)
(format "%S '%S" (car var) (cdr var)))
vars
"\n ")
body)))))))
```
The org-babel-execute:clojure function is updated to call
org-babel-expand-body:clojure to get the expanded body, and
ob-clojure--prepare-for-evaluation to wrap the body in a print
expression (depending on PARAMS and CLJS-P):
```
(defun org-babel-execute:clojure (body params &optional cljs-p)
"Execute the BODY block of Clojure code with PARAMS using Babel.
When CLJS-P is non-nil, execute with a ClojureScript backend
instead of Clojure."
(let* ((backend-override (cdr (assq :backend params)))
(org-babel-clojure-backend
(cond
(backend-override (intern backend-override))
(org-babel-clojure-backend (if cljs-p
org-babel-clojurescript-backend
org-babel-clojure-backend))
(t (user-error "You need to customize `%S'
or set the `:backend' header argument"
(if cljs-p
org-babel-clojurescript-backend
org-babel-clojure-backend)))))
;; We allow a Clojure source block to be evaluated with the
;; nbb backend and therefore have to expand the body with
;; ClojureScript syntax when we either evaluate a
;; ClojureScript source block or use the nbb backend.
(cljs-p (or cljs-p (eq org-babel-clojure-backend 'nbb))))
(let* ((expanded (org-babel-expand-body:clojure body params))
(prepared (ob-clojure--prepare-for-evaluation expanded params
cljs-p))
(result-params (cdr (assq :result-params params)))
result)
(setq result
(cond
((eq org-babel-clojure-backend 'inf-clojure)
(ob-clojure-eval-with-inf-clojure prepared params))
((eq org-babel-clojure-backend 'clojure-cli)
(ob-clojure-eval-with-cmd ob-clojure-cli-command prepared))
((eq org-babel-clojure-backend 'babashka)
(ob-clojure-eval-with-cmd ob-clojure-babashka-command prepared))
((eq org-babel-clojure-backend 'nbb)
(ob-clojure-eval-with-cmd ob-clojure-nbb-command prepared))
((eq org-babel-clojure-backend 'cider)
(ob-clojure-eval-with-cider prepared params cljs-p))
((eq org-babel-clojure-backend 'slime)
(ob-clojure-eval-with-slime prepared params))
(t (user-error "Invalid backend"))))
(org-babel-result-cond result-params
result
(condition-case nil (org-babel-script-escape result)
(error result))))))
```
--
Simon Cossar