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

Reply via email to