5

My aim is to write dynamic reports which will be generated using a base skeleton file and snippets that correspond to and parametrise the particular issues. These issues are all content-wise similar and can be represented using exactly the same logical structure. The Emacs' org-mode seemed like a perfect solution given the power which comes with org-babel. My question is if there exist an Org Mode Way (tm) to deal with this problem. I will lay out my current approach below, but I hope someone has a less cumbersome solution.

The structure of my org dynamic report as follows,

  1. skeleton.org:

    • include1.org
    • include2.org
    • ...

    body

where include org files (plugged in using #+INCLUDE:) mostly contain #+MACRO macroname macro definitions and :PROPERTY: blocks.

I was originally intending to use {{{macroname}}} substitutions and to read in the parameters into the skeleton and generate the report. However, while #+MACRO: definitions work within many elements of org-mode, their major drawback is that one cannot substitute them into :var varname=value #+HEADER declarations, or #+CALL source block calls. This is why :PROPERTY: blocks seemed like a right way to go. A property value can be read into a :var with a simple elisp-to-var assignment :var=(org-get-entry nil "prop-name" t).

Unfortunately, as i found out, org-get-entry function works only for properties local to the file and current heading (and its sub-elements with third argument non-nil). This means it will not scan the files I have #+INCLUDE-ed.

My solution to this limitation was to write an elisp function to open a file, search the property entries under a particular heading and return what was found:

(defun tk-org-get-prop (heading prop)                                                                                                                                         
  "Finds a property somewhere under a heading in the current buffer."                                                                                                         
  (car (org-map-entries `(org-entry-get nil ,prop t)                                                                                                                          
                        heading)))                                                                                                                                            


(defun tk-org-get-prop-file (filename heading prop)                                                                                                                           
  "Finds a property somewhere under a heading in the file."                                                                                                                   
  (with-current-buffer (find-file-noselect filename)                                                                                                                          
    (tk-org-get-prop heading prop)))

I can now assign property values under a specific heading in a specific file with :var somevar=(tk-org-get-prop-file "input1.org" ".*property_heading.*" "property_name") .

The aforementioned approach allows me to extract parameters from various input files and substitute them into the skeleton, but it feels hacky and it seems like there has to be a more elegant way to do that.

Ideally, I would like something like dynamic blocks (#+BEGIN :par1 val1 :par2 val2 ... #+END syntax), but generating org code instead of returning a value of some custom-written elisp writer function.

  • 1
    If you're using a language that supports the :session property, you may not need to use org mode properties to do this. In my use-case, based on R and bash source blocks, I set the session values for the file with a #+PROPERTY line at the top, then set specific parameters in the first source block for each language, right at the top of the file. The rest of the source blocks reference these variables, so they don't need to change. – Tyler Feb 9 '18 at 15:25
  • @Tyler Of course, this is one way to do this, but a) I prefer to be able to have as much of this sorted out in org (and elisp as necessary), b) I'd rather have things that change (org snippets that describe my data) separate from things that remain the same (skeleton report) since that suits the way my data is structured. – Mali Remorker Feb 11 '18 at 15:01
2

After exploring various approaches to a truly dynamic org document, I have decided to ditch paramterising it via :PROPERTIES: declaration.

I now perceive the combination of Org and pure Elisp as the most natural tool to solve the problem posed in the question. I have replaced the properties with Lisp association lists which are then fed to gnuplot source blocks using #+HEADER: :var x=(some lisp code ...) declarations. The advantages of Elisp over other Babel languages is that the session is already there, no need to fiddle with additional code blocks and their settings and that one can supply pure Elisp code to header variables :var.

In the end, I have settled for something similar to what was described in Tyler's comment, just using Elisp instead of R/bash and keeping the modularity intact by separating the main structure of the report from the plugin snippets.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.