Prechádzať zdrojové kódy

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.
Aaron Ecay 11 rokov pred
rodič
commit
08e2596718
5 zmenil súbory, kde vykonal 142 pridanie a 12 odobranie
  1. 25 0
      doc/org.texi
  2. 11 12
      lisp/ob-R.el
  3. 50 0
      lisp/ob-core.el
  4. 34 0
      testing/examples/babel.org
  5. 22 0
      testing/lisp/test-ob.el

+ 25 - 0
doc/org.texi

@@ -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

+ 11 - 12
lisp/ob-R.el

@@ -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))))

+ 50 - 0
lisp/ob-core.el

@@ -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))))
 

+ 34 - 0
testing/examples/babel.org

@@ -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

+ 22 - 0
testing/lisp/test-ob.el

@@ -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