Production de fiches de solutions avec L^{A}TEX 2ε^{∗}

Copyright (C) 1994,1995 par Mike Piff 31 octobre 2001

Table des matières

1 Introduction 1 2 Le fichier du gestionnaire de documentation 2 3 Interface utilisateur 2 4 Un exemple simple 4 5 Un exemple complexe 4 6 Un exemple supplémentaire 6 7 Identification 7 8 Options 7 9 Manipulation de fichiers 7 10 L’interface fichier 9 11 L’interface solution 11

1 Introduction

Ce package est une modification de l’ancienne option de style answers de l’auteur, qui a été utilisée pendant quelques années, basée sur l’idée du TEXBook de lier solutions et exercices. J’ai saisi l’opportunité de cette révision pour modifier le format des solutions, afin qu’elles soient maintenant présentées comme un environnement L^{A}TEX plutôt que débutées par une commande et terminées par la fin de l’environnement environnant, une manière fort peu en accord avec L^{A}TEX !

∗Traduit en français par Jean-Pierre Drucbert et Mathieu Goutelle le 15 septembre 2000.

Titre original « Production of solution sheets in L^{A}TEX 2ε ».

L’autre changement important est que plusieurs descripteurs de fichiers peuvent être actifs en même temps. Cela permet de placer certaines solutions en annexe dans un livre (par exemple) et d’autres d’être placées dans un fichier séparé pour être imprimées et distribuées aux étudiants au fur et à mesure de la progression du cours.

De plus, les fichiers physiques actuels ouverts avec chaque descripteur peuvent maintenant être changés en cours de travail, permettant ainsi de créer plusieurs fichiers avec le même format. Ainsi, par exemple, chaque chapitre d’un livre peut créer son propre fichier de solutions, permettant à l’utilisateur d’utiliser \include pour les chapitres et les solutions.

Enfin, n’importe quel nombre de types de solutions peut être attaché à un fichier et non plus uniquement les deux anciens, solution et indication. Le format de chaque type de solution est sous le contrôle total de l’utilisateur.

2 Le fichier du gestionnaire de documentation

Voici le fichier du gestionnaire qui produit la documentation. On utilise la classe de document fournie par la distribution L^{A}TEX 2ε pour produire la documentation.

1 ⟨∗driver⟩

 2 \documentclass{ltxdoc}
 3 \usepackage[T1]{fontenc}       % ajouté par le traducteur
 4 \usepackage[latin1]{inputenc}  % ajouté par le traducteur
 5 \usepackage[frenchb]{babel}    % ajouté par le traducteur
 6 \RecordChanges
 7 \begin{document}
 8 \DocInput{f-answers.dtx}
 9 \PrintIndex
10 \PrintChanges
11 \end{document}

12 ⟨/driver⟩

3 Interface utilisateur

Le package doit être inclus avec la commande :

       \usepackage[nosolutionfiles]{answers}

Si l’argument optionnel est spécifié, les solutions apparaissent directement dans le texte au lieu d’être écrites dans un autre fichier. Cela permet de produire une version de démonstration.

\Newassociation Après cela, il doit y avoir plusieurs déclarations de la forme :

       \Newassociation{xxx}{yyy}{zzz}

où xxx est un environnement dans le document et yyy un environnement qui entourera le contenu de xxx lorsqu’il est écrit dans le descripteur de fichier symbolique zzz. Les noms xxx, yyy and zzz doivent contenir uniquement des lettres, pas de chiffre, de signe de ponctuation ou d’espaces.

\solutionextension Par défaut, la sortie se fait dans zzz.tex si zzz est ouvert. La commande \solutionextension peut être redéfini pour remplacer l’extension tex par une autre. Alternativement, le fichier de sortie peut être modifié en tant que paramètre

de \Opensolutionfile et chaque \Opensolutionfile sur le même descripteur

peut utiliser un fichier physique différent. Par défaut, \solutionpoint est ajouté avant \solutionextension. Pour le supprimer, il faut le redéfinir (la valeur par défaut est évidemment un point).

\Opensolutionfile À un certain point, l’utilisateur tape :

\Closesolutionfile
       \Opensolutionfile{zzz}
       ...
       \Closesolutionfile{zzz}

pour créer un fichier de solution écrit par les environnements xxx jusqu’aux environnements yyy. Si cette construction est utilisée plusieurs fois, plusieurs fichiers de solutions vont être créés. L’utilisateur peut souhaitér que ces fichiers aient des noms différents. S’il utilise \Opensolutionfile{zzz}[www], alors www.tex est utilisé comme nom de fichier de sortie actuel au lieu de zzz.tex. Cela permet au descripteur de fichier zzz de créer plusieurs fichiers www.tex, par exemple un pour chaque chapitre d’un livre ou pour chaque feuille de problème. Ensuite, on peut les utiliser grâce à la commande \include. La même valeur de \solutionextension est utilisé pour les arguments principal et optionnel. Le nom www doit respecter les conventions habituelles sur les noms de fichier.

\Writetofile De plus, des données peuvent être écrites directement dans un fichier au moyen de \Writetofile. Son premier argument est le descripteur de fichier et le second la ligne de texte à écrire. Il est très important de se souvenir que chaque mot de contrôle dans la ligne doit être précédé par \protect, autrement la primitive TEX \write va les développer. Aussi, comme l’argument est lu à la manière habituelle de TEX, tout espace suivant un mot de contrôle disparaîtra à moins que des précautions soient prises. Donc, pour écrire \xx yyy dans le fichier, l’utilisateur doit

taper \protect\xx\space yyy.

Filesave Un bloc de texte peut être sauvé dans un descripteur de fichier grâce à :

       \begin{Filesave}{zzz}
         ....
       \end{Filesave}

autour de celui-là, dès que zzz a été ouvert. Les restrictions précédentes s’appliquant à \Writetofile n’existent pas pour cet environnement.

\Readsolutionfile L’un des fichiers générés peut être lu grâce à :

       \Readsolutionfile{zzz}

à condition que le fichier n’ait pas été fermé sans être rouvert. On peut aussi utiliser simplement \input ou \include au choix.

Aucune de ces opérations E/S n’ont d’effet si le descripteur de fichier n’a pas été ouvert ou si le paramètre nosolutionsfiles est spécifié.

4 Un exemple simple

Voici un exemple direct pour illustrer comment on peut utiliser ces macros.

13 ⟨∗ex1⟩

14 \documentclass[12pt,a4paper]{article}
15 \usepackage{answers}
16 \Newassociation{sol}{Solution}{ans}
17 \newtheorem{ex}{Exercice}
18 \begin{document}
19 \Opensolutionfile{ans}[ans1]
20 \section{Problèmes}
21 \begin{ex}
22 Premier exercice
23 \begin{sol}
24 Première solution.
25 \end{sol}
26 \end{ex}
27 \begin{ex}
28 Deuxième exercice
29 \begin{sol}
30 Deuxième solution.
31 \end{sol}
32 \end{ex}
33 \Closesolutionfile{ans}
34 \section{Solutions}
35 \input{ans1}
36 \end{document}

37 ⟨/ex1⟩

5 Un exemple complexe

Ce qui suit est un exemple (très complexe) de l’usage du package answers. Il utilise certains des raffinements décrits plus haut.

38 ⟨∗ex2⟩

39 \documentclass[12pt,a4paper]{article}
40 \usepackage{answers}%\usepackage[nosolutionfiles]{answers}

D’abord, un environnement qui contient des problèmes et qui les numérote. Il est basé sur un theorem de L^{A}TEX mais avec un corps en roman plutôt qu’en italique.

41 \newtheorem{Exc}{Exercice}
42 \newenvironment{Ex}{\begin{Exc}\normalfont}{\end{Exc}}

Trois types de solutions sont écrites dans deux fichiers différents. Le descripteur de fichier test contiendra les solutions et indications que l’étudiant verra ; testtwo contient les solutions aux problèmes qu’ils remettront vraisemblablement et qui doivent donc être préparées séparément.

43 \Newassociation{solution}{Soln}{test}
44 \Newassociation{hint}{Hint}{test}
45 \Newassociation{Solution}{sSol}{testtwo}

Parce que nous voulons repérer deux types distincts de problèmes dans le fichier principal, nous définissons ceci :

46 \newcommand{\prehint}{~[Indication]}
47 \newcommand{\presolution}{~[Solution]}
48 \newcommand{\preSolution}{~[Devoir à la maison]}

Nous fournissons un paramètre supplémentaire quand nous ouvrons un descripteur de fichier test car nous voulons écrire la commande \section dans le fichier solution. Il s’agit seulement ici d’une illustration ; cela serait plus pertinent si le fichier solution était inclus par \include

49 \newcommand{\Opentesthook}[2]%
50 {\Writetofile{#1}{\protect\section{#1: #2}}}

Le texte par défaut, que L^{A}TEX écrit lorsqu’il rencontre un environnement solution est modifié ici.

51 \renewcommand{\Solnlabel}[1]{\emph{Solution #1}}
52 \renewcommand{\Hintlabel}[1]{\emph{Indication #1}}
53 \renewcommand{\sSollabel}[1]{\emph{Solution à #1}}

54

55 \begin{document}

Nous ouvrons le descripteur test en tant que fichier test1.tex.

56 \Opensolutionfile{test}[ans2]{Solutions}

et nous écrivons un peu de texte dedans.

57 \Writetofile{test}{\protect\subsection{Quelques solutions}}

Le descripteur testtwo est ouvert en tant que testtwo.tex.

58 \Opensolutionfile{testtwo}[ans2x]
59 \Writetofile{testtwo}{%
60 \protect\subsection{Solutions supplémentaires}}

Maintenant les problèmes.

61 \section{Exercises}
62 \begin{Ex}
63 Un exercice avec une solution.
64 \begin{solution}
65 Voilà une solution.
66 \relax{}
67 \end{solution}
68 \end{Ex}
69 \begin{Ex}
70 Un exercice avec une indication et une solution cachée.
71 \begin{hint}
72 Voilà une indication.

73 \end{hint}
74 \begin{Solution}
75 Voilà une solution cachée.
76 \end{Solution}
77 \end{Ex}
78 \begin{Ex}
79 Un exercice avec une indication.
80 \begin{hint}
81 Voilà une indication.
82 \end{hint}
83 \end{Ex}

Nous fermons les deux fichiers de solution et incluons immédiatement leur contenu. Nous aurions pu utiliser ici \include.

84 \Closesolutionfile{test}
85 \Readsolutionfile{test}
86 \clearpage
87 \Closesolutionfile{testtwo}
88 \Readsolutionfile{testtwo}
89 \end{document}

90 ⟨/ex2⟩

6 Un exemple supplémentaire

Voici une application à une situation non envisagée au départ, suggérée à l’auteur par Martin Osborne. Ici, les exercices et solutions ne sont pas numérotés ; ils sont décrits.

91 ⟨∗ex3⟩

92 \documentclass[12pt,a4paper]{article}
93 \usepackage{answers}
94 \newenvironment{Ex}[1]{\begin{trivlist}\item \emph{#1} %
95 \renewcommand{\Currentlabel}{#1}}{\end{trivlist}}
96 \Newassociation{solution}{Soln}{solutions}

97

98 \renewenvironment{Soln}[1]{\begin{trivlist}\item
99 Solution à \emph{#1} }{\end{trivlist}}

100

101 \begin{document}
102 \section*{Problèmes}
103 \Opensolutionfile{solutions}[ans3]
104 \begin{Ex}{Premier exercice}
105 Un exercice avec une solution.
106 \begin{solution}
107 Voici la solution.
108 \relax{}
109 \end{solution}
110 \end{Ex}
111 \begin{Ex}{Second exercice}
112 Un second exercice avec une solution.

113 \begin{solution}
114 Voici une autre solution.
115 \end{solution}
116 \end{Ex}
117 \Closesolutionfile{solutions}
118 \section*{Solutions}
119 \Readsolutionfile{solutions}
120 \end{document}

121 ⟨/ex3⟩

7 Identification

Ce package peut être utilisé uniquement avec L^{A}TEX 2ε, un message idoine est donc affiché quand un autre format est utilisé.

122 ⟨∗answers⟩

123 \NeedsTeXFormat{LaTeX2e}[1996/06/01]

On déclare le nom du package et sa version :

124 \ProvidesPackage{answers}[1996/07/10]

et on l’affiche sur le terminal (et le fichier log) :

125 \typeout{Package `answers' <\filedate>.}
126 \typeout{\Copyright}

8 Options

Il y a une seul option nosolutionfiles qui bascule dans le mode où les solutions ne sont pas écrites dans des fichiers mais produites immédiatement.

127 \newif\ifanswerfiles \answerfilestrue
128 \DeclareOption{nosolutionfiles}{\answerfilesfalse
129 \typeout{No answer files being produced}}%
130 \ProcessOptions

Comme ce package utilise fortement le package verbatim, on s’assure que celuici est chargé.

131 \RequirePackage{verbatim}

9 Manipulation de fichiers

\solutionextension L’extension par défaut des fichiers solution est définie ici.

132 \newcommand{\solutionpoint}{.}
133 \newcommand{\solutionextension}{tex}

Elle peut être changée par \renewcommand.

Filesave On définit un environnement Filesave avec un paramètre, le descripteur de fichier. Il est similaire à l’exemple de Schöpf dans la description de verbatim.

134 \newenvironment{Filesave}[1]{%
135 \@bsphack
136 \def\verbatim@processline{}%
137 \Iffileundefined{#1}{}{%
138 \Ifopen{#1}{%
139 \def\verbatim@processline{%
140 \Ifanswerfiles{%
141 \immediate\write\@nameuse{#1@file}%
142 {\the\verbatim@line}%
143 }{}%

144 }%

145 }{}%

146 }%

147 \let\do\@makeother\dospecials
148 \catcode`\^^M\active \catcode`\^^I=12\relax
149 \verbatim@start
150 }{\@esphack}

\Writetofile Il est aussi utile d’avoir une macro pour écrire dans un fichier. Dans celle-ci, on a besoin de placer \protect devant chaque mot de contrôle dans l’argument qui pourrait être développé prématurément et ainsi provoqué des problèmes.

151 \newcommand{\Writetofile}[2]{%
152 \@bsphack
153 \Iffileundefined{#1}{}{%
154 \Ifopen{#1}{%

155 {%

156 \let\protect\string
157 \Ifanswerfiles{%
158 \immediate\write\@nameuse{#1@file}{#2}%
159 }{}%

160 }%

161 }{}%

162 }%

163 \@esphack

164 }

\Ifopen On a besoin de tester si un fichier est déjà ouvert ou non.

165 \newcommand{\Ifopen}[3]{%
166 \csname if#1open\endcsname#2\else#3\fi}%

\Iffileundefined On a aussi besoin de tester si une variable de fichier a déjà été définie pour un descripteur de fichier donné.

167 \newcommand{\Iffileundefined}[3]{%
168 \csname ifx\expandafter\endcsname
169 \csname #1@file\endcsname\relax
170 #2\else#3\fi}

Enfin, on a besoin de tester si on doit faire la sortie sur un fichier ou non.

171 \newcommand{\Ifanswerfiles}[2]{%
172 \ifanswerfiles #1\else #2\fi}

10 L’interface fichier

\Opensolutionfile Avant de pouvoir écrire des solutions, nous devons ouvrir un (ou des) fichier de solutions. La commande pour faire cela prend un seul paramètre, qui est d’ordinaire un nom de fichier sans extension. Ainsi, ce sera sans doute une chaîne de 8 caractères pour la portabilité. Cette opération ne tronquera pas un fichier ouvert existant. Néanmoins, si le second paramètre optionnel est spécifié, ce dernier représente le nom de fichier actuel et le premier paramètre est alors un nom de descripteur symbolique de fichier arbitraire.

173 \def\Opensolutionfile#1{%
174 \@ifnextchar[{\define@filename{#1}}%
175 {\define@filename{#1}[#1]}}%
176 \def\define@filename#1[#2]{%
177 \global\@namedef{#1@filename}{#2\solutionpoint\solutionextension}%
178 \Ifanswerfiles{%
179 \typeout{Output from handle #1 going
180 to #2.\solutionextension}%
181 }{}%
182 \Iffileundefined{#1}{%
183 \expandafter\newwrite\csname #1@file\endcsname
184 \csname newif\expandafter\endcsname
185 \csname if#1open\endcsname
186 \global\csname #1openfalse\endcsname
187 \expandafter\ifx\csname Open#1hook\endcsname\relax
188 \global\@namedef{Open#1hook}##1{}%
189 \fi
190 \expandafter\ifx\csname Close#1hook\endcsname\relax
191 \global\@namedef{Close#1hook}##1{}%
192 \fi
193 }{}%
194 \let\Tmp\relax
195 \Ifopen{#1}{\typeout{File #1 already open}}{%
196 \Ifanswerfiles{%
197 \immediate\openout\@nameuse{#1@file}=%
198 \@nameuse{#1@filename}%
199 }{}%
200 \global\csname#1opentrue\endcsname
201 \def\Tmp{\@nameuse{Open#1hook}{#1}}%

202 }%

203 \Tmp

204 }

\Closesolutionfile Nous avons aussi une commande pour fermer un fichier préalablement ouvert.

205 \def\Closesolutionfile#1{%
206 \let\Tmp\relax

207 \Iffileundefined{#1}{}{%
208 \Ifopen{#1}{%
209 \Ifanswerfiles{%
210 \immediate\closeout\@nameuse{#1@file}%
211 }{}%
212 \global\csname #1openfalse\endcsname
213 \def\Tmp{\@nameuse{Close#1hook}{#1}}%
214 }{}%

215 }%

216 \Tmp

217 }

On notera que ces deux commandes fournissent un point d’entrée qui leur permet de réaliser des tâches supplémentaires. Par exemple, l’opération d’ouverture peut écrire des informations supplémentaires en redéfinissant le point d’entrée idoine. L’opération de fermeture peut, si nécessaire, réaliser un \input immédiat du contenu du fichier de solutions. Par exemple :

         \newcommand{\Openxxxhook}[2]{%
           \Writetofile{#1}{\protect\section{#2}}%
         }%
         \newcommand{\Closexxxhook}[1]{%
           \Readsolutionfile{#1}%
         }

et ensuite :

         \Opensolutionfile{xxx}{Réponses aux problèmes sélectionnés}
         ...
         \Closesolutionfile{xxx}

Le comportement par défaut est d’ignorer le premier paramètre. Notez que si vous le modifier, vous devez garder à l’esprit que le premier paramètre est toujours le descripteur de fichier.

\Readsolutionfile L’opération de lecture du fichier de solutions peut être accomplie avec la commande suivante.

218 \def\Readsolutionfile#1{%
219 \Ifanswerfiles{%
220 \Iffileundefined{#1}{}{%
221 \Ifopen{#1}{%
222 \typeout{WARNING: attempt to read open file #1}%
223 }{%
224 \edef\Tmp{%
225 \noexpand\InputIfFileExists
226 {\@nameuse{#1@filename}}{}%
227 {\noexpand\message{File
228 \@nameuse{#1@filename}%
229 \space not found}}%

230 }%

231 \Tmp

232 }% 233 }%

234 }{}%

235 }

236

11 L’interface solution

\Newassociation Plusieurs descripteurs de fichier de solutions peuvent être définis. Vous êtes seulement limités par le nombre que TEX met à votre disposition. Chaque environnement de solution, pour écrire dans l’un de ces descripteurs, doit connaître dans quel descripteur il doit écrire ainsi que les informations à ajouter au fichier, indépendamment de son contenu. On réalise ceci en créant une association entre l’environnement source, l’environnement destination et le descripteur de fichier.

237 \newcommand{\Newassociation}[3]{%
238 \newsolution{#2}%
239 \expandafter\ifx\csname #3opentrue\endcsname\relax
240 \expandafter\newif\csname if#3open\endcsname
241 \fi
242 \newenvironment{#1}{%
243 \Ifanswerfiles{%
244 \let\Tmp\relax
245 \Iffileundefined{#3}{}{%
246 \Ifopen{#3}{%
247 \immediate\write\@nameuse{#3@file}%
248 {\string\begin{#2}\@nameuse{#2params}}%
249 \def\Tmp{\Filesave{#3}}%
250 }{}%

251 }%

252 }{%
253 \edef\Tmp{\noexpand\begin{#2}\@nameuse{#2params}}%

254 }%

255 \csname pre#1\endcsname
256 \Tmp

257 }% 258 {%

259 \Ifanswerfiles{%
260 \Iffileundefined{#3}{}{%
261 \Ifopen{#3}{%
262 \endFilesave%
263 \immediate\write\@nameuse{#3@file}%
264 {\string\end{#2}}%
265 \csname post#1\endcsname
266 }{}%

267 }%

268 }{%
269 \end{#2}%

270 }% 271 }% 272 }

\newsolution L’environnement destination par défaut, dans le fichier de solution, est défini pour prendre un unique paramètre, un nombre de référence reçu de l’environnement source. Il est inséré avec le style \solutionstyle, valant par défaut \textbf. En plus, on peut ajouter au type de solution yyy des balises avant et après en définissant respectivement \preyyy et \postyyy, par exemple pour ajouter une ligne de la largeur de la page ou un symbole. Si quelque chose de plus sophistiqué est désiré, il est probablement mieux de redéfinir l’environnement par

\renewenvironment{yyy}.
\Currentlabel
273 \newcommand{\newsolution}[1]{%
274 \@ifundefined{#1}{%
275 \global\@namedef{#1params}{{\Currentlabel}}%
276 \newenvironment{#1}[1]%

277 {%

278 \csname pre#1\endcsname
279 \trivlist
280 \item[\hskip\itemsep{\@nameuse{#1label}{##1}}]}%
281 {\csname post#1\endcsname\endtrivlist}%
282 \global\@namedef{#1label}##1{\solutionstyle{##1}}%
283 }{\typeout{WARNING: environment #1 already in use}}%

284 }

285 \newcommand{\solutionstyle}[1]{\textbf{#1}}
286 \newcommand{\Currentlabel}{\@currentlabel}

Le format de l’étiquette pour l’environnement solution xxx est défini par la commande \xxxlabel, qui, par défaut, prend un argument. L’argument lui est passé par la commande \xxxparams, qui se développe en {\Currentlabel}, synonyme de {\@currentlabel} ; cette argument est écrit automatiquement par l’environnement source. L’étiquette apparaît en gras par défaut. Nous pouvons facilement changer le comportement de cet environnement en modifiant ces deux commandes. Par exemple :

        \renewcommand{\xxxlabel}[1]{\emph{Solution to #1}}
        \renewcommand{\xxxparams}{{\Currentlabel(p.\thepage)}}

fourniront un nombre et une référence de page en italique.

Des comportements plus compliqués peuvent être obtenus en redéfinissant l’environnement xxx lui-même, pour qu’il accepte différents paramètres. Notez cependant que \xxxparams doit être redéfinit pour fournir ces paramètres.

Voilà qui nous amène à la fin du package answers.

287 ⟨/answers⟩

Historique des changements

2.0

Général : Première version pour La-

TeX2e . . . . . . . . . . . . . . . . . . 1 2.02

Général : Fichier .drv supprimé de

l’installation . . . . . . . . . . . . . . 1 2.03

Général : Possibilité pour un descripteur de fichier d’ouvrir plusieurs fichiers successivement, en utilisant un paramètre otionnel. . . . . . . . . . . . . . . . . . . . . 1

2.04

Général : Ajout de l’option nosolutionfiles pour permettre que les solutions puissent suivre les problèmes pour un usage pédagogique. Quelques changements mineures pour améliorer la flexibilité. . . . . . . . . . . . . . . 1

2.05

Général : Meilleure documentation

des caractéristiques . . . . . . . . . 1 2.06

Général : Ajout de documentations supplémentaires, comme suggéré par David Epstein. … 1

2.07

Général : Condition pour tester si les fichiers ouverts n’ont pas été modifiés globalement (repéré par David Epstein). . . . . . 1

2.08

Général : Ajout d’exemples supplémentaires. . . . . . . . . . . . . . . . 1