From 6698edbe83d18d599786180f3d4422301d78a2c4 Mon Sep 17 00:00:00 2001 From: Eric Schulte Date: Thu, 11 Jun 2009 15:15:59 -0700 Subject: [PATCH] finally think I'm on the right track for output vs. values, mostly working w/ruby - moved ruby functions into their own buffer - removed org-babel-sessions.el - drastically scaled down org-babel-comint.el (may grow later if we find duplication between language buffers) - removed org-babel-script.el - adjusted org-babel-init.el to reflect new file layout For the big breakthrough see `org-babel-ruby-evaluate' in org-babel-ruby.el. This will be the model upon which all future language evaluations will be built. --- lisp/org-babel-comint.el | 62 ----------------- lisp/org-babel-init.el | 4 +- lisp/org-babel-ruby.el | 133 +++++++++++++++++++++++++++++++++++ lisp/org-babel-script.el | 142 -------------------------------------- lisp/org-babel-session.el | 46 ------------ org-babel.org | 42 ++++++----- 6 files changed, 161 insertions(+), 268 deletions(-) create mode 100644 lisp/org-babel-ruby.el delete mode 100644 lisp/org-babel-script.el delete mode 100644 lisp/org-babel-session.el diff --git a/lisp/org-babel-comint.el b/lisp/org-babel-comint.el index f015c6c7d..ca2fdd97d 100644 --- a/lisp/org-babel-comint.el +++ b/lisp/org-babel-comint.el @@ -51,67 +51,5 @@ body inside the protection of `save-window-excursion' and (set-buffer buffer) ,@body))) -(defun org-babel-comint-append-output-filter (text) - (setq string-buffer (concat string-buffer text))) - -(defmacro org-babel-comint-with-output (&rest body) - `(let ((string-buffer "")) - (add-hook 'comint-output-filter-functions 'org-babel-comint-append-output-filter) - (condition-case nil (progn ,@body) (t)) - (remove-hook 'comint-output-filter-functions 'org-babel-comint-append-output-filter) - string-buffer)) - -(defun org-babel-comint-command-to-output (buffer cmd) - "Pass CMD to BUFFER using `org-babel-comint-input-command', and -then return the a list of the output(s) generated by CMD." - (let ((raw (org-babel-comint-with-output - (org-babel-comint-input-command buffer cmd)))) - (mapcar #'org-babel-chomp - ;; split the output along prompts - (split-string - ;; remove CMD if it is at the front of the output - (if (string= cmd (substring raw 0 (length cmd))) - (substring raw (length cmd)) - raw) - comint-prompt-regexp)))) - -(defun org-babel-comint-input-command (buffer cmd) - "Pass CMD to BUFFER The input will not be echoed." - (org-babel-comint-in-buffer buffer - (goto-char (process-mark (get-buffer-process buffer))) - (insert cmd) - (comint-send-input) - (org-babel-comint-wait-for-output buffer))) - -(defun org-babel-comint-wait-for-output (buffer) - "Wait until output arrives" - (org-babel-comint-in-buffer buffer - (while (progn - (goto-char comint-last-input-end) - (not (and (re-search-forward comint-prompt-regexp nil t) - (goto-char (match-beginning 0)) - (string= (face-name (face-at-point)) - "comint-highlight-prompt")))) - (accept-process-output (get-buffer-process buffer))))) - -(defun org-babel-comint-command-to-last (buffer cmd) - "Pass CMD to BUFFER using `org-babel-comint-input-command', and -then return the result as a string using -`org-babel-comint-last-value'." - (org-babel-comint-input-command buffer cmd) - (org-babel-comint-last-value buffer)) - -(defun org-babel-comint-last-value (buffer) - "Return the last comint output in BUFFER as a string." - (org-babel-comint-in-buffer buffer - (goto-char (process-mark (get-buffer-process buffer))) - (forward-line 0) - (org-babel-clean-text-properties - (buffer-substring (+ comint-last-input-end - ;; because comint insists on echoing input - (- comint-last-input-end - comint-last-input-start)) - (- (point) 1))))) - (provide 'org-babel-comint) ;;; org-babel-comint.el ends here diff --git a/lisp/org-babel-init.el b/lisp/org-babel-init.el index 53f8c741f..d5c8116c7 100644 --- a/lisp/org-babel-init.el +++ b/lisp/org-babel-init.el @@ -36,10 +36,10 @@ (require 'org-babel-ref) (require 'org-babel-exp) (require 'org-babel-table) -(require 'org-babel-session) +(require 'org-babel-comint) ;; language specific files -(require 'org-babel-script) +(require 'org-babel-ruby) (require 'org-babel-shell) (require 'org-babel-lisp) (require 'org-babel-R) diff --git a/lisp/org-babel-ruby.el b/lisp/org-babel-ruby.el new file mode 100644 index 000000000..c7c087679 --- /dev/null +++ b/lisp/org-babel-ruby.el @@ -0,0 +1,133 @@ +;;; org-babel-ruby.el --- org-babel functions for ruby + +;; Copyright (C) 2009 Eric Schulte + +;; Author: Eric Schulte +;; Keywords: literate programming, reproducible research +;; Homepage: http://orgmode.org +;; Version: 0.01 + +;;; License: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; Org-Babel support for evaluating ruby source code. + +;;; Code: +(require 'org-babel) +(require 'inf-ruby) + +(org-babel-add-interpreter "ruby") + +(defun org-babel-execute:ruby (body params) + "Execute a block of Ruby code with org-babel. This function is +called by `org-babel-execute-src-block'." + (message "executing Ruby source code block") + (let* ((vars (org-babel-ref-variables params)) + (result-params (split-string (or (cdr (assoc :results params)) ""))) + (result-type (cond ((member "output" result-params) 'output) + ((member "output" result-params) 'value) + (t 'value))) + (full-body (concat + (mapconcat ;; define any variables + (lambda (pair) + (format "\t%s=%s" + (car pair) + (org-babel-ruby-var-to-ruby (cdr pair)))) + vars "\n") "\n" body "\n")) ;; then the source block body + (session (org-babel-ruby-initiate-session)) + (results (org-babel-ruby-evaluate session full-body result-type))) + (case result-type ;; process results based on the result-type + ('output (let ((tmp-file (make-temp-file "org-babel-ruby"))) + (with-temp-file tmp-file (insert results)) + (org-babel-import-elisp-from-file tmp-file))) + ('value (org-babel-ruby-table-or-results results))))) + +(defun org-babel-ruby-var-to-ruby (var) + "Convert an elisp var into a string of ruby or python source +code specifying a var of the same value." + (if (listp var) + (concat "[" (mapconcat #'org-babel-ruby-var-to-ruby var ", ") "]") + (format "%S" var))) + +(defun org-babel-ruby-table-or-results (results) + "If the results look like a table, then convert them into an +Emacs-lisp table, otherwise return the results as a string." + (org-babel-read + (if (string-match "^\\[.+\\]$" results) + (org-babel-read + (replace-regexp-in-string + "\\[" "(" (replace-regexp-in-string + "\\]" ")" (replace-regexp-in-string + ", " " " (replace-regexp-in-string + "'" "\"" results))))) + results))) + +;; functions for interacting with comint sessions +(defvar org-babel-ruby-session nil) + +(defun org-babel-ruby-initiate-session () + "If there is not a current inferior-process-buffer in SESSION +then create. Return the initialized session." + (setq org-babel-ruby-session (save-window-excursion + (funcall #'run-ruby nil) + (current-buffer)))) + +(defvar org-babel-ruby-last-value-eval "_" + "When evaluated by Ruby this returns the return value of the last statement.") +(defvar org-babel-ruby-eoe-indicator ":org_babel_ruby_eoe" + "Used to indicate that evaluation is has completed.") + +(defun org-babel-ruby-evaluate (buffer body &optional to-return) + "Pass BODY to the Ruby process in BUFFER. If TO-RETURN equals +'output then return a list of the outputs of the statements in +BODY, if TO-RETURN equals 'value then return the value of the +last statement in BODY." + (org-babel-comint-in-buffer buffer + (let ((string-buffer "") + (full-body (mapconcat #'org-babel-chomp + (list body org-babel-ruby-last-value-eval org-babel-ruby-eoe-indicator) "\n")) + results) + (flet ((my-filt (text) (setq string-buffer (concat string-buffer text)))) + ;; setup filter + (add-hook 'comint-output-filter-functions 'my-filt) + ;; pass FULL-BODY to process + (goto-char (process-mark (get-buffer-process buffer))) + (insert full-body) + (comint-send-input) + ;; wait for end-of-evaluation indicator + (while (progn + (goto-char comint-last-input-end) + (not (save-excursion (and (re-search-forward comint-prompt-regexp nil t) + (re-search-forward (regexp-quote org-babel-ruby-eoe-indicator) nil t))))) + (accept-process-output (get-buffer-process buffer))) + ;; remove filter + (remove-hook 'comint-output-filter-functions 'my-filt)) + ;; remove echo'd FULL-BODY from input + (if (string-match (replace-regexp-in-string "\n" "\r\n" (regexp-quote full-body)) string-buffer) + (setq string-buffer (substring string-buffer (match-end 0)))) + ;; split results with `comint-prompt-regexp' + (setq results (cdr (member org-babel-ruby-eoe-indicator + (reverse (mapcar #'org-babel-trim (split-string string-buffer comint-prompt-regexp)))))) + (case to-return + (output (mapconcat #'identity (reverse (cdr results)) "\n")) + (value (car results)) + (t (reverse results)))))) + +(provide 'org-babel-ruby) +;;; org-babel-ruby.el ends here diff --git a/lisp/org-babel-script.el b/lisp/org-babel-script.el deleted file mode 100644 index d3eed2fbe..000000000 --- a/lisp/org-babel-script.el +++ /dev/null @@ -1,142 +0,0 @@ -;;; org-babel-script.el --- org-babel functions for scripting languages - -;; Copyright (C) 2009 Eric Schulte - -;; Author: Eric Schulte -;; Keywords: literate programming, reproducible research -;; Homepage: http://orgmode.org -;; Version: 0.01 - -;;; License: - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 3, or (at your option) -;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. - -;;; Commentary: - -;; Org-Babel support for evaluating ruby, and python source code. - -;;; Code: -(require 'org-babel) -(require 'inf-ruby) -(require 'python) - -;; org-babel introduction and formalities -(defun org-babel-script-add-interpreter (var cmds) - (set-default var cmds) - (mapc (lambda (cmd) - (org-babel-add-interpreter cmd) - (eval - `(defun ,(intern (concat "org-babel-execute:" cmd)) (body params) - ,(concat "Evaluate a block of " cmd " script with org-babel. This function is -called by `org-babel-execute-src-block'. This function is an -automatically generated wrapper for `org-babel-script-execute'.") - (org-babel-script-execute ,cmd body params)))) - cmds)) - -(defcustom org-babel-script-interpreters '("ruby" "python") - "List of interpreters of scripting languages which can be -executed through org-babel." - :group 'org-babel - :set 'org-babel-script-add-interpreter) - -(mapc #'org-babel-add-interpreter org-babel-script-interpreters) - -;; main execute function used by org-babel -(defun org-babel-script-execute (interpreter body params) - "Pass BODY to INTERPRETER obeying any options set with PARAMS." - (message (format "executing %s code block..." cmd)) - (let* ((vars (org-babel-ref-variables params)) - (results-params (split-string (or (cdr (assoc :results params)) ""))) - (full-body (concat - (mapconcat ;; define any variables - (lambda (pair) - (format "\t%s=%s" - (car pair) - (org-babel-script-var-to-ruby/python (cdr pair)))) - vars "\n") body "\n"))) ;; then the source block body - (org-babel-script-initiate-session interpreter) - (cond - ((member "script" results-params) ;; collect all output - (let ((tmp-file (make-temp-file "org-babel-R-script-output"))) - ;; this is totally not working well - (org-babel-script-input-command interpreter (concat - "org_babel_io_holder = $stdout;" - (format "org_babel_tmp_file_holder = File.open('%s', 'w'); " tmp-file) - "$stdout = org_babel_tmp_file_holder; " - body - "org_babel_tmp_file_holder.flush; " - "$stdout = org_babel_io_holder;")) - (with-temp-buffer (insert-file-contents tmp-file) (buffer-string)))) - ((member "last" results-params) ;; the value of the last statement - (org-babel-script-input-command interpreter full-body) - (org-babel-script-table-or-results - (org-babel-script-command-to-string interpreter "_")))))) - -(defun org-babel-script-var-to-ruby/python (var) - "Convert an elisp var into a string of ruby or python source -code specifying a var of the same value." - (if (listp var) - (concat "[" (mapconcat #'org-babel-script-var-to-ruby/python var ", ") "]") - (format "%S" var))) - -(defun org-babel-script-table-or-results (results) - "If the results look like a table, then convert them into an -Emacs-lisp table, otherwise return the results as a string." - (setq results (org-babel-chomp results)) - (org-babel-read - (if (string-match "^\\[.+\\]$" results) - ;; somewhat hacky, but thanks to similarities between languages - ;; it seems to work - (org-babel-read - (replace-regexp-in-string - "\\[" "(" (replace-regexp-in-string - "\\]" ")" (replace-regexp-in-string - ", " " " (replace-regexp-in-string - "'" "\"" results))))) - (org-babel-chomp results)))) - -;; functions for interacting with comint sessions -(defvar org-babel-script-ruby-session nil) -(defvar org-babel-script-python-session nil) - -(defun org-babel-script-session (interpreter) - (case (if (symbolp interpreter) interpreter (intern interpreter)) - ('ruby 'org-babel-script-ruby-session) - ('python 'org-babel-script-python-session))) - -(defun org-babel-script-initiate-session (interpreter) - "If there is not a current inferior-process-buffer in SESSION -then create. Return the initialized session." - (case (intern (format "%s" interpreter)) - ('ruby - (setq org-babel-script-ruby-session (save-window-excursion - (funcall #'run-ruby nil) - (current-buffer)))) - ('python - (setq org-babel-script-python-session (save-window-excursion - (funcall #'run-python) - (current-buffer)))))) - -(defun org-babel-script-input-command (interpreter cmd) - (org-babel-comint-input-command - (eval (org-babel-script-session interpreter)) (org-babel-chomp cmd))) - -(defun org-babel-script-command-to-string (interpreter cmd) - (org-babel-comint-command-to-string - (eval (org-babel-script-session interpreter)) (org-babel-chomp cmd))) - -(provide 'org-babel-script) -;;; org-babel-script.el ends here diff --git a/lisp/org-babel-session.el b/lisp/org-babel-session.el deleted file mode 100644 index a63443ef1..000000000 --- a/lisp/org-babel-session.el +++ /dev/null @@ -1,46 +0,0 @@ -;;; org-babel-session.el --- session management for org-babel - -;; Copyright (C) 2009 Eric Schulte, Dan Davison - -;; Author: Eric Schulte, Dan Davison -;; Keywords: literate programming, reproducible research -;; Homepage: http://orgmode.org -;; Version: 0.01 - -;;; License: - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 3, or (at your option) -;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. - -;;; Commentary: - -;; Org-Babel evaluates code in the context of consistent sessions. -;; This file will hold functions for interacting with these sections. -;; -;; For more information see org-babel.org in the top level directory. - -;;; Code: -(require 'org-babel) - -(defcustom org-babel-session-defaults nil - "An a-list associating each org-babel interpreter with a -default session buffer." - :group 'org-babel - :type 'alist) - - - -(provide 'org-babel-session) -;;; org-babel-session.el ends here diff --git a/org-babel.org b/org-babel.org index d6929042c..2ca85a563 100644 --- a/org-babel.org +++ b/org-babel.org @@ -496,7 +496,6 @@ executions. 5 #+end_src - *** TODO rework evaluation lang-by-lang [0/4] This should include... @@ -510,6 +509,32 @@ This should include... - sessions in comint buffers +**** TODO Ruby [3/4] + +- [X] functional results working with comint +- [X] script results +- [X] ensure callable by other source block +- [ ] rename buffer after session + +#+srcname: ruby-use-last-output +#+begin_src ruby :results replace +a = 2 +b = 4 +c = a + b +[a, b, c, 78] +#+end_src + +#+resname: ruby-use-last-output +| 2 | 4 | 6 | 78 | + +#+srcname: task-call-use-last-output +#+begin_src ruby :var last=ruby-use-last-output :results replace +last.flatten.size +#+end_src + +#+resname: task-call-use-last-output +: 4 + **** TODO R [3/3] - [X] functional results working with comint @@ -549,21 +574,6 @@ twoentyseven (setq debug-on-error t) #+end_src -**** TODO Ruby [1/4] - -- [X] functional results working with comint -- [ ] script results -- [ ] ensure callable by other source block -- [ ] rename buffer after session - -#+srcname: ruby-use-last-output -#+begin_src ruby :results replace script -a = 2 -b = 4 -c = a + b -c * (a + b) -#+end_src - **** TODO Python **** TODO Shells