litorgy-R.el 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. ;;; litorgy-R.el --- litorgy functions for R code evaluation
  2. ;; Copyright (C) 2009 Eric Schulte
  3. ;; Author: Eric Schulte
  4. ;; Keywords: literate programming, reproducible research, R, statistics
  5. ;; Homepage: http://orgmode.org
  6. ;; Version: 0.01
  7. ;;; License:
  8. ;; This program is free software; you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation; either version 3, or (at your option)
  11. ;; any later version.
  12. ;;
  13. ;; This program is distributed in the hope that it will be useful,
  14. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;; GNU General Public License for more details.
  17. ;;
  18. ;; You should have received a copy of the GNU General Public License
  19. ;; along with GNU Emacs; see the file COPYING. If not, write to the
  20. ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  21. ;; Boston, MA 02110-1301, USA.
  22. ;;; Commentary:
  23. ;; Litorgy support for evaluating R code
  24. ;;; Code:
  25. (require 'litorgy)
  26. (litorgy-add-interpreter "R")
  27. (defvar litorgy-R-func-name "litorgy_R_main"
  28. "This is the main function which wraps each R source code
  29. block.")
  30. (defun litorgy-execute:R (body params)
  31. "Execute a block of R code with litorgy. This function is
  32. called by `litorgy-execute-src-block'."
  33. (message "executing R source code block...")
  34. (save-window-excursion
  35. (let ((vars (litorgy-ref-variables params))
  36. results)
  37. (litorgy-R-initiate-R-buffer)
  38. (mapc (lambda (pair) (litorgy-R-assign-elisp (car pair) (cdr pair))) vars)
  39. (litorgy-R-input-command
  40. (format "%s <- function ()\n{\n%s\n}" litorgy-R-func-name body))
  41. (litorgy-R-to-elisp litorgy-R-func-name))))
  42. (defun litorgy-R-quote-tsv-field (s)
  43. "Quote field S for export to R."
  44. (concat "\"" (mapconcat 'identity (split-string s "\"") "\"\"") "\""))
  45. (defun litorgy-R-assign-elisp (name value)
  46. "Read the elisp VALUE into a variable named NAME in the current
  47. R process in `litorgy-R-buffer'."
  48. (unless litorgy-R-buffer
  49. (error "No active R buffer"))
  50. (if (listp value)
  51. (let ((transition-file (make-temp-file "litorgy-R-import"))
  52. (value (mapcar (lambda (row)
  53. (mapcar (lambda (cell)
  54. (if (stringp cell)
  55. cell
  56. (format "%S" cell))) row)) value)))
  57. (with-temp-file transition-file
  58. ;; DED: I think the :sep "\t" is redundant here as
  59. ;; orgtbl-to-tsv adds it automatically?
  60. (insert (orgtbl-to-tsv value '(:sep "\t" :fmt litorgy-R-quote-tsv-field)))
  61. (insert "\n"))
  62. (litorgy-R-input-command
  63. (format "%s <- read.table(\"%s\", sep=\"\\t\", as.is=TRUE)" name transition-file)))))
  64. (defun litorgy-R-to-elisp (func-name)
  65. "Return the result of calling the function named FUNC-NAME in
  66. `litorgy-R-buffer' as Emacs lisp."
  67. (let ((tmp-file (make-temp-file "litorgy-R")) result)
  68. (litorgy-R-input-command
  69. (format "write.table(%s(), \"%s\", , ,\"\\t\", ,\"nil\", , FALSE, FALSE)" func-name tmp-file))
  70. (with-temp-buffer
  71. (org-table-import tmp-file nil)
  72. (delete-file tmp-file)
  73. (setq result (mapcar (lambda (row)
  74. (mapcar #'litorgy-R-read row))
  75. (org-table-to-lisp)))
  76. (if (null (cdr result)) ;; if result is trivial vector, then scalarize it
  77. (if (consp (car result))
  78. (if (null (cdr (car result)))
  79. (caar result)
  80. result)
  81. (car result))
  82. result))))
  83. (defun litorgy-R-read (cell)
  84. "Strip nested \"s from around strings in exported R values."
  85. (litorgy-read (or (and (stringp cell)
  86. (string-match "\\\"\\(.+\\)\\\"" cell)
  87. (match-string 1 cell))
  88. cell)))
  89. ;; functions for evaluation of R code
  90. (defvar litorgy-R-buffer nil
  91. "Holds the buffer for the current R process")
  92. (defun litorgy-R-initiate-R-buffer ()
  93. "If there is not a current R process then create one."
  94. ;; DED: Ideally I think we should use ESS mechanisms for this sort
  95. ;; of thing. See ess-force-buffer-current.
  96. (unless (and (buffer-live-p litorgy-R-buffer) (get-buffer litorgy-R-buffer))
  97. (save-excursion
  98. (R)
  99. (setf litorgy-R-buffer (current-buffer))
  100. (litorgy-R-wait-for-output)
  101. (litorgy-R-input-command ""))))
  102. (defun litorgy-R-command-to-string (command)
  103. "Send a command to R, and return the results as a string."
  104. (litorgy-R-input-command command)
  105. (litorgy-R-last-output))
  106. (defun litorgy-R-input-command (command)
  107. "Pass COMMAND to the R process running in `litorgy-R-buffer'."
  108. (save-excursion
  109. (save-match-data
  110. (set-buffer litorgy-R-buffer)
  111. (goto-char (process-mark (get-buffer-process (current-buffer))))
  112. (insert command)
  113. (comint-send-input)
  114. (litorgy-R-wait-for-output))))
  115. (defun litorgy-R-wait-for-output ()
  116. "Wait until output arrives"
  117. (save-excursion
  118. (save-match-data
  119. (set-buffer litorgy-R-buffer)
  120. (while (progn
  121. (goto-char comint-last-input-end)
  122. (not (re-search-forward comint-prompt-regexp nil t)))
  123. (accept-process-output (get-buffer-process (current-buffer)))))))
  124. (defun litorgy-R-last-output ()
  125. "Return the last R output as a string"
  126. (save-excursion
  127. (save-match-data
  128. (set-buffer litorgy-R-buffer)
  129. (goto-char (process-mark (get-buffer-process (current-buffer))))
  130. (forward-line 0)
  131. (let ((raw (buffer-substring comint-last-input-end (- (point) 1)))
  132. output output-flag)
  133. (mapconcat
  134. (lambda (el)
  135. (if (stringp el)
  136. (format "%s" el)
  137. (format "%S" el)))
  138. (delq nil
  139. (mapcar
  140. (lambda (line)
  141. (unless (string-match "^>" line)
  142. (and (string-match "\\[[[:digit:]]+\\] *\\(.*\\)$" line)
  143. (match-string 1 line))))
  144. ;; drop first, because it's the last line of input
  145. (cdr (split-string raw "[\n\r]")))) "\n")))))
  146. (provide 'litorgy-R)
  147. ;;; litorgy-R.el ends here