Multiple Documents From One Source: LaTEX For Lecturers and Teachers
Multiple Documents From One Source: LaTEX For Lecturers and Teachers
Multiple Documents From One Source: LaTEX For Lecturers and Teachers
Designing a unified workflow a macro \condition that expands to the number and
use \ifcase to make the adjustments for corresponding
Our goal is to produce multiple output documents with
case.
differing content in a single run. Though this might
seem impossible at first glance, Ulrike Fischer found
a way [2] to do this using only pdflatex. We will Listing 1. Use case implementation
introduce her approach step by step, keeping an eye on
1 \ R e q u i r e P a c k a g e { comment }
platform independence.
2
Since pdflatex Sheet.tex will only produce
3 \ includecomment { problem }
Sheet.pdf our task splits into three parts:
4 \ ifcase \ condition
5 % \ condition = 0 , student
1. Find a way to tell LaTEX which parts of the source
6 \ excludecomment { s o l u t i o n }
file to use and which to ignore
7 \ excludecomment { h o w t o g r a d e }
2. Change the file name of the output document in
8 \ or % \ c o n d i t i o n = 1 , t u t o r
order to be able to produce multiple outputs
9 \ includecomment { s o l u t i o n }
3. Produce all versions in just one run of pdflatex
10 \ excludecomment { h o w t o g r a d e }
11 \ or % \ c o n d i t i o n = 2 , c o r r e c t o r
Selectively in- & excluding code
12 \ includecomment { s o l u t i o n }
We would like to wrap code into a LaTEX environment
13 \ includecomment { howtograde }
and have some kind of “switch” in the document pream-
14 \ fi
ble to control whether to have LaTEX process it or not.
This is exactly what comment.sty by Victor Eijkhout
[1] does. Now all it takes is defining the value of \condition
to control the content of the output.
Usage. The comment package provides us with two sim-
ple commands Coding discipline. One could of course implement the
above using \ifnum instead. I prefer to use \ifcase
@ \includecomment{foobar} defines the envi- here because the cases are “automatically numbered”
ronment foobar whose content will be included in order of appearance. That way I got less confused
@ \excludecomment{foobar} defines the envi- about which number represents which use case, saving
ronment foobar whose content will be ignored me time on debugging.
Example. A nice feature of environments defined using Rethinking command line calls
comment.sty will not break the line, so we can use We want to control the version of the output without
them in midsentence. The minimal example editing the source document. We could write a wrapper
1 \ includecomment { t r u t h } document that defines our \condition macro followed
2 \ excludecomment { n o n s e n s e } by the actual document code:
3
4 Knuth s t a r t e d 1 \ gdef \ c o n d i t i o n { 0 }
5 \ begin { t r u t h } 2 \ input S h e e t . t e x
6 d e v e l o p i n g \ TeX { }
7 \ end { t r u t h } On second thought we can also pass this code on to
8 \ begin { n o n s e n s e } LaTEX directly on the command line
9 u s i n g WinWord
10 \ end { n o n s e n s e } pdflatex "\gdef\condition{0} \input Sheet.tex"
11 in 1977. avoiding the additional file.
will just output Changing the output file name
Knuth started developing TEX in 1977. By now we can produce any version of the document
by altering a single value but they will still be written to
Implementing our use cases. Knowing the above, we
the same output file, thereby overwriting the previous
can easily write a document that matches our use cases, output.
but we would still have to adjust the in- and exclusions A quick look at pdflatex’s manpage1 provides
before compiling.
To reduce such modifications to a bare minimum we pdflatex --jobname="student" Sheet.tex
will assign a number to each use case. We can then define which will create student.pdf from Sheet.tex.
Multiple documents from one source EUROTEX 2012 & 6CM PROCEEDINGS 103
The UniFlow principle Combining the UniFlow template (listing 2) with the
After introducing all the building blocks we are now able implementation of the use cases and the corresponding
to understand Ulrike Fischer’s ingenious construction pseudo shell script (listings 1 and 3) we have constructed
[2] to produce multiple output documents in one single the single source document Sheet.tex. Enabling shell
run. escape and processing it with pdflatex will result
We start off with a document skeleton to demonstrate in the three output documents Sheet-student.pdf,
the recursive nature of the approach. Sheet-tutor.pdf and Sheet-corrector.pdf, each
of them with the desired specific content. Therefore all
of our initial requirements are met and we have devel-
Listing 2. General UniFlow template
oped a unified workflow.
1 % Beginning of Sheet.tex Pitfall. Neither the wrapping pdflatex run nor script
2 \ ifx \ condition \ undefined 3 will produce an output file named Sheet.pdf. This
3 % Pseudo shell script (listing 3) can cause error messages when using text editors with
4 \ expandafter \ stop built-in PDF viewers like TEXmaker and its standard
5 \ fi “quick build” feature.
6
7 % Use case implementation (listing 1) Exercise. If you would like to check your understanding
8 of the UniFlow principle, try to write a template for this
9 % Actual document code begins here scenario:
A school teacher always designs two slightly different
versions A and B of an exam. She would like to produce
Processing this code will have pdflatex enter the \ifx the four versions A, B, A with solutions and B with
block as the macro \condition has not been defined solutions from a single source document.
yet. After executing a “pseudo shell script” LaTEX will
first expand the token \fi and then \stop reading. Note
that this run will not produce any output.
In the pseudo shell script, we will invoke pdflatex
again on this very same document. The file’s base name
is obtained from \jobname
pdflatex "\string\input\space\jobname"
and we told the parser to interpret \input as a \string,
preventing it from expansion ([4], p. 40).
104 EUROTEX 2012 & 6CM PROCEEDINGS Leo Arnold
UniFlow in action
19 30 −20
!
The UniFlow principle can also serve to integrate exter-
nal programs into the LaTEX run. Due to the author’s A= 26 39 −26
background the examples are taken from mathematics. 61 93 −62
For applications in other subjects see the PythonTEX Solution. The characteristic polynomial of A is
gallery [5] or Herbert Voß’s article on general source
code [7]. χ_A(x) = x3 + 4x2 + 3x = x · (x + 1) · (x + 3)
For the sake of simplicity we now focus on having hence its eigenvalues are
only one output document. Nevertheless we will still
have to define the \condition macro (setting it to an [0, −1, −3]
arbitrary string value) whenever we want pdflatex to Using sagetex.sty we just needed to type
ignore the \ifx block. The generalization to multiple
output versions is left to the reader as an exercise. 1 % ’ sagesilent ’ r e t u r n s no o u t p u t
2 \ begin { s a g e s i l e n t }
Implementing UniFlow. Here, due to the use of sample(), the output will be
different after every compile run.
1 % B e g i n n i n g o f Example . Rnw
2 \ ifx \ condition \ undefined
3 \ immediate \ w r i t e 1 8 { Aftermath
4 R CMD Sweave \ jobname . Rnw } Of course we could have achieved all of this in a one-
5 \ immediate \ w r i t e 1 8 { call fashion using some kind of shell script, make6 or its
6 pdflatex LaTEX analogs latexmk7 or rubber8 . On the other hand
7 " \ gdef \ s t r i n g \ c o n d i t i o n { 0 } the UniFlow principle provides a platform independent,
8 \ s t r i n g \ input \ space \ jobname " } script-like alternative without additional (Make)files or
9 \ expandafter \ stop non-TEX executables.
10 \ fi
The future of UniFlow
Editing the Example.Rnw as source file and using the
To enable anyone to implement the UniFlow principle
above code, the correct command line call is
with ease I will work on developing it into a LaTEX
pdflatex --shell-escape Example.Rnw package.
If you like to use the tab completion feature of your Versatility is UniFlow’s biggest asset and every reader
system shell, it will probably only offer you the .tex will by now have his or her special use case in mind – and
file. Observe that this will generate the same output most certainly be struggling with the inconvenient syn-
because both execute the same pseudo shell script. tax of the corresponding \write18 statement. Hence
designing an intuitive command structure will be key
Exercise. Roll a dice 100 times in a row recording the
and your TEXnical comments and pieces of advice are
number of pips each time. Visualize their relative fre-
always welcome.
quency as a histogram and a pie chart.
One step further we could think about a unified inter-
Solution. Since this exercise depends on probability, face to integrate virtually any program into the LaTEX
everyone will have a different result. Mine looks like run. Herbert Voß [7] already showed how general source
this: code can be extracted from a document and reincluding
2 the output after processing. His approach works with
0.20
Acknowledgments
4
6 Many people have directly or indirectly contributed in
0.00
1 2 3 4 5 6
the development of the UniFlow principle.
number of pips
5 First and foremost I want to thank Ulrike Fischer who
These diagrams where of course generated at compile provided the core concepts in her short and effective
time from the following code snippet. post on StackExchange.
When I was struggling with selectively showing or
1 # R e l e v a n t p a r t o f Example . Rnw hiding content, Rolf Niepraschk pointed out the fasci-
2 << echo =FALSE , f i g =TRUE >>= nating simplicity of comment.sty to me.
3 par ( ps = 2 0 ) Marcus Bitzl is an avid reader of “Die TEXnische
4 p i p s <− sample ( 1 : 6 , 1 0 0 , r e p l a c e = Komödie” and drew my attention to the articles on the
TRUE ) integration of free math software. He was also the first
5 hist ( pips , b r e a k s =c ( 0 . 5 , 1 . 5 , to encourage the development of a UniFlow package.
2 . 5 , 3 . 5 , 4 . 5 , 5 . 5 , 6 . 5 ) , col= The articles by Günter Rau (SageTEX) and Uwe
" g r a y " , f r e q =FALSE , main= " " , Ziegenhagen (Sweave) were invaluable primers to me
x l a b = " number ␣ o f ␣ p i p s " , y l a b = " and made the vivid demonstrations of UniFlow in action
r e l a t i v e ␣ frequency " ) possible.
6 @ Finally I would like to express my gratitude to the
7 EuroTEX 2012 organizers for arranging a wonderful and
8 << echo =FALSE , f i g =TRUE >>= inspiring conference and giving me the opportunity to
9 p i e ( t a b l e ( p i p s ) , c o l =c ( " w h i t e " , " present the UniFlow principle.
b l a c k " ) , cex =2)
10 @
106 EUROTEX 2012 & 6CM PROCEEDINGS Leo Arnold
References
[1] V. Eijkhout. comment.sty: Selec-
tively include / excludes portions of text.
CTAN:macros/latex/contrib/comment:
http://www.ctan.org/tex-archive/
macros/latex/contrib/comment.
[2] U. Fischer. Answer to “Can one
TeX file output to multiple PDF files?”
http://tex.stackexchange.com/a/5265.
[3] P. Hirschhorn. exam.cls: Pack-
age for typesetting exam scripts.
CTAN:macros/latex/contrib/exam: http:
//www.ctan.org/tex-archive/macros/
latex/contrib/exam.
[4] D. E. Knuth. The TEXbook. Addison-Wesley,
Eighth printing, August 1986.
[5] G. Poore. PythonTEX: Fast Access to Python from
within LaTEX. github:gpoore/pythontex:
https://github.com/gpoore/pythontex.
[6] G. Rau. SageTEX. Die TEXnische Komödie,
1/2011: http://archiv.dante.de/DTK/PDF/
komoedie_2011_1.pdf:17–21.
[7] H. Voß. Einlesen und Ausführen von Quell-
code. Die TEXnische Komödie, 1/2011: http:
//archiv.dante.de/DTK/PDF/komoedie_
2011_1.pdf:40–54.
[8] U. Ziegenhagen. Datenanalyse mit Sweave, LaTEX
und R. Die TEXnische Komödie, 4/2010: http:
//www.dante.de/DTK/Ausgaben/dtk104.
pdf:35–45.
Weblinks
1. http://linux.die.net/man/1/pdflatex
2. http://wiki.contextgarden.net/Write18
3. http://www.sagemath.org
4. http://www.r-project.org
5. http://www.statistik.lmu.de/~leisch/Sweave
6. http://www.gnu.org/software/make
7. CTAN:support/latexmk: http://ctan.org/
tex-archive/support/latexmk/
8. https://launchpad.net/rubber
Leo Arnold
tex@arney.de