emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [O] [RFC] [PATCH] ob-core.el: allow the auto-generation of output fi


From: Aaron Ecay
Subject: Re: [O] [RFC] [PATCH] ob-core.el: allow the auto-generation of output file names for src blocks.
Date: Sun, 27 Apr 2014 22:18:23 -0400
User-agent: Notmuch/0.17+160~g03680d1 (http://notmuchmail.org) Emacs/24.4.50.2 (x86_64-unknown-linux-gnu)

Hi Eric, Bastien, Achim,

Thanks so much for the feedback.  I’ve adopted the :file-ext approach
suggested by Bastien, leaving the previous default behavior in place for
blocks with a :file argument.

2014ko apirilak 22an, Eric Schulte-ek idatzi zuen:

[...]


> One option might be to borrow naming behavior from the comment
> functionality in ob-tangle which looks like the following (from line 426
> in ob-tangle.el).
>
> (let (...
>       (source-name
>        (intern (or (nth 4 info)       ; explicit #+name:
>                    (format "%s:%d"    ; constructed from header and position
>                            (or (ignore-errors (nth 4 
> (org-heading-components)))
>                                "No heading")
>                            block-counter))))
>       ...))

I’m not sure I like this approach.  It relies on counting source
blocks, so an addition/deletion of a block could change the index.
I’m worried that this can lead to the accumulation of many output
files: heading:1.ext, heading:2.ext, ... all with no clear indication
of what block they were spawned by.  It would also be possible for
the result links in the buffer to become inconsistent with the actual
block:auto-generated name mapping.

I think I would prefer the code in this patch to do nothing in this case
(not create a :file value), but for language-specific code that needs a
:file to raise an error to prompt the user to add a name.

>
>>
>> 2. should :output-dir apply to the :file case as well?
>>
>
> If you mean "should :output-dir be used as the base when :file is a
> relative pathname" then I'd say "yes", and I think if this isn't the
> current behavior then the current behavior should be changed.

Achim raises a backwards compatibility concern.  I am not sure how
serious it is: the default settings (no :output-dir) are backwards
compatible, and if users set that arg we ought to just give them what
they ask for.

Nonetheless, the new version of the patch conservatively obeys Achim’s
suggestion.  I can change this to your suggestion, if that is the
consensus.

To address a comment from Bastien: :output-dir accepts absolute as well
as relative directory names.  Referring to a “subdirectory” was a
mistake on my part; the docs in the new patch should be clearer.

The updated patch (now with docs and tests) is attached to this email.

Thanks again,

--
Aaron Ecay
>From 4b428820432752117c60b79da0a79fd4e50e4ba1 Mon Sep 17 00:00:00 2001
From: Aaron Ecay <address@hidden>
Date: Tue, 22 Apr 2014 15:13:48 -0400
Subject: [PATCH] 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.
* 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.
---
 doc/org.texi               | 27 +++++++++++++++++++++++++++
 lisp/ob-core.el            | 34 ++++++++++++++++++++++++++++++++++
 testing/examples/babel.org | 34 ++++++++++++++++++++++++++++++++++
 testing/lisp/test-ob.el    | 14 ++++++++++++++
 4 files changed, 109 insertions(+)

diff --git a/doc/org.texi b/doc/org.texi
index 2546be1..79cc044 100644
--- a/doc/org.texi
+++ b/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,31 @@ 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.
 
address@hidden file-ext
address@hidden @code{:file-ext}
address@hidden @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
address@hidden:} 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.
+
address@hidden output-dir
address@hidden @code{:output-dir}
address@hidden @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 is
+combined with the @code{#+NAME:} of the source block and the value of the
address@hidden 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 dir
 @subsubsection @code{:dir} and remote execution
 @cindex @code{:dir}, src header argument
diff --git a/lisp/ob-core.el b/lisp/ob-core.el
index 1348f04..4a3683d 100644
--- a/lisp/ob-core.el
+++ b/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
@@ -2890,6 +2892,38 @@ 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 (or (cdr-safe (assq :output-dir params)) "")))
+    ;; Only operate if:
+    ;; 1. :file is not given
+    ;; 2. :file-ext is given
+    ;; 3. the source block has a #+name
+    (if (and (not file-cons) file-ext src-name)
+       (progn
+         ;; Create the :output-dir if it does not exist
+         (when (and file-ext (not (string= dir "")))
+           (make-directory dir t)
+           (unless (string-match "/\\'" dir)
+             (setq dir (concat dir "/"))))
+         (cons (cons :file (concat dir src-name "." file-ext)) params))
+      ;; Otherwise return params unmodified
+      params)))
 
 ;;; Used by backends: R, Maxima, Octave.
 (defun org-babel-graphical-output-file (params)
diff --git a/testing/examples/babel.org b/testing/examples/babel.org
index 449824f..68ba65a 100644
--- a/testing/examples/babel.org
+++ b/testing/examples/babel.org
@@ -458,3 +458,37 @@ function definition
                 "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: file-ext-file-wins2
+#+BEGIN_SRC emacs-lisp :output-dir xxx :file foo.bar
+nil
+#+END_SRC
diff --git a/testing/lisp/test-ob.el b/testing/lisp/test-ob.el
index c0ca493..fb791d6 100644
--- a/testing/lisp/test-ob.el
+++ b/testing/lisp/test-ob.el
@@ -1237,6 +1237,20 @@ 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"
+    (macrolet ((at-next (&rest body)
+                       `(progn
+                          (org-babel-next-src-block)
+                          (save-match-data ,@body))))
+      (at-next (should (equal "file-ext-basic.txt" (cdr (assq :file (nth 2 
(org-babel-get-src-block-info t)))))))
+      (at-next (should (equal "foo/file-ext-dir-relative.txt" (cdr (assq :file 
(nth 2 (org-babel-get-src-block-info t)))))))
+      (at-next (should (equal "foo/file-ext-dir-relative-slash.txt" (cdr (assq 
:file (nth 2 (org-babel-get-src-block-info t)))))))
+      (at-next (should (equal "/tmp/file-ext-dir-absolute.txt" (cdr (assq 
:file (nth 2 (org-babel-get-src-block-info t)))))))
+      (at-next (should (equal "foo.bar" (cdr (assq :file (nth 2 
(org-babel-get-src-block-info t)))))))
+      (at-next (should (equal "foo.bar" (cdr (assq :file (nth 2 
(org-babel-get-src-block-info t)))))))
+      )))
+
 (provide 'test-ob)
 
 ;;; test-ob ends here
-- 
1.9.2


reply via email to

[Prev in Thread] Current Thread [Next in Thread]