ob-core.el: allow the auto-generation of output file names for src blocks.

* lisp/ob-core.el (org-babel-generate-file-param): New function.
(org-babel-get-src-block-info): Use it.
(org-babel-merge-params): Handle :file-ext.
(org-babel-graphical-output-file): error if no :file or :file-ext.
* testing/lisp/test-ob.el (test-org-babel/file-ext-and-output-dir):
New test.
* doc/org.texi (Specific header arguments): Add doc for :file-ext and
:output-dir header args.
* lisp/ob-R.el (org-babel-expand-body:R): Don’t calculate
graphics-file.
(org-babel-execute:R): Only look for a graphics-file if needed.
This commit is contained in:
Aaron Ecay 2014-04-22 15:13:48 -04:00
parent 7c8559e339
commit 08e2596718
5 changed files with 142 additions and 12 deletions

View File

@ -14406,6 +14406,8 @@ argument in lowercase letters. The following header arguments are defined:
be collected and handled
* file:: Specify a path for file output
* file-desc:: Specify a description for file results
* file-ext:: Specify an extension for file output
* output-dir:: Specify a directory to write file output to
* dir:: Specify the default (possibly remote)
directory for code block execution
* exports:: Export code and/or results
@ -14840,6 +14842,29 @@ description for file code block results which are inserted as Org mode links
with no value the link path will be placed in both the ``link'' and the
``description'' portion of the Org mode link.
@node file-ext
@subsubsection @code{:file-ext}
@cindex @code{:file-ext}, src header argument
The value of the @code{:file-ext} header argument is used to provide an
extension to write the file output to. It is combined with the
@code{#+NAME:} of the source block and the value of the @ref{output-dir}
header argument to generate a complete file name.
This header arg will be overridden by @code{:file}, and thus has no effect
when the latter is specified.
@node output-dir
@subsubsection @code{:output-dir}
@cindex @code{:output-dir}, src header argument
The value of the @code{:output-dir} header argument is used to provide a
directory to write the file output to. It may specify an absolute directory
(beginning with @code{/}) or a relative directory (without @code{/}). It can
be combined with the @code{#+NAME:} of the source block and the value of the
@ref{file-ext} header argument to generate a complete file name, or used
along with a @ref{file} header arg.
@node dir
@subsubsection @code{:dir} and remote execution
@cindex @code{:dir}, src header argument

View File

@ -95,17 +95,15 @@ this variable.")
(defun org-babel-expand-body:R (body params &optional graphics-file)
"Expand BODY according to PARAMS, return the expanded body."
(let ((graphics-file
(or graphics-file (org-babel-graphical-output-file params))))
(mapconcat #'identity
(append
(when (cdr (assoc :prologue params))
(list (cdr (assoc :prologue params))))
(org-babel-variable-assignments:R params)
(list body)
(when (cdr (assoc :epilogue params))
(list (cdr (assoc :epilogue params)))))
"\n")))
(mapconcat #'identity
(append
(when (cdr (assoc :prologue params))
(list (cdr (assoc :prologue params))))
(org-babel-variable-assignments:R params)
(list body)
(when (cdr (assoc :epilogue params))
(list (cdr (assoc :epilogue params)))))
"\n"))
(defun org-babel-execute:R (body params)
"Execute a block of R code.
@ -117,7 +115,8 @@ This function is called by `org-babel-execute-src-block'."
(cdr (assoc :session params)) params))
(colnames-p (cdr (assoc :colnames params)))
(rownames-p (cdr (assoc :rownames params)))
(graphics-file (org-babel-graphical-output-file params))
(graphics-file (and (member "graphics" (assq :result-params params))
(org-babel-graphical-output-file params)))
(full-body
(let ((inside
(list (org-babel-expand-body:R body params graphics-file))))

View File

@ -283,6 +283,8 @@ Returns a list
;; resolve variable references and add summary parameters
(when (and info (not light))
(setf (nth 2 info) (org-babel-process-params (nth 2 info))))
(when info
(setf (nth 2 info) (org-babel-generate-file-param name (nth 2 info))))
(when info (append info (list name indent head)))))
(defvar org-babel-exp-reference-buffer nil
@ -2435,6 +2437,16 @@ parameters when merging lists."
(setq exports (funcall e-merge exports-exclusive-groups
exports '("results"))))
(setq params (cons pair (assq-delete-all (car pair) params)))))
(:file-ext
(when (cdr pair)
(setq results (funcall e-merge results-exclusive-groups
results '("file")))
(unless (or (member "both" exports)
(member "none" exports)
(member "code" exports))
(setq exports (funcall e-merge exports-exclusive-groups
exports '("results"))))
(setq params (cons pair (assq-delete-all (car pair) params)))))
(:exports
(setq exports (funcall e-merge exports-exclusive-groups
exports (split-string (cdr pair)))))
@ -2890,10 +2902,48 @@ For the format of SAFE-LIST, see `org-babel-safe-header-args'."
(member (cdr pair) (cdr entry)))
(t nil)))))))
(defun org-babel-generate-file-param (src-name params)
"Calculate the filename for source block results.
The directory is calculated from the :output-dir property of the
source block; if not specified, use the current directory.
If the source block has a #+NAME and the :file parameter does not
contain any period characters, then the :file parameter is
treated as an extension, and the output file name is the
concatenation of the directory (as calculated above), the block
name, a period, and the parameter value as a file extension.
Otherwise, the :file parameter is treated as a full file name,
and the output file name is the directory (as calculated above)
plus the parameter value."
(let* ((file-cons (assq :file params))
(file-ext-cons (assq :file-ext params))
(file-ext (cdr-safe file-ext-cons))
(dir (cdr-safe (assq :output-dir params)))
fname)
;; create the output-dir if it does not exist
(when dir
(make-directory dir t))
(if file-cons
;; :file given; add :output-dir if given
(when dir
(setcdr file-cons (concat (file-name-as-directory dir) (cdr file-cons))))
;; :file not given; compute from name and :file-ext if possible
(when (and src-name file-ext)
(if dir
(setq fname (concat (file-name-as-directory (or dir ""))
src-name "." file-ext))
(setq fname (concat src-name "." file-ext)))
(setq params (cons (cons :file fname) params))))
params))
;;; Used by backends: R, Maxima, Octave.
(defun org-babel-graphical-output-file (params)
"File where a babel block should send graphical output, per PARAMS."
(unless (assq :file params)
(if (assq :file-ext params)
(error ":file-ext given but no :file generated; did you forget to give a block a #+NAME?")
(error "No :file header argument given; cannot create graphical result.")))
(and (member "graphics" (cdr (assq :result-params params)))
(cdr (assq :file params))))

View File

@ -458,3 +458,37 @@ comments for ":var":
"0"))))
(format "elisp a:%d, b:%d, c:%d, d:%d, e:%d" a b c d e)
#+END_SRC
* =:file-ext= and =:output-dir= header args
:PROPERTIES:
:ID: 93573e1d-6486-442e-b6d0-3fedbdc37c9b
:END:
#+name: file-ext-basic
#+BEGIN_SRC emacs-lisp :file-ext txt
nil
#+END_SRC
#+name: file-ext-dir-relative
#+BEGIN_SRC emacs-lisp :file-ext txt :output-dir foo
nil
#+END_SRC
#+name: file-ext-dir-relative-slash
#+BEGIN_SRC emacs-lisp :file-ext txt :output-dir foo/
nil
#+END_SRC
#+name: file-ext-dir-absolute
#+BEGIN_SRC emacs-lisp :file-ext txt :output-dir /tmp
nil
#+END_SRC
#+name: file-ext-file-wins
#+BEGIN_SRC emacs-lisp :file-ext txt :file foo.bar
nil
#+END_SRC
#+name: output-dir-and-file
#+BEGIN_SRC emacs-lisp :output-dir xxx :file foo.bar
nil
#+END_SRC

View File

@ -1237,6 +1237,28 @@ echo \"$data\"
(org-babel-execute-src-block)))
(should (= noweb-expansions-in-cache-var 2)))))
(ert-deftest test-org-babel/file-ext-and-output-dir ()
(org-test-at-id "93573e1d-6486-442e-b6d0-3fedbdc37c9b"
(org-babel-next-src-block)
(should (equal "file-ext-basic.txt"
(cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))
(org-babel-next-src-block)
(should (equal "foo/file-ext-dir-relative.txt"
(cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))
(org-babel-next-src-block)
(should (equal "foo/file-ext-dir-relative-slash.txt"
(cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))
(org-babel-next-src-block)
(should (equal "/tmp/file-ext-dir-absolute.txt"
(cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))
(org-babel-next-src-block)
(should (equal "foo.bar"
(cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))
(org-babel-next-src-block)
(should (equal "xxx/foo.bar"
(cdr (assq :file (nth 2 (org-babel-get-src-block-info t))))))
))
(provide 'test-ob)
;;; test-ob ends here