]> code.delx.au - gnu-emacs/blobdiff - lisp/org/ob-clojure.el
Update copyright year to 2015
[gnu-emacs] / lisp / org / ob-clojure.el
index c42d9b4db388dd9f8a3ac15d58d8544b94fae1e8..dd730a29822f6bc1718e8772b60cff0d455102ca 100644 (file)
@@ -1,11 +1,11 @@
 ;;; ob-clojure.el --- org-babel functions for clojure evaluation
 
-;; Copyright (C) 2009, 2010  Free Software Foundation, Inc.
+;; Copyright (C) 2009-2015 Free Software Foundation, Inc.
 
 ;; Author: Joel Boehland
+;;     Eric Schulte
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: http://orgmode.org
-;; Version: 7.01
 
 ;; This file is part of GNU Emacs.
 
 
 ;;; Commentary:
 
-;;; ob support for evaluating clojure code
+;; Support for evaluating clojure code, relies on slime for all eval.
 
 ;;; Requirements:
 
-;;; A working clojure install. This also implies a working java executable
-;;; clojure-mode
-;;; slime
-;;; swank-clojure
+;; - clojure (at least 1.2.0)
+;; - clojure-mode
+;; - slime
 
-;;; By far, the best way to install these components is by following
-;;; the directions as set out by Phil Hagelberg (Technomancy) on the
-;;; web page: http://technomancy.us/126
+;; By far, the best way to install these components is by following
+;; the directions as set out by Phil Hagelberg (Technomancy) on the
+;; web page: http://technomancy.us/126
 
 ;;; Code:
 (require 'ob)
-(require 'ob-eval)
-(eval-when-compile (require 'cl))
 
-(declare-function slime-eval-async "ext:slime" (sexp &optional cont package))
 (declare-function slime-eval "ext:slime" (sexp &optional package))
-(declare-function swank-clojure-concat-paths "ext:slime" (paths))
-(declare-function org-babel-ref-variables "ext:slime" (params))
-(declare-function slime "ext:slime" (&optional command coding-system))
-(declare-function slime-output-buffer "ext:slime" (&optional noprompt))
-(declare-function slime-filter-buffers "ext:slime" (predicate))
 
+(defvar org-babel-tangle-lang-exts)
 (add-to-list 'org-babel-tangle-lang-exts '("clojure" . "clj"))
 
 (defvar org-babel-default-header-args:clojure '())
+(defvar org-babel-header-args:clojure '((package . :any)))
 
-(defvar org-babel-clojure-wrapper-method
-  "
-(defn spit
-  [f content]
-  (with-open [#^java.io.PrintWriter w
-                 (java.io.PrintWriter.
-                   (java.io.BufferedWriter.
-                     (java.io.OutputStreamWriter.
-                       (java.io.FileOutputStream.
-                         (java.io.File. f)))))]
-      (.print w content)))
-
-(defn main
-  []
-  %s)
-
-(spit \"%s\" (str (main)))")
-;;";; <-- syntax highlighting is messed without this double quote
-
-;;taken mostly from clojure-test-mode.el
-(defun org-babel-clojure-clojure-slime-eval (string &optional handler)
-  "Evaluate a STRING of clojure code using `slime-eval-async'."
-  (slime-eval-async `(swank:eval-and-grab-output ,string)
-                    (or handler #'identity)))
-
-(defun org-babel-clojure-slime-eval-sync (string)
-  "Evaluate a STRING of clojure code using `slime-eval'."
-  (slime-eval `(swank:eval-and-grab-output ,string)))
-
-;;taken from swank-clojure.el
-(defvar swank-clojure-binary)
-(defvar swank-clojure-classpath)
-(defvar swank-clojure-java-path)
-(defvar swank-clojure-extra-vm-args)
-(defvar swank-clojure-library-paths)
-(defvar swank-clojure-extra-classpaths)
-(defun org-babel-clojure-babel-clojure-cmd ()
-  "Create the command to start clojure according to current settings."
-  (if (and (not swank-clojure-binary) (not swank-clojure-classpath))
-      (error "%s" (concat "You must specifiy either a `swank-clojure-binary' "
-                         "or a `swank-clojure-jar-path'"))
-    (if swank-clojure-binary
-        (if (listp swank-clojure-binary)
-            swank-clojure-binary
-          (list swank-clojure-binary))
-      (delq
-       nil
-       (append
-        (list swank-clojure-java-path)
-        swank-clojure-extra-vm-args
-        (list
-         (when swank-clojure-library-paths
-           (concat "-Djava.library.path="
-                   (swank-clojure-concat-paths swank-clojure-library-paths)))
-         "-classpath"
-         (swank-clojure-concat-paths
-          (append
-           swank-clojure-classpath
-           swank-clojure-extra-classpaths))
-         "clojure.main"))))))
-
-(defun org-babel-clojure-table-or-string (results)
-  "Convert RESULTS to an elisp value.
-If RESULTS looks like a table, then convert to an Emacs-lisp
-table, otherwise return the results as a string."
-  (org-babel-read
-   (if (string-match "^\\[.+\\]$" results)
-       (org-babel-read
-        (concat "'"
-                (replace-regexp-in-string
-                 "\\[" "(" (replace-regexp-in-string
-                            "\\]" ")" (replace-regexp-in-string
-                                       ", " " " (replace-regexp-in-string
-                                                 "'" "\"" results))))))
-     results)))
-
-(defun org-babel-clojure-var-to-clojure (var)
-  "Convert an elisp value into a clojure variable.
-The elisp value VAR is converted into a string of clojure source
-code specifying a variable of the same value."
-  (if (listp var)
-      (format "'%s" var)
-    (format "%S" var)))
-
-(defun org-babel-clojure-build-full-form (body vars)
-  "Construct a clojure let form with VARS as the let variables."
-  (let ((vars-forms
-        (mapconcat ;; define any variables
-         (lambda (pair)
-           (format "%s %s"
-                   (car pair) (org-babel-clojure-var-to-clojure (cdr pair))))
-         vars "\n      "))
-       (body (org-babel-trim body)))
-    (if (> (length vars-forms) 0)
-       (format "(let [%s]\n  %s)" vars-forms body)
-      body)))
-
-(defun org-babel-prep-session:clojure (session params)
-  "Prepare SESSION according to the header arguments specified in PARAMS."
-  (require 'slime) (require 'swank-clojure)
-  (let* ((session-buf (org-babel-clojure-initiate-session session))
-         (vars (org-babel-ref-variables params))
-         (var-lines (mapcar ;; define any top level session variables
-                     (lambda (pair)
-                       (format "(def %s %s)\n" (car pair)
-                               (org-babel-clojure-var-to-clojure (cdr pair))))
-                     vars)))
-    session-buf))
-
-(defun org-babel-load-session:clojure (session body params)
-  "Load BODY into SESSION."
-  (require 'slime) (require 'swank-clojure)
-  (save-window-excursion
-    (let ((buffer (org-babel-prep-session:clojure session params)))
-      (with-current-buffer buffer
-        (goto-char (point-max))
-        (insert (org-babel-chomp body)))
-      buffer)))
-
-(defvar org-babel-clojure-buffers '())
-(defvar org-babel-clojure-pending-sessions '())
-
-(defun org-babel-clojure-session-buffer (session)
-  "Return the buffer associated with SESSION."
-  (cdr (assoc session org-babel-clojure-buffers)))
-
-(defun org-babel-clojure-initiate-session-by-key (&optional session)
-  "Initiate a clojure session in an inferior-process-buffer.
-If there is not a current inferior-process-buffer in SESSION
-then create one.  Return the initialized session."
-  (save-window-excursion
-    (let* ((session (if session
-                        (if (stringp session) (intern session)
-                          session)
-                     :default))
-           (clojure-buffer (org-babel-clojure-session-buffer session)))
-      (unless (and clojure-buffer (buffer-live-p clojure-buffer))
-        (setq org-babel-clojure-buffers
-             (assq-delete-all session org-babel-clojure-buffers))
-        (push session org-babel-clojure-pending-sessions)
-        (slime)
-        ;; we are waiting to finish setting up which will be done in
-        ;; org-babel-clojure-session-connected-hook below.
-        (let ((timeout 9))
-          (while (and (not (org-babel-clojure-session-buffer session))
-                      (< 0 timeout))
-            (message "Waiting for clojure repl for session: %s ... %i"
-                    session timeout)
-            (sit-for 1)
-            (decf timeout)))
-        (setq org-babel-clojure-pending-sessions
-              (remove session org-babel-clojure-pending-sessions))
-        (unless (org-babel-clojure-session-buffer session)
-          (error "Couldn't create slime clojure process"))
-        (setq clojure-buffer (org-babel-clojure-session-buffer session)))
-      session)))
-
-(defun org-babel-clojure-initiate-session (&optional session params)
-  "Return the slime-clojure repl buffer bound to SESSION.
-Returns nil if \"none\" is specified."
-  (require 'slime) (require 'swank-clojure)
-  (unless (and (stringp session) (string= session "none"))
-    (org-babel-clojure-session-buffer
-     (org-babel-clojure-initiate-session-by-key session))))
-
-(defun org-babel-clojure-session-connected-hook ()
-  "Finish  binding an org-babel session to a slime-clojure repl."
-  (let ((pending-session (pop org-babel-clojure-pending-sessions)))
-    (when pending-session
-      (save-excursion
-        (switch-to-buffer (slime-output-buffer))
-        (rename-buffer
-        (if (stringp pending-session)
-            pending-session (symbol-name pending-session)))
-        (org-babel-clojure-bind-session-to-repl-buffer
-        pending-session (slime-output-buffer))))))
-
-(add-hook 'slime-connected-hook 'org-babel-clojure-session-connected-hook)
-
-(defun org-babel-clojure-bind-session-to-repl-buffer (session repl-buffer)
-  "Associate SESSION with REPL-BUFFER."
-  (when (stringp session) (setq session (intern session)))
-  (setq org-babel-clojure-buffers
-        (cons (cons session repl-buffer)
-              (assq-delete-all session org-babel-clojure-buffers))))
-
-(defun org-babel-clojure-repl-buffer-pred ()
-  "Test whether the current buffer is an active slime-clojure
-repl buffer."
-  (and (buffer-live-p (current-buffer)) (eq major-mode 'slime-repl-mode)))
-
-(defun org-babel-clojure-bind-session-to-repl (session)
-  "Bind SESSION to a clojure repl."
-  (interactive "sEnter session name: ")
-  (let ((repl-bufs (slime-filter-buffers 'org-babel-clojure-repl-buffer-pred)))
-    (unless repl-bufs (error "No existing slime-clojure repl buffers exist"))
-    (let ((repl-buf (read-buffer "Choose slime-clojure repl: " repl-bufs t)))
-      (org-babel-clojure-bind-session-to-repl-buffer session repl-buf))))
-
-(defun org-babel-clojure-evaluate-external-process
-  (buffer body &optional result-type)
-  "Evaluate the body in an external process."
-  (let ((cmd (format "%s -" (mapconcat #'identity
-                                      (org-babel-clojure-babel-clojure-cmd)
-                                      " "))))
-    (case result-type
-      (output (org-babel-eval cmd body))
-      (value (let* ((tmp-file (make-temp-file "org-babel-clojure-results-")))
-              (org-babel-eval cmd (format org-babel-clojure-wrapper-method
-                                          body tmp-file tmp-file))
-              (org-babel-clojure-table-or-string
-               (org-babel-eval-read-file tmp-file)))))))
-
-(defun org-babel-clojure-evaluate-session (buffer body &optional result-type)
-  "Evaluate the body in the context of a clojure session."
-  (require 'slime) (require 'swank-clojure)
-  (let ((raw nil)
-        (results nil))
-    (with-current-buffer buffer
-      (setq raw (org-babel-clojure-slime-eval-sync body))
-      (setq results (reverse (mapcar #'org-babel-trim raw)))
-      (cond
-       ((equal result-type 'output)
-       (mapconcat #'identity (reverse (cdr results)) "\n"))
-       ((equal result-type 'value)
-       (org-babel-clojure-table-or-string (car results)))))))
-
-(defun org-babel-clojure-evaluate (buffer body &optional result-type)
-  "Pass BODY to the Clojure process in BUFFER.
-If RESULT-TYPE equals 'output then return a list of the outputs
-of the statements in BODY, if RESULT-TYPE equals 'value then
-return the value of the last statement in BODY as elisp."
-  (if buffer
-      (org-babel-clojure-evaluate-session buffer body result-type)
-    (org-babel-clojure-evaluate-external-process buffer body result-type)))
-
-(defun org-babel-expand-body:clojure (body params &optional processed-params)
+(defun org-babel-expand-body:clojure (body params)
   "Expand BODY according to PARAMS, return the expanded body."
-  (org-babel-clojure-build-full-form
-   body (nth 1 (or processed-params (org-babel-process-params params)))))
+  (let* ((vars (mapcar #'cdr (org-babel-get-header params :var)))
+        (result-params (cdr (assoc :result-params params)))
+        (print-level nil) (print-length nil)
+        (body (org-babel-trim
+               (if (> (length vars) 0)
+                   (concat "(let ["
+                           (mapconcat
+                            (lambda (var)
+                              (format "%S (quote %S)" (car var) (cdr var)))
+                            vars "\n      ")
+                           "]\n" body ")")
+                 body))))
+    (cond ((or (member "code" result-params) (member "pp" result-params))
+          (format (concat "(let [org-mode-print-catcher (java.io.StringWriter.)] "
+                          "(clojure.pprint/with-pprint-dispatch clojure.pprint/%s-dispatch "
+                          "(clojure.pprint/pprint (do %s) org-mode-print-catcher) "
+                          "(str org-mode-print-catcher)))")
+                  (if (member "code" result-params) "code" "simple") body))
+         ;; if (:results output), collect printed output
+         ((member "output" result-params)
+          (format "(clojure.core/with-out-str %s)" body))
+         (t body))))
 
 (defun org-babel-execute:clojure (body params)
-  "Execute a block of Clojure code."
-  (require 'slime) (require 'swank-clojure)
-  (let* ((processed-params (org-babel-process-params params))
-         (body (org-babel-expand-body:clojure body params processed-params))
-         (session (org-babel-clojure-initiate-session
-                  (first processed-params))))
-    (org-babel-reassemble-table
-     (org-babel-clojure-evaluate session body (nth 3 processed-params))
-     (org-babel-pick-name
-      (nth 4 processed-params) (cdr (assoc :colnames params)))
-     (org-babel-pick-name
-      (nth 5 processed-params) (cdr (assoc :rownames params))))))
+  "Execute a block of Clojure code with Babel."
+  (require 'slime)
+  (with-temp-buffer
+    (insert (org-babel-expand-body:clojure body params))
+    (let ((result
+           (slime-eval
+            `(swank:eval-and-grab-output
+              ,(buffer-substring-no-properties (point-min) (point-max)))
+            (cdr (assoc :package params)))))
+      (let ((result-params (cdr (assoc :result-params params))))
+        (org-babel-result-cond result-params
+          result
+          (condition-case nil (org-babel-script-escape result)
+            (error result)))))))
 
 (provide 'ob-clojure)
 
-;; arch-tag: a43b33f2-653e-46b1-ac56-2805cf05b7d1
+
 
 ;;; ob-clojure.el ends here