Question

I have a very simple example to illustrate the problem. Consider the following code block in Perl, in an org-mode file:

#+begin_src perl :results table
return qw(1 2 3);
#+end_src

It produces the following result:

#+results:
| 1\n2\n3\n |

which is not totally satisfactory since I was expecting a full org-table.

For instance, in Python the following code:

#+begin_src python :results table
return (1, 2, 3)
#+end_src

produces this result:

#+results:
| 1 | 2 | 3 |

So that's apparently working in Python but not in Perl. Am I doing something wrong? Is this a known bug?

Was it helpful?

Solution

Since I felt a little masochistic this morning I decided to take a shot at hacking a little lisp again. I cooked up a small fix which works for your example but I can't promise it will work more complex ones. So here it comes:

org-babel defines a wrapper for each language. The perl one did not produce something babel detects as a list so I modified it. In order to not make everything formated as a table I had to check if the result was printable as a table:

(setq org-babel-perl-wrapper-method
  "
sub main {
%s
}
@r = main;
open(o, \">%s\");
if ($#r > 0) {
print o \"(\",join(\", \",@r), \")\",\"\\n\"
} else {
print o join(\"\\n\", @r), \"\\n\"
}")

You can modify this further to fit your needs if you want to.

The next thing is that the perl-evaluate method in babel does not run the output through further formating so I modified the evaluate method taking the new parts from the python-evaluate code:

(defun org-babel-perl-table-or-string (results)
  "Convert RESULTS into an appropriate elisp value.
If the results look like a list or tuple, then convert them into an
Emacs-lisp table, otherwise return the results as a string."
  (org-babel-script-escape results))


(defun org-babel-perl-evaluate (session body &optional result-type)
  "Pass BODY to the Perl process in SESSION.
If RESULT-TYPE equals 'output then return a list of the outputs
of the statements in BODY, if RESULT-TYPE equals 'value then
return the value of the last statement in BODY, as elisp."
  (when session (error "Sessions are not supported for Perl."))

    ((lambda (raw)
     (if (or (member "code" result-params)
         (member "pp" result-params)
         (and (member "output" result-params)
          (not (member "table" result-params))))
     raw
       (org-babel-perl-table-or-string (org-babel-trim raw))))

     (case result-type
       (output (org-babel-eval org-babel-perl-command body))

       (value (let ((tmp-file (org-babel-temp-file "perl-")))
        (org-babel-eval
         org-babel-perl-command
         (format org-babel-perl-wrapper-method body
             (org-babel-process-file-name tmp-file 'noquote)))
        (org-babel-eval-read-file tmp-file))))))

The new parts are org-babel-perl-table-or-string and the part in org-babel-perl-evaluate between the empty lines (plus 1 closing parenthesis at the end).

So what this now does is let perl print lists similar to the way python prints them and put the printed results through org-babel's formating procedures.


Now to the result:

A List:

#+begin_src perl :results value
return qw(1 2 3);
#+end_src

#+results:
| 1 | 2 | 3 |

A scalar:

#+begin_src perl :results value
return "Hello test 123";
#+end_src

#+results:
: Hello test 123

Ways you can use this code:

  1. Place it in scratch and M-x eval-buffer for testing
  2. Place it in a elsip src block at the beginning of your org-document
  3. Place it in your .emacs after babel is loaded
  4. Modify ob-perl.el in your lisp/org folder (might need to recompile org-mode afertwards)

I didn't not tested this much further than the output examples I gave you so if it misbehaves for other examples feel free to complain.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top