6

I am using the following code snippet to write environments out to files and run arbitrary commands (like python or Rscript). It works quite nice however I would like to write something to the file before and after I insert the stuff from the enviroment there:

\documentclass{beamer}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\usepackage{fancyvrb}
\makeatletter

\newenvironment{Rtest}[1]%
  {\xdef\d@tn@me{#1}%
  % \xdef\r@ncmd{Rscript #1.R > #1.Rlog}% uncomment to run command on file
  \typeout{Writing file #1}\VerbatimOut{#1.R}% 
  }
  {\endVerbatimOut %
 \toks0{\immediate\write18}%
 %\expandafter\toks\expandafter1\expandafter{\r@ncmd}% uncomment to run command on file
 %\edef\d@r@ncmd{\the\toks0{\the\toks1}}\d@r@ncmd % uncomment to run command on file
 \input{\d@[email protected]}%
}

\makeatother

\begin{document}

\frame[containsverbatim]{

\begin{Rtest}{hello}
Hallo Welt 
\end{Rtest}

}

\end{document}

What I would like to achieve is to have an environment like the following:

\begin{Rtest}{hello}{beforecode}{aftercode}
Hallo Welt 
\end{Rtest}

that results in hello.R looking like this:

beforecode
Hallo Welt
aftercode

How can I modify the code above to accomplish this?

2
  • Not an answer to the question; but \immediate\write18{\r@ncmd} is much easier than that long series of commands: \r@ncmd has been defined by \xdef, so it has survived full expansion so it can go as argument to \write.
    – egreg
    Dec 30, 2014 at 11:01
  • Use \begin{frame}[fragile]...\end{frame} and not \frame{...}.
    – egreg
    Dec 30, 2014 at 11:38

2 Answers 2

4

This solution is based on this answer of Ulrike Fischer.

\documentclass{beamer}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\usepackage{environ}

\newwrite\myexport

\makeatletter
\NewEnviron{Rtest}[3]{%
\immediate\openout\myexport=#1.R%
\toks@={#2}%
\immediate\write\myexport{\the\toks@}%
\toks@=\expandafter{\BODY}%
\immediate\write\myexport{\the\toks@}%
\toks@={#3}%
\immediate\write\myexport{\the\toks@}%
\immediate\closeout\myexport%
\input{#1.R}
}
\makeatother


\begin{document}

\frame[containsverbatim]{

\begin{Rtest}{hello}{beforecode}{aftercode}
Hallo Welt
\end{Rtest}

}

\end{document} 

Contents of hello.R

beforecode
Hallo Welt
aftercode

Output

enter image description here

4
  • 1
    This will tokenize the contents of Rtest, losing the possibility of doing verbatim; for instance, line breaks will be lost.
    – egreg
    Dec 30, 2014 at 11:36
  • 1
    @egreg I know, but I'm not sure about what has to be the contents of the .R file and anyway, I can't do any better... Dec 30, 2014 at 11:37
  • Rtest will contain arbitrary R or Python code, line breaks must remain as they are as they may have a special meaning. Dec 30, 2014 at 12:20
  • Unfortunately this solution will not read the input (content environment) verbatim.
    – user202729
    Dec 28, 2021 at 10:20
1

Customizing fancyvrb's VerbatimOut might be the simplest approach. This should give you a good starting point for additional customization.

I wrote this for Python since I don't have an R installation handy. The test environment takes the base name of the script, the before code, and the after code, in addition to an optional argument that specifies whether the code is executed. If code is executed, the output is brought in verbatim. You should be able to customize this easily to get whatever you need.

This assumes that the before code and after code are single lines.

\documentclass{beamer}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\usepackage{fancyvrb}
\usepackage{upquote}
\usepackage{etoolbox}
\makeatletter
\def\VerbatimOutPlus{\FV@Environment{}{VerbatimOutPlus}}

% Write #2 before and #3 after environment contents
\def\FVB@VerbatimOutPlus#1#2#3{%
  \@bsphack
  \begingroup
    \FV@UseKeyValues
    \FV@DefineWhiteSpace
    \def\FV@Space{\space}%
    \FV@DefineTabOut
    \def\FV@ProcessLine{\immediate\write\FV@OutFile}%
    \immediate\openout\FV@OutFile #1\relax
    % Added next 2 lines
    \immediate\write\FV@OutFile{#2}%
    \def\FV@appendline{#3}%
    \let\FV@FontScanPrep\relax
    \let\@noligs\relax
    \FV@Scan}

\def\FVE@VerbatimOutPlus{%
  % Added next line
  \immediate\write\FV@OutFile{\FV@appendline}%
  \immediate\closeout\FV@OutFile\endgroup\@esphack}

\DefineVerbatimEnvironment{VerbatimOutPlus}{VerbatimOutPlus}{}

\newenvironment{PYtest}[4][]%
  {\VerbatimEnvironment
    \def\FV@run@opts{#1}%
    \def\FV@Plus@outfilename{#2.py}%
    \begin{VerbatimOutPlus}{#2.py}{#3}{#4}}%
  {\end{VerbatimOutPlus}%
    \VerbatimInput{\FV@Plus@outfilename}%
    \ifdefstring{\FV@run@opts}{run}{%
      \hrule
      \immediate\write18{python \FV@Plus@outfilename\space> \FV@Plus@outfilename log}%
      \VerbatimInput{\FV@Plus@outfilename log}}{}}
\makeatother

\begin{document}

\begin{frame}[fragile=singleslide]
\begin{PYtest}[run]{hello}{'''beforecode'''}{'''aftercode'''}
print('Text')
\end{PYtest}
\end{frame}

\end{document}

enter image description here

2
  • I am receiving an error message with your code: ! I can't write on file hello.py'.` Jan 1, 2015 at 5:26
  • @UweZiegenhagen That looks like a permissions issue. Probably the same as this question if you are on Windows.
    – G. Poore
    Jan 1, 2015 at 16:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .