Search code examples
rsweaver-exams

Creation of especialized \Sexpr function version


I'm using the exams package to generate some exams (engineering). My source files are in Rnw format so the underlying engine is Sweave.

In R side, I'm using units package (to check dimensionality correctness) and I've created a function (called units2tex) to convert a magnitude from units to LaTeX equivalent. So, when I calculate a variable, I have to create a copy for LaTeX:

<<>>=
R = set_units(1,ohm)
I = set_units(1,A)
V = R*I

R_tex = units2tex(R)
I_tex = units2tex(I)
#V_tex = units2tex(V)

@

For $R = \Sexpr{R_tex}$, the answer is \Sexpr{units2tex(V)}.

In both cases (to print R and V) I have to explicitly call units2tex function somewhere. It's is a lot of typing (more to type, more places to be wrong) because there are a lot of steps and intermediate temporal values.

Is it possible to easily create versions of \Sexpr with automatic function calls?

More concretely:

  • Is is possible to create \SexprT{V} to function like \Sexpr{units2tex(V)}?
  • Is is possible to create \SexprT{V,digits=2} (or similar) to function like \Sexpr{units2tex(V,digits=2)}?

In both cases without losing the use of original \Sexpr.

My current options and its cons:

  • Explicitly call to units2tex(...) and duplicate variables (units version and LaTeX version). It is my current approach. A lot to typing, prone to forget conversions or generate conversions that they are not used latter.
  • use very short function names: \Sexpr{t(V)}. Difficult to remember the meaning of each translation function. Pollution of the namespace. I still remember last time I use a c function (after a and b ones) and break original c function.
  • Use some kind of preprocessor and made the changes. As I said before, all ecosystem is to work with exams package. This package executes Sweave in the background, I do not want to alter the pipeline of the files to generate the tests. I would write a *.Rnw2 file and have to create a script in ¿sed? ¿R?, read files, modify values and generate the *.Rnw file and then call exams2pdf functions... There is problems if I forgot to update Rnw exams files. I'd use a Makefile to coordinate, but I have to switch between a terminal and Rstudio... This option is, maybe the best (after the creation of \Sexpr versions) but the solution obscures the pipeline and difficult quick questions generation to check them.

So, the best approach is: Is it possible to create variations of \Sexpr?

Full example: file: "question.Rnw"

\usepackage[utf8]{inputenc}
\usepackage[OT1]{fontenc}

<<echo=FALSE, results=hide>>=
library(units)

units2tex <- function(x) {
# this function is not important here. Simplified version the original version much complex
paste0(x,deparse_unit(x))
}

@


\begin{question}

<<echo=FALSE, results=hide>>=

In <- set_units(1e-3,A)
Pn <- set_units(sample(c(2,1,0.5,0.25,0.125),1),W)

In_tex <- units2tex(In)
Pn_tex <- units2tex(Pn)

@

A resistor nah nah nah current $I_n=\Sexpr{In_tex}$ nah, nah, nah $P_n=\Sexpr{Pn_tex}$

What is V?

<<echo=FALSE, results=hide>>=
Vn <- set_units(Pn/In,V)
Vn_tex <- units2tex(Vn) 
@

\begin{answerlist}
  \item $V = \Sexpr{Vn_tex}$
  \item $V = \Sexpr{Pn_tex}$
  \item $V = \Sexpr{In_tex}$
\end{answerlist}    
\end{question}

\begin{solution}

To calculate $V$, we do $V= P_n/I_n = \frac{\Sexpr{Pn_tex}}{\Sexpr{In_tex}} = \Sexpr{Vn_tex}$
\begin{answerlist}
  \item Ok
  \item Bad
  \item Wrong
\end{answerlist}    
\end{solution}

\exname{question1}
\extype{schoice}
\exsolution{100}
\exshuffle{TRUE}

And to compile:

library(exams)
exams2html(c("question1.Rnw"), encoding="utf-8",template='plain8.html',mathjax = TRUE)

Solution

  • In Rnw exercises the content of \Sexpr{} is turned into character by explicitly calling as.character() on it. As this is a generic function you could easily define your own method, say,

    as.character.units <- function(x, ...) units2tex(x, ...)
    

    and then simply using \Sexpr{V} will automatically call your units2tex() function behind the scenes.

    Note that the same does not work for Rmd exercises. So i you want to mix Rnw and Rmd exercises, then using a shortcut function name such as the following might be better:

    u2t <- function(x, ...) units2tex(x, ...)
    

    This would then need to be called as \Sexpr{u2t(V)} and `r u2t(V)`, respectively.