3

I write a lot of exams, quizzes, and homework problems for the course I teach. Whenever I write an evaluation foo.tex, I always want a separate solutions file foo-solutions.tex to be written. Here's an example of my workflow.

I start by writing the evaluation along with the solutions in a file foo-solutions.tex:

\documentclass{exam}
\printanswers

\newcommand{\checkforstudent}[1]{%
  \ifcsname#1\endcsname%
  \noprintanswers%
  \else%  ... command '#1' does not exist ...%
  \fi%
}


\begin{document}

\checkforstudent{studentmode}

\begin{questions}
  \question What is the first sentence of \emph{Moby Dick}?
  \begin{solution}
    \emph{Call me Ishmael.}
  \end{solution}
\end{questions}

\end{document}

The command \checkforstudent tests whether or not the input exists a a command. If so, then the answers are switched off. The first line after \begin{document} uses \checkforstudent to check for a command

Compiling this file generates foo-solutions.pdf:

screen-shot of foo-solutions.pdf

I also have a file foo.tex:

\newcommand{\studentmode}{}\input foo-solutions

This file defines the command \studentmode and then inputs the entirety of foo-solutions.tex. Compiling foo.tex generates foo.pdf:

screen-shot of foo.pdf

Finally, I have these two pdfs generated at once with a bash script write-files.sh

#!/bin/bash

pdflatex foo-solutions.tex
pdflatex foo-solutions.tex

pdflatex foo
pdflatex foo

The script compiles both files twice to make sure all references are properly dealt with.

This workflow works reasonably well. However, there are some annoyances:

  1. I have to keep track of three files instead of one (foo-solutions.tex, foo.tex, and write-files.sh).
  2. When I write a new evaluation bar.tex, I copy foo-solutions.tex, foo.tex, and write-files.sh to a new directory and replace the instances of foo with bar. This really annoys me.
  3. Many of my colleagues are not comfortable with running bash scripts. So, when I share my documents with them, they have trouble generating both the evaluation and the solutions.

It would be nice if there were a solution to my problem that allowed me to generate foo-solutions.pdf and foo.pdf with just one latex file.

Is this possible?

Note. My current workflow was inspired by this answer to a similar question of mine.

arauzo
  • 208

4 Answers4

3

Along with your first file (you called it foo-solutions.tex, but for this Makefile you should call it foo.tex) you can use the following Makefile:

TEX   = pdflatex
# if you want to use specific FLAGS for compilation
FLAGS =

FILE = $(wildcard *.tex)

STDVER = $(FILE:%.tex=%-students)
SOLVER = $(FILE:%.tex=%-solutions)
STDOPT = studentmode

STDPDF = $(STDVER).pdf
SOLPDF = $(SOLVER).pdf

all: $(STDPDF) $(SOLPDF)

$(STDPDF): $(FILE)
    $(TEX) $(FLAGS) -jobname $(STDVER) "\def\$(STDOPT){}\input{$(FILE)}"
    $(TEX) $(FLAGS) -jobname $(STDVER) "\def\$(STDOPT){}\input{$(FILE)}"
    $(TEX) $(FLAGS) -jobname $(STDVER) "\def\$(STDOPT){}\input{$(FILE)}"
$(SOLPDF): $(FILE)
    $(TEX) $(FLAGS) -jobname $(SOLVER) $(FILE)
    $(TEX) $(FLAGS) -jobname $(SOLVER) $(FILE)
    $(TEX) $(FLAGS) -jobname $(SOLVER) $(FILE)

.PHONY: clean clean_sol clean_std
clean: clean_sol clean_std
clean_sol:
    -rm -f $(SOLVER).*
clean_std:
    -rm -f $(STDVER).*

Put it in the same directory as your .tex-file called Makefile. In this directory should only be one .tex-file. If there are more change the line FILE = $(wildcard *.tex) to FILE = <your-tex-files-name>.tex. It produces two separate pdfs one called <your-tex-files-name>-students.pdf and one called <your-tex-files-name>-solutions.pdf. Call it from the shell with make.

This is a rather basic Makefile. It could use some enhancements, but should do the trick.

If you want to remove the created pdfs and auxiliary files, call make clean from the shell.

Skillmon
  • 60,462
3

1) Using the bash script you can easily avoid having two .tex files and simplify your code.

This can be your foo.tex:

\begin{document}

\begin{questions}
  \question What is the first sentence of \emph{Moby Dick}?
  \begin{solution}
    \emph{Call me Ishmael.}
  \end{solution}
\end{questions}

\end{document}

and the script to generate foo-exam.pdf and foo-solutions.pdf:

#!/bin/bash

pdflatex -jobname foo-exam "\documentclass{exam}\input foo"
pdflatex -jobname foo-exam "\documentclass{exam}\input foo"

pdflatex -jobname foo-solutions "\documentclass{exam}\printanswers\input foo"
pdflatex -jobname foo-solutions "\documentclass{exam}\printanswers\input foo"

2) You can also use just one script for all evaluations, by calling the script with a parameter, like create-exam.sh foo.

#!/bin/bash

if [ "$1" != "" ] && [ -f "${1}".tex ]; then

  pdflatex -jobname ${1}-exam "\documentclass{exam}\input ${1}"
  pdflatex -jobname ${1}-exam "\documentclass{exam}\input ${1}"

  pdflatex -jobname ${1}-solutions "\documentclass{exam}\printanswers\input ${1}"
  pdflatex -jobname ${1}-solutions "\documentclass{exam}\printanswers\input ${1}"

else
  echo "Syntax is:"
  echo "  create-exam name (where name.tex is the file to compile)"
fi

3) With the parameter, if you install the script to your colleagues in their PATH once, it will work for all evaluations.

There may be a solution without scripts by using \immediate\write18{shell command} but it would require activating this unsafe option in Latex and escaping characters in that command, which is very difficult. If avoiding scripts is an absolute requirement, I would go for the Makefile solution.

arauzo
  • 208
1

Another option could be to ask on each TeX run whether to include the answers or not. This way you only need the TeX file and nothing else. It might get annoying to have to answer the question though.

\documentclass{exam}
\def\TestIncludeAnswersTrue{true}
\def\TestIncludeAnswersFalse{false}
\def\askanswers{
  \typein[\IncludeAnswers]{Include answers?
  (\TestIncludeAnswersTrue/\TestIncludeAnswersFalse)}
  \ifx\TestIncludeAnswersTrue\IncludeAnswers
    \printanswers
  \else
    \ifx\TestIncludeAnswersFalse\IncludeAnswers
    \else
      \typeout{Please answer with '\TestIncludeAnswersTrue' or
      '\TestIncludeAnswersFalse'}
      \askanswers
    \fi
  \fi
}
\askanswers


\begin{document}

\begin{questions}
  \question What is the first sentence of \emph{Moby Dick}?
  \begin{solution}
    \emph{Call me Ishmael.}
  \end{solution}
\end{questions}

\end{document}
Skillmon
  • 60,462
0

The solutions posted here work well, but I think I've finally figured out an elegant solution using symlinks and latexmk.

The package currfile can detect the name of the file being compiled by latex. The package xstring has a function \IfSubStr that executes code conditioned on if a given string is a substring of another given string.

So, if we insert the line

\IfSubStr*{\currfilename}{solutions}{ \printanswers }{ \noprintanswers }

in our preamble, the exam class will print solutions if the file name contains the substring solutions.

Consider the solutions document ~/myexam/exam-solutions.tex

\documentclass{exam}

\usepackage{currfile}
\usepackage{xstring}

\IfSubStr*{\currfilename}{solutions}{ \printanswers }{ \noprintanswers }

\begin{document}

\begin{questions}

\question What is the first sentence of \emph{Moby Dick}?
  \begin{solution}
    \emph{Call me Ishmael.}
  \end{solution}

\end{questions}

\end{document}

Issuing ln -s ~/myexam/exam-solutions.tex ~/myexam/exam.tex creates the symlink exam.tex linked to exam-solutions.tex. Running latexmk from ~/myexam/, automatically generates both the bare exam and the solutions.