Knitr – function that works both in \Sexpr and in code-chunks

knitr

I try to learn knitr.

knitr lets you nest snippets of "inline-code" written in the language R between \Sexpr{...}.

knitr lets you nest "code-chunks" written in the language R between

<< >>=
[chunk of R-code goes here]
@

. knitr does pre-process the input-file. Hereby all snippets of inline-code and all code-chunks are processed by the language R.
In what is fed to (La)TeX the snippets of inline-code and the code-chunks are replaced by the result of this processing.

I try to write an R-function which does a system-call, e.g., echo some phrase and captures the standard-output and delivers into the .tex-file created by knitr.

By now I have an R-function for doing this within R-code-chunks and another function for doing this within R\Sexpr-inline-code-snippets.

The function to be used within R-code-chunks does not work out within R\Sexpr-inline-code-snippets.

The function to be used within R\Sexpr-inline-code-snippets does not work out within R-code-chunks.

The question is:

What should an R-function for knitr look like which works out both within R\Sexpr-inline-code-snippets and within R-code-chunks?

Here is the file test.Rtex I have so far:

<<CallExternalFunctionsStuff, include=FALSE, cache=FALSE, echo=FALSE, results='asis'>>=
knitr::opts_template$set(
  CallExternalApp = list(include=TRUE, cache=FALSE, echo=FALSE, results='asis')
)
CallExternalAppInChunk <- function(A) {
  return(cat(paste(system(A, intern = TRUE),collapse="\n")))
}
CallExternalAppInSexpr <- function(A) {
  return(paste(capture.output(cat(system(A, intern = TRUE), sep="\n", fill=FALSE)), collapse="\n"))
}
@
\documentclass{article}

\begin{document}

\noindent Between ZZZ is what \verb|verbatim| does usually:\bigskip

ZZZZ
\begin{verbatim}
hello1
hello2
\end{verbatim}ZZZZ

\bigskip

\noindent \verb|CallExternalAppInChunk| works inside an R-code-chunk:\bigskip

ZZZZ
\begin{verbatim}
<<opts.label='CallExternalApp'>>= 
CallExternalAppInChunk("echo hello1&&echo hello2")
@
\end{verbatim}ZZZZ

\bigskip

\noindent \verb|CallExternalAppInSexpr| works inside knitR's \verb|\Sexpr|:\bigskip

ZZZZ
\begin{verbatim}
\Sexpr{CallExternalAppInSexpr("echo hello1&&echo hello2")}
\end{verbatim}ZZZZ

\bigskip

\noindent \verb|CallExternalAppInSexpr| does not work inside an R-code-chunk:\bigskip

ZZZZ
\begin{verbatim}
<<opts.label='CallExternalApp'>>= 
CallExternalAppInSexpr("echo hello1&&echo hello2")
@
\end{verbatim}ZZZZ

\bigskip

\noindent \verb|CallExternalAppInChunk| does not work inside knitR's \verb|\Sexpr|:\bigskip

ZZZZ
\begin{verbatim}
\Sexpr{CallExternalAppInChunk("echo hello1&&echo hello2")}
\end{verbatim}ZZZZ

\end{document}

Here is the output this produces

enter image description here

Best Answer

A short answer is that you return the character string but mark it with xfun::raw_string(), e.g.,

CallExternalApp <- function(A) {
  xfun::raw_string(paste(system(A, intern = TRUE), collapse = "\n"))
}

Under the hood, xfun::raw_string() will let R's print() function print a string with cat(), which makes it work in a code chunk, and also return the string itself (with a new class), which makes it work in an inline expression in \Sexpr{}.

In a code chunk, R objects are automatically printed (this is a subtle feature of R). In an inline R expression, knitr obtains its returned value and writes it out unless the value is marked as invisible().

Why doesn't CallExternalAppInChunk() work in \Sexpr{}? Because it doesn't return the character value, but returns what cat() returns (i.e., an invisible NULL).

Why doesn't CallExternalAppInSexpr() work in a code chunk? Because it returns a normal character string, and knitr will print it in the way that a character string is printed in a normal R console (i.e., with indices like [1] and double quotes).