texlive[69622] Master/texmf-dist: randexam (28jan24)

commits+karl at tug.org commits+karl at tug.org
Sun Jan 28 22:25:18 CET 2024


Revision: 69622
          https://tug.org/svn/texlive?view=revision&revision=69622
Author:   karl
Date:     2024-01-28 22:25:18 +0100 (Sun, 28 Jan 2024)
Log Message:
-----------
randexam (28jan24)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.pdf
    trunk/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex
    trunk/Master/texmf-dist/doc/latex/randexam/randexam-a-blank.pdf
    trunk/Master/texmf-dist/doc/latex/randexam/randexam-b-answer.pdf
    trunk/Master/texmf-dist/doc/latex/randexam/randexam-b-blank.pdf
    trunk/Master/texmf-dist/doc/latex/randexam/randexam.pdf
    trunk/Master/texmf-dist/doc/latex/randexam/randexam.tex
    trunk/Master/texmf-dist/tex/latex/randexam/randexam.cls

Modified: trunk/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex	2024-01-28 21:25:08 UTC (rev 69621)
+++ trunk/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex	2024-01-28 21:25:18 UTC (rev 69622)
@@ -12,11 +12,12 @@
 
 \examtitle{name=Math 1906 Final Exam,date=2018-06-28,version=A} % make exam title
 
-\gradetable
+\gradetable[total=4]
 
-\examgroup{Fill in the blanks.}{6 questions; 3 points for each; 18 points in total.}
+\exampart{Fill in the blanks.}{6 questions; 3 points for each; 18 points in total.}
 
-\answertable[3em]{6}{3} % make answer table: height 3em, six in total, three for each row
+% make answer table: six in total, three for each row, strut height 3em
+\answertable[total=6,column=3,strut=3em]
 
 \begin{question}
 The first question $k>0$, text $f(x)=\ln x-\frac{x}{\e}+k$ text $(0,+\infty)$
@@ -70,9 +71,10 @@
 
 \newpage
 
-\examgroup{Select one answer from four choices.}{6 questions; 3 points for each; 18 points in total.}
+\exampart{Select one answer from four choices.}{6 questions; 3 points for each; 18 points in total.}
 
-\answertable{6}{6} % 生成答题栏:默认行高,总共8题,每行8题
+% make answer table: six in total, six for each row, default strut height
+\answertable[total=6,column=6]
 
 \begin{question}
 The first question text, text text text text text text text text text text
@@ -168,7 +170,7 @@
 
 \newpage
 
-\examgroup{Work out math questions.}{6 questions; 8 points for each; 48 points in total.}
+\exampart{Work out math questions.}{6 questions; 8 points for each; 48 points in total.}
 
 \begin{question}
 The first question $\int\e^{2x}\,(\tan x+1)^2\dx$.
@@ -305,9 +307,9 @@
 
 \newpage
 
-\examgroup{Work out math proofs.}{2 questions; 16 points in total.}
+\exampart{Work out math proofs.}{2 questions; 16 points in total.}
 
-\renewcommand{\solutionname}{Proof} % 将“解”字改为“证”字
+\DeclareExamTranslation{current}{solution-Solution=Proof} % rename "Solution" as "Proof"
 
 \begin{question}[points=9]
 The first question $\{x_n\}$ text $x_1=\sqrt2$, $x_{n+1}=\sqrt{2+x_n}$.

Modified: trunk/Master/texmf-dist/doc/latex/randexam/randexam-a-blank.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/randexam/randexam-b-answer.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/randexam/randexam-b-blank.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/randexam/randexam.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/randexam/randexam.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/randexam/randexam.tex	2024-01-28 21:25:08 UTC (rev 69621)
+++ trunk/Master/texmf-dist/doc/latex/randexam/randexam.tex	2024-01-28 21:25:18 UTC (rev 69622)
@@ -3,7 +3,7 @@
 \documentclass[12pt,plain,most]{randexam}
 \geometry{b5paper,margin=2cm}
 
-\newcommand*{\myversion}{2024B}
+\newcommand*{\myversion}{2024C}
 \newcommand*{\mydate}{\the\year-\mylpad\month-\mylpad\day}
 \newcommand*{\mylpad}[1]{\ifnum#1<10 0\the#1\else\the#1\fi}
 
@@ -46,6 +46,7 @@
 \NewDocumentCommand\myfile{m}{\textcolor{purple3}{\mbox{#1}}}
 \NewDocumentCommand\mykey{m}{\textcolor{brown3}{\mbox{\fakeverb{#1}}}}
 \NewDocumentCommand\myval{m}{\textcolor{azure3}{\mbox{\fakeverb{#1}}}}
+\NewDocumentCommand\myelem{m}{\textcolor{violet3}{\mbox{#1}}}
 
 \begin{document}
 
@@ -57,6 +58,7 @@
     Title: \fillbox{\color{blue3}The randexam class for LaTeX}\\
     Author: \fillbox{Jianrui Lyu (tolvjr at 163.com)}\\
     Version: \fillbox{\myversion{} (\mydate)}\\
+    Code: \fillbox{\url{https://github.com/lvjr/randexam}}\\
     \hline
   \end{tabularx}%
 }
@@ -102,16 +104,16 @@
 \subsection{Document body}
 
 In document body you normally write an \mycmd{\examtitle},
-multiple \mycmd{\examgroup}, and an optional \mycmd{\examdata} commands:
+multiple \mycmd{\exampart}, and an optional \mycmd{\examdata} commands:
 
 \begin{code}
 \examtitle{name=Math Final Exam,date=2018-06-28,version=A}
 ......
-\examgroup{Fill in the blanks.}{3 points for each.}
+\exampart{Fill in the blanks.}{3 points for each.}
 ......
-\examgroup{Select one answer.}{3 points for each.}
+\exampart{Select one answer.}{3 points for each.}
 ......
-\examgroup{Work out math calculations.}{8 points for each.}
+\exampart{Work out math calculations.}{8 points for each.}
 ......
 \examdata{Some data may be used in the exam}
 ......
@@ -130,16 +132,16 @@
 When class option \myopt{random} is passed, the value of \mykey{version} key
 will be modified from \myval{A} to \myval{B}.
 
-\subsection{Exam groups}
+\subsection{Exam parts}
 
-The questions in an exam could be separated into several groups:
+The questions in an exam could be separated into several parts:
 
 \begin{code}
-\examgroup{Fill in the blanks.}{3 points for each.}
+\exampart{Fill in the blanks.}{3 points for each.}
 ......
-\examgroup{Select one answer.}{3 points for each.}
+\exampart{Select one answer.}{3 points for each.}
 ......
-\examgroup{Work out math calculations.}{8 points for each.}
+\exampart{Work out math calculations.}{8 points for each.}
 ......
 \end{code}
 
@@ -160,7 +162,7 @@
 \subsection{True-or-false questions}
 
 \begin{code}
-\examgroup{True-or-false questions}{3 points for each.}
+\exampart{True-or-false questions}{3 points for each.}
 
 \begin{question}
 The first true-or-false question. \tickout{T}
@@ -189,7 +191,7 @@
 \subsection{Fill-in-the-blank questions}
 
 \begin{code}
-\examgroup{Fill in the blanks.}{3 points for each.}
+\exampart{Fill in the blanks.}{3 points for each.}
 
 \begin{question}
 The first fill-in-the-blank question \fillout{answer}.
@@ -217,7 +219,7 @@
 \subsection{Multiple-choice questions}
 
 \begin{code}
-\examgroup{Select one answer.}{3 points for each.}
+\exampart{Select one answer.}{3 points for each.}
 
 \begin{question}
 The first multiple-choice questions \pickout{A}.
@@ -275,7 +277,7 @@
 For subjective questions, you could put answers inside \myenv{solution} environment.
 
 \begin{code}
-\examgroup{Work out math calculations.}{8 points for each.}
+\exampart{Work out math calculations.}{8 points for each.}
 
 \begin{question}
 The first math calculation question.
@@ -315,7 +317,7 @@
 You can write other types of questions. For example:
 
 \begin{code}
-\examgroup{Some question type}{4 points for each.}
+\exampart{Some question type}{4 points for each.}
 
 \begin{question}
 First question text. \answer{Answer text.}
@@ -345,11 +347,17 @@
 You can get it by using \mycmd{\gradetable} command.
 
 \begin{code}
-\gradetable
+\gradetable[total=6,strut=2em]
 \end{code}
 
-\gradetable
+\vspace{-1.5em}\gradetable[total=6,strut=2em]
 
+The meanings of keys in the \verb!\gradetable! command are:
+\begin{description}
+  \item[total] total number of parts in this exam.
+  \item[strut] strut height of the score row; its default value is \verb!2.5em!.
+\end{description}
+
 \subsection{Answer tables}
 
 Before true-or-false, fill-in-the-blank, or multiple-choice questions,
@@ -356,17 +364,18 @@
 you may use \mycmd{\answertable} to generate an blank answer table:
 
 \begin{code}
-\answertable[3em]{6}{3}
+\answertable[total=6,column=3,strut=3em]
 \end{code}
 
-\answertable[3em]{6}{3}
+\answertable[total=6,column=3,strut=3em]
 
-The meanings of the three arguments of \verb!\answertable! commands are as follows:
-\begin{itemize}
-  \item The first one means the strut height of the answer rows; its default value is \verb!1em!.
-  \item The second one means the total number of questions in this exam group.
-  \item The third one means the number of questions in each row.
-\end{itemize}
+The meanings of keys in the \verb!\answertable! command are:
+\begin{description}
+  \item[total] total number of questions in this exam part.
+  \item[column] number of questions in each row.
+  \item[strut] strut height of the answer rows; its default value is \verb!1em!.
+  \item[notice] notice text before the answer table.
+\end{description}
 
 \subsection{Vertical space}
 
@@ -412,12 +421,13 @@
 
 \subsection{Solution name}
 
-If you want to change the name of \myenv{solution} environment,
-you could redefine \mycmd{\solutionname} command.
+If you would like to change the name of \myenv{solution} environment,
+you could modify the translation of \mykey{solution-Solution} keyword
+(see Subsection \ref{subsect:translation}).
 The following example changes it from "Solution" to "Proof":
 
 \begin{code}
-\renewcommand{\solutionname}{Proof}
+\DeclareExamTranslation{current}{solution-Solution=Proof}
 \end{code}
 
 \subsection{Points command}
@@ -498,7 +508,7 @@
 \subsection{Randomized variants}\label{opt:random}
 
 Assume \myfile{exam-a-answer.tex} is an exam paper.
-You can get an randomized variant with all questions in the same group shuffled,
+You can get an randomized variant with all questions in the same part shuffled,
 by creating an \myfile{exam-b-answer.tex} file with the following lines:
 
 \begin{code}
@@ -507,7 +517,7 @@
 \end{code}
 
 That is to say, when adding \myopt{random} option to \mypkg{randexam} class,
-The questions in the same group will be shuffled in the compiled exam paper.
+The questions in the same part will be shuffled in the compiled exam paper.
 Furthermore, four choices in an \myenv{abcd} environment will be shuffled too.
 
 \subsection{Two column exam papers}
@@ -538,4 +548,147 @@
 That is to say, you can make an exam of A3 size from an exam of A4 size,
 even if you have only the PDF file.
 
+\section{Customizations}
+
+\subsection{Translations of keywords}\label{subsect:translation}
+
+With \mycmd{\DeclareExamTranslation} you can define the translaitons of the keywords
+in an \mypkg{randexam} paper. At this time only English keywords are defined:
+
+\begin{code}
+\DeclareExamTranslation{english}{
+   answertable-Answer   = Answer
+  ,answertable-Number   = Number
+  ,examdata-Appendix    = Appendix
+  ,exampart-Part        = Part
+  ,examtitle-Name       = Name
+  ,examtitle-Solutions  = Solutions
+  ,gradetable-Evaluator = Evaluator
+  ,gradetable-Part      = Part
+  ,gradetable-Score     = Score
+  ,gradetable-Total     = Total
+  ,headfoot-Name        = Name
+  ,headfoot-of          = of
+  ,headfoot-Page        = Page
+  ,headfoot-Solutions   = Solutions
+  ,headfoot-Version     = Version
+  ,points-point         = point
+  ,points-points        = points
+  ,question-Question    = Question
+  ,solution-Solution    = Solution
+}
+\end{code}
+
+You could translate them for another language and enable them with \mycmd{\SelectExamTranslation} command:
+
+\begin{code}
+\DeclareExamTranslation{somelang}{
+   question-Question    = Questioooooon
+  ,solution-Solution    = Soooooolution
+}
+\SelectExamTranslation{somelang}
+\end{code}
+\DeclareExamTranslation{somelang}{
+   question-Question    = Questioooooon
+  ,solution-Solution    = Soooooolution
+}
+\SelectExamTranslation{somelang}
+
+After this, you could load current translation of some keywords with \mycmd{\UseExamTranslation} command:
+
+\begin{code}
+\UseExamTranslation{question-Question}
+\UseExamTranslation{solution-Solution}
+\end{code}
+\hrule
+\UseExamTranslation{question-Question}
+\UseExamTranslation{solution-Solution}
+\vspace{0.5em}
+\hrule
+\vspace{0.5em}
+
+\SelectExamTranslation{english}
+
+This command is useful in defining new templates for the exam (see Subsection \ref{subsect:template}).
+
+\subsection{Saving and reading key values}
+
+With \mycmd{\DeclareExamValue} and \mycmd{\UseExamValue} you could save and read
+the value of a key, respectively.
+
+\begin{code}
+\DeclareExamValue{somemodule}{somekey}{SomeValue}
+\UseExamValue{somemodule}{somekey}
+\end{code}
+\hrule
+\DeclareExamValue{somemodule}{somekey}{SomeValue}
+\UseExamValue{somemodule}{somekey}
+\vspace{0.5em}
+\hrule
+\vspace{0.5em}
+
+These two commands are useful in defining new templates
+for the exam (see Subsection \ref{subsect:template}).
+
+\subsection{Templates of elements}\label{subsect:template}
+
+With \mycmd{\DeclareExamTemplate} you could define a new template for some exam element,
+which could be set as default template with \mycmd{\SelectExamTemplate}.
+And with \mycmd{\UseExamTemplate} you could use the default template of the element.
+
+To customize \myelem{examtitle} element for your school,
+you can write the following code in document preamble:
+\begin{code}
+\DeclareExamTemplate{examtitle}{myschool}{%
+  \fbox{%
+    \UseExamValue{examtitle}{name}\quad%
+    \UseExamValue{examtitle}{date}%
+  }%
+}%
+\SelectExamTemplate{examtitle}{myschool}
+\end{code}
+\DeclareExamTemplate{examtitle}{myschool}{%
+  \fbox{%
+    \UseExamValue{examtitle}{name}\quad%
+    \UseExamValue{examtitle}{date}%
+  }%
+}%
+\SelectExamTemplate{examtitle}{myschool}
+
+Then the \mycmd{\examtitle} command in document body will produce different result:
+\begin{code}
+\examtitle{name=Final Exam in My School,date=2024-01-01}
+\end{code}
+\vspace{-1em}
+\examtitle{name=Final Exam in My School,date=2024-01-01}
+
+Normally \mycmd{\examtitle} will call \mycmd{\UseExamTemplate{examtitle}{default}}.
+
+All elements that could be customized with templates in an exam paper
+are listed in the following table:
+
+\begingroup\renewcommand\arraystretch{1.5}\noindent
+\begin{tabularx}{\linewidth}{ll}
+\hline
+  \myelem{examtitle}     & for customizing \mycmd{\examtitle} command \\
+\hline
+  \myelem{exampart}      & for customizing \mycmd{\exampart} command \\
+\hline
+  \myelem{examdata}      & for customizing \mycmd{\examdata} command \\
+\hline
+  \myelem{gradetable}    & for customizing \mycmd{\gradetable} command \\
+\hline
+  \myelem{answertable}   & for customizing \mycmd{\answertable} command \\
+\hline
+  \myelem{questionbegin} & for customizing \myenv{question} environment \\
+\hline
+  \myelem{questionend}   & for customizing \myenv{question} environment \\
+\hline
+  \myelem{solutionbegin} & for customizing \myenv{solution} environment \\
+\hline
+  \myelem{solutionend}   & for customizing \myenv{solution} environment \\
+\hline
+\end{tabularx}\par
+\endgroup
+
 \end{document}

Modified: trunk/Master/texmf-dist/tex/latex/randexam/randexam.cls
===================================================================
--- trunk/Master/texmf-dist/tex/latex/randexam/randexam.cls	2024-01-28 21:25:08 UTC (rev 69621)
+++ trunk/Master/texmf-dist/tex/latex/randexam/randexam.cls	2024-01-28 21:25:18 UTC (rev 69622)
@@ -5,9 +5,9 @@
 % ----------------------------------------------------------------------------
 
 \NeedsTeXFormat{LaTeX2e}
-\ProvidesClass{randexam}[2024-01-20 v2024B Make an exam paper and its randomized variants]
+\ProvidesClass{randexam}[2024-01-28 v2024C Make an exam paper and its randomized variants]
 
-%% Old LaTeX release could not recongnize date format like 2022-11-01
+%% Old LaTeX release could not recognize date format like 2022-11-01
 %\@ifl at t@r\fmtversion{2022-11-01}{}{
 \@ifl at t@r\fmtversion{2022/11/01}{}{
   \ClassError{randexam}{%
@@ -16,6 +16,9 @@
   }{Please update your TeX distribution first.}
 }
 
+\RequirePackage{functional}
+\IgnoreSpacesOn
+
 \RequirePackage{etoolbox}
 
 \newbool{plain}       \boolfalse{plain}      % use plain page style
@@ -27,7 +30,7 @@
 \newbool{amsfonts}    \boolfalse{amsfonts}   % use ams fonts
 \newbool{freealign}   \boolfalse{freealign}  % load freealign package
 \newbool{medmath}     \boolfalse{medmath}    % use medium-size formulas
-\newbool{grader}      \boolfalse{grader}     % add grader line in the grade table
+\newbool{evaluator}   \boolfalse{evaluator}  % add evaluator line in the grade table
 
 \DeclareKeys{
   plain     .if    = plain,
@@ -39,7 +42,7 @@
   amsfonts  .if    = amsfonts,
   freealign .if    = freealign,
   medmath   .if    = medmath,
-  grader    .if    = grader,
+  evaluator .if    = evaluator,
   many      .code  = \booltrue{freealign},
   most      .code  = \booltrue{freealign}\booltrue{medmath}
 }
@@ -66,7 +69,6 @@
 \RequirePackage{zref-user,zref-lastpage}
 \RequirePackage{tabularx}
 \RequirePackage{xcolor}
-\RequirePackage{xkeyval}
 
 \ifplain
   \allowdisplaybreaks[4]
@@ -91,6 +93,103 @@
 \NewDocumentCommand\SetExamOption{+m}{\SetKeys[randexam]{#1}}
 
 %% ---------------------------------------------------------------------------
+%% Template commands for exam elements
+%% ---------------------------------------------------------------------------
+
+%% #1: exam element; #2: template name; #3: template code
+%% If the template name = default, we enable the template at once
+%% Otherwise, we may enable the template by using \SelectExamTemplate command
+\NewDocumentCommand\DeclareExamTemplate{mm+m}{
+  \tlSet{\expName{l at rdxm@template@#1@#2 at tl}}{#3}
+  \ignorespaces
+}
+
+%% #1: exam element; #2: template name
+\NewDocumentCommand\SelectExamTemplate{mm}{
+  \tlSetEq{\expName{l at rdxm@template@#1 at default@tl}}{\expName{l at rdxm@template@#1@#2 at tl}}
+  \ignorespaces
+}
+
+%% #1: exam element; #2: template name.
+%% In an expandable command, we should use \UseName but not \expName.
+\NewExpandableDocumentCommand\UseExamTemplate{mm}{
+  \UseName{l at rdxm@template@#1@#2 at tl}
+}
+
+%% ---------------------------------------------------------------------------
+%% Translation commands for exam keywords
+%% ---------------------------------------------------------------------------
+
+\tlSet\l at rdxm@current at language@tl{english}
+
+\DeclareUnknownKeyHandler[randexam-translation]{
+  \tlSet{\expName{l at rdxm@translate@\l at rdxm@declare at language@tl @#1 at tl}}{#2}
+}
+
+%% #1: language name; #2: a keyval list with keyword = transaltion format
+\NewDocumentCommand\DeclareExamTranslation{mm}{
+  \tlIfEqTF{#1}{current}{
+    \tlSetEq\l at rdxm@declare at language@tl\l at rdxm@current at language@tl
+  }{
+    \tlSet\l at rdxm@declare at language@tl{#1}
+  }
+  \SetKeys[randexam-translation]{#2}
+  \ignorespaces
+}
+
+%% #1: language name
+\NewDocumentCommand\SelectExamTranslation{m}{
+  \tlSet\l at rdxm@current at language@tl{#1}
+  \ignorespaces
+}
+
+%% #1: keyword name.
+%% In an expandable command, we should use \UseName but not \expName.
+\NewExpandableDocumentCommand\UseExamTranslation{m}{
+  \UseName{l at rdxm@translate@\l at rdxm@current at language@tl @#1 at tl}
+}
+
+\DeclareExamTranslation{english}{
+   answertable-Answer   = Answer
+  ,answertable-Number   = Number
+  ,examdata-Appendix    = Appendix
+  ,exampart-Part        = Part
+  ,examtitle-Name       = Name
+  ,examtitle-Solutions  = Solutions
+  ,gradetable-Evaluator = Evaluator
+  ,gradetable-Part      = Part
+  ,gradetable-Score     = Score
+  ,gradetable-Total     = Total
+  ,headfoot-Name        = Name
+  ,headfoot-of          = of
+  ,headfoot-Page        = Page
+  ,headfoot-Solutions   = Solutions
+  ,headfoot-Version     = Version
+  ,points-point         = point
+  ,points-points        = points
+  ,question-Question    = Question
+  ,solution-Solution    = Solution
+}
+
+\SelectExamTranslation{english}
+
+%% ---------------------------------------------------------------------------
+%% Keyvalue commands for exam options
+%% ---------------------------------------------------------------------------
+
+%% #1 module name; #2: key name; #3: its value
+\NewDocumentCommand\DeclareExamValue{mm+m}{
+  \tlSet{\expName{l at rdxm@value@#1@#2 at tl}}{#3}
+  \ignorespaces
+}
+
+%% #1: module name; #2: key name.
+%% In an expandable command, we should use \UseName but not \expName.
+\NewExpandableDocumentCommand\UseExamValue{mm}{
+  \UseName{l at rdxm@value@#1@#2 at tl}
+}
+
+%% ---------------------------------------------------------------------------
 %% Command for exam title: \examtitle
 %% ---------------------------------------------------------------------------
 
@@ -101,88 +200,143 @@
 \newcommand{\ischeck}[1]{\ifnum#1>0\,$\checkmark$\,\else\quad\fi}
 \newcommand{\isquad}[1]{\ifnum#1=0\,$\checkmark$\,\else\quad\fi}
 
-\def\rdxm at temp@a{A}
-\def\rdxm at temp@c{C}
-\def\rdxm at empty{}
-
 \DeclareKeys[randexam-title]{
-  name    .store = \@rdxm at title@name,
-  date    .store = \@rdxm at title@date,
-  version .store = \@rdxm at title@version
+   name    .code = \DeclareExamValue{examtitle}{name}{#1}
+  ,date    .code = \DeclareExamValue{examtitle}{date}{#1}
+  ,version .code = \DeclareExamValue{examtitle}{version}{#1}
 }
 
 \NewDocumentCommand\SetExamTitle{+m}{\SetKeys[randexam-title]{#1}}
 
-\SetExamTitle{name=Math 1906,date=\today,version=A}
+\SetExamTitle{name=Math~1906,date=\today,version=A}
 
-\newcommand\examtitle[1]{%
-  \SetExamTitle{#1}%
-  \thispagestyle{plain}
-  \ifbool{random}{%
-    \ifx\@rdxm at title@version\rdxm at temp@a\def\@rdxm at title@version{B}\fi
-    \ifx\@rdxm at title@version\rdxm at temp@c\def\@rdxm at title@version{D}\fi
-  }{}%
+\DeclareExamTemplate{examtitle}{normal}{
   \begingroup
   \Large\noindent
-  \ifbool{answer}{%
-    \textcolor{red!80!black}{\@rdxm at title@name\hfill Solutions}%
-  }{%
-    \@rdxm at title@name\hfill Name:\underspace{6em}%
+  \ifbool{answer}{
+    \textcolor{red!80!black}{
+      \UseExamValue{examtitle}{name}\hfill\UseExamTranslation{examtitle-Solutions}
+    }
+  }{
+    \UseExamValue{examtitle}{name}\hfill\UseExamTranslation{examtitle-Name}:\underspace{6em}
   }\par
   \endgroup
 }
+\SelectExamTemplate{examtitle}{normal}
 
+\NewDocumentCommand\examtitle{+m}{
+  \SetExamTitle{#1}
+  \thispagestyle{plain}
+  \ifbool{random}{
+    \tlIfEqT{\expWhole{\UseExamValue{examtitle}{version}}}{A}{
+      \DeclareExamValue{examtitle}{version}{B}
+    }
+    \tlIfEqT{\expWhole{\UseExamValue{examtitle}{version}}}{C}{
+      \DeclareExamValue{examtitle}{version}{D}
+    }
+  }{}
+  \UseExamTemplate{examtitle}{default}
+}
+
 %% ---------------------------------------------------------------------------
 %% Command for grade table: \gradetable
 %% ---------------------------------------------------------------------------
 
-%% You need to put .code:n before .initial:n
-\DeclareKeys[randexam]{%
-  groupnumber .code:n    = \let\exam at group@number#1,
-  groupnumber .initial:n = \Roman,
+%% total: total number of parts in current exam;
+%% strut: strut height in the score row.
+\DeclareKeys[randexam-gradetable]{
+   total  .code      = \DeclareExamValue{gradetable}{total}{#1}
+  ,total  .initial:n = 6
+  ,strut  .code      = \DeclareExamValue{gradetable}{strut}{#1}
+  ,strut  .initial:n = 2.5em
 }
 
 \newcounter{@exam at grade@cnt}
-\newcommand\rdxm at group@number[1]{%
-  \stepcounter{@exam at grade@cnt}%
-  \exam at group@number{@exam at grade@cnt}%
+\newrobustcmd\rdxm at part@number[1]{
+  \setcounter{@exam at grade@cnt}{#1}
+  \exam at part@number{@exam at grade@cnt}
 }
 
-\newcommand\insertgroupname{Part}
-\newcommand\insertscorename{Score}
-\newcommand\insertgradername{Grader}
-\newcommand\inserttotalname{Total}
+%% #1: the tl variable; #2: the first cell; #3: the last cell
+%% #4: the number of middle cells; #5: the map command for middle cells.
+\newrobustcmd\rdxm at table@make at row[5]{
+  \tlSet#1{#2 & }
+  \intStepOneInline{1}{#4}{
+    \tlPutRight#1{#5{##1} &}
+  }
+  \tlPutRight#1{ #3}
+}
 
-\newcommand\gradetable{%
-  \par\vspace{1em}%
-  \setcounter{@exam at grade@cnt}{0}%
-  \noindent\begin{tabularx}{\linewidth}{|*{8}{Y|}}
+\newrobustcmd\rdxm at gobble@one[1]{}
+
+%% \dimeval or \dimexpr doesn't accept decimal numbers such as 0.3
+\NewDocumentCommand\MakeExamStruct{m}{
+  \rule[-\dimeval{(#1)*3/10}]{0pt}{#1}
+}
+
+\DeclareExamTemplate{gradetable}{normal}{
+  \rdxm at table@make at row
+    \l at rdxm@gradetable at part@tl
+    {\textbf{\UseExamTranslation{gradetable-Part}}}
+    {\UseExamTranslation{gradetable-Total}}
+    {\UseExamValue{gradetable}{total}}
+    \rdxm at part@number
+  \rdxm at table@make at row
+    \l at rdxm@gradetable at score@tl
+    {\textbf{\UseExamTranslation{gradetable-Score}}
+         \MakeExamStruct{\UseExamValue{gradetable}{strut}}}
+    {}
+    {\UseExamValue{gradetable}{total}}
+    \rdxm at gobble@one
+  \ifbool{evaluator}{
+    \rdxm at table@make at row
+      \l at rdxm@gradetable at evaluator@tl
+      {\textbf{\UseExamTranslation{gradetable-Evaluator}}
+           \MakeExamStruct{\UseExamValue{gradetable}{strut}}}
+      {}
+      {\UseExamValue{gradetable}{total}}
+      \rdxm at gobble@one
+  }{}
+  \noindent
+  \begin{tabularx}{\linewidth}{|c|*{\UseExamValue{gradetable}{total}}{Y|}Y|}
     \hline
-    \textbf{\insertgroupname}
-      & \rdxm at group@number{1} & \rdxm at group@number{2} & \rdxm at group@number{3}
-      & \rdxm at group@number{4} & \rdxm at group@number{5} & \rdxm at group@number{6}
-      & \inserttotalname\\
-    \hline
-    \textbf{\insertscorename}\rule[-0.75em]{0pt}{2.5em} &  &  &  &  &  &  & \\
-    \hline
-    \ifbool{grader}{
-      \textbf{\insertgradername}\rule[-0.75em]{0pt}{2.5em} &  &  &  &  &  &  & \\
-      \hline
-    }{}
+    \l at rdxm@gradetable at part@tl \\ \hline
+    \l at rdxm@gradetable at score@tl \\ \hline
+    \ifbool{evaluator}{\l at rdxm@gradetable at evaluator@tl \\ \hline}{}
   \end{tabularx}
 }
+\SelectExamTemplate{gradetable}{normal}
 
+\NewDocumentCommand\gradetable{O{}}{
+  \par\vspace{1em}
+  \begingroup
+  \SetKeys[randexam-gradetable]{#1}
+  \UseExamTemplate{gradetable}{default}
+  \endgroup
+}
+
 %% ---------------------------------------------------------------------------
 %% Setting header and footer
 %% ---------------------------------------------------------------------------
 
 \newcommand{\rdxm at columnbox}[1]{\makebox[\columnwidth]{#1}}
-\newcommand{\rdxm at headleft}{\@rdxm at title@name}
-\newcommand{\rdxm at headright}{\ifbool{answer}{Solutions}{Name:\hspace{12em}}}
+\newcommand{\rdxm at headleft}{\UseExamValue{examtitle}{name}}
+\newcommand{\rdxm at headright}{
+  \ifbool{answer}{
+    \UseExamTranslation{headfoot-Solutions}
+  }{
+    \UseExamTranslation{headfoot-Name}:\hspace{12em}
+  }
+}
 \newcommand{\rdxm at headtext}{\rdxm at headleft\hfill\rdxm at headright}
-\newcommand{\rdxm at footleft}{\@rdxm at title@date}
-\newcommand{\rdxm at footcenter}{Page~\thepage~of~\zpageref{LastPage}}
-\newcommand{\rdxm at footright}{Version \@rdxm at title@version}
+\newcommand{\rdxm at footleft}{\UseExamValue{examtitle}{date}}
+\newcommand{\rdxm at footcenter}{
+  \UseExamTranslation{headfoot-Page}~\thepage\space
+  \UseExamTranslation{headfoot-of}~\zpageref{LastPage}
+}
+\newcommand{\rdxm at footright}{
+  \UseExamTranslation{headfoot-Version}~\UseExamValue{examtitle}{version}
+}
 \newcommand{\rdxm at foottext}{\rdxm at footleft\hfill\rdxm at footcenter\hfill\rdxm at footright}
 
 % fancy page style
@@ -235,7 +389,7 @@
   \RequirePackage{pgffor}
   \newcommand*\exam at set@seed{%
     %% 当\pgfmathrandom的参数为3的倍数时,对相邻种子生成的多个随机数分布不均匀
-    %\pgfmathsetseed{\numexpr\rdxm at random@seed+\value{rdxm at group}-1\relax}%
+    %\pgfmathsetseed{\numexpr\rdxm at random@seed+\value{rdxm at part}-1\relax}%
     %% 因此我们改用下面的方法,用随机数种子生成下一个随机数种子
     \pgfmathsetseed{\rdxm at random@seed}%
     \pgfmathrandominteger\rdxm at random@seed{1}{2147483647}%
@@ -243,12 +397,18 @@
 \fi
 
 %% ---------------------------------------------------------------------------
-%% Command for exam groups: \examgroup
+%% Command for exam groups: \exampart
 %% Command for appendix data: \examdata
 %% Environment for questions: question
 %% Environment for solutions: solution
 %% ---------------------------------------------------------------------------
 
+%% You need to put .code before .initial:n
+\DeclareKeys[randexam-exampart]{%
+  partnumber .code      = \let\exam at part@number#1,
+  partnumber .initial:n = \Roman,
+}
+
 \newif\ifonlyonequestion \onlyonequestionfalse % 此部分仅有一道题时不显示题目编号
 \xdef\allquestions{}
 \xdef\lastquestion{}
@@ -255,13 +415,13 @@
 \newcounter{question}        % 当前题型的小题编号
 \newcounter{questionreal}    % 实际显示的小题编号,在各题型小题统一编号时使用
 \newcounter{totalquestions}  % 之前各题型小题总数,在各题型小题统一编号时使用
-\newcommand{\solutionname}{Solution}
+
 \newcounter{choice} % 后面选择题的 abcd 环境要用到
 \newcommand{\hangtext}{}
 \newlength{\hanglength}
-\colorlet{group number}{black}
-\colorlet{question number}{blue!80!black}
-\colorlet{solution name}{blue!80!black}
+\colorlet{part~number}{black}
+\colorlet{question~number}{blue!80!black}
+\colorlet{solution~name}{blue!80!black}
 
 \newcounter{rdxm at shuffle@temp at cnt}
 \newcounter{rdxm at list@temp at cnt}
@@ -337,19 +497,29 @@
   \xdef\lastquestion{}%
 }
 
-\newcounter{rdxm at group}
+\newcounter{rdxm at part}
 
-\newcommand\insertgroup[2]{%
-  \noindent\textbf{\textcolor{group number}{Part~\Roman{rdxm at group}}: #1} (#2)%
+\DeclareExamTemplate{exampart}{normal}{
+  \noindent
+  \textbf{
+    \textcolor{part~number}{\UseExamTranslation{exampart-Part}~\Roman{rdxm at part}}
+    :~\UseExamValue{exampart}{type}
+  }
+  \space(\UseExamValue{exampart}{points})
 }
+\SelectExamTemplate{exampart}{normal}
 
-\newcommand{\examgroup}[2]{%
+\newcommand{\exampart}[2]{
   \printquestions
-  \setcounter{totalquestions}{\value{totalquestions}+\value{question}}%
-  \setcounter{question}{0}%
-  \stepcounter{rdxm at group}%
-  \vspace{1em}%
-  \insertgroup{#1}{#2}%
+  \setcounter{totalquestions}{\value{totalquestions}+\value{question}}
+  \setcounter{question}{0}
+  \stepcounter{rdxm at part}
+  \vspace{1em}
+  \begingroup
+  \DeclareExamValue{exampart}{type}{#1}
+  \DeclareExamValue{exampart}{points}{#2}
+  \UseExamTemplate{exampart}{default}
+  \endgroup
   \par\nopagebreak
   \if\relax\detokenize{#1}\relax % #1 is empty
     \onlyonequestiontrue
@@ -361,10 +531,19 @@
   \@afterheading
 }
 
-\renewcommand\appendixname{Appendix}
-\newcommand{\examdata}[1]{%
+\DeclareExamTemplate{examdata}{normal}{
+  \centerline{
+    \textbf{\UseExamTranslation{examdata-Appendix}}
+    \quad\UseExamValue{examdata}{caption}
+  }
+  \smallskip
+}
+\SelectExamTemplate{examdata}{normal}
+
+\NewDocumentCommand\examdata{+m}{
   \printquestions\rdxm at stop@random
-  \centerline{\textbf{\appendixname}\quad #1}\smallskip
+  \DeclareExamValue{examdata}{caption}{#1}
+  \UseExamTemplate{examdata}{default}
 }
 
 \preto{\@enddocumenthook}{\printquestions\rdxm at stop@random}
@@ -371,48 +550,78 @@
 
 \newcommand\ignorepars{\@ifnextchar\par{\expandafter\ignorepars\@gobble}{}}
 
-% 局部定义,仅在当前题目内有效
-\define at key{exam at question}{points}[-1]{\def\rdxm at question@points{#1}}
-\define at key{exam at question}{level}[]{\def\rdxm at question@level{#1}}
-\define at key{exam at question}{year}[]{\def\rdxm at question@year{#1}}
+% local definition, valid only in current question
+\DeclareKeys[randexam-question]{
+   points .store = \l at rdxm@question at points
+  ,level  .store = \l at rdxm@question at level
+  ,year   .store = \l at rdxm@question at year
+}
 
-\newcommand\pointname{point}
-\newcommand\pointsname{points}
-\newcommand\pointorpoints[1]{\ifnumgreater{#1}{1}{\pointsname}{\pointname}}
+\newcommand\pointorpoints[1]{
+  \ifnumgreater{#1}{1}{
+    \UseExamTranslation{points-points}
+  }{
+    \UseExamTranslation{points-point}
+  }
+}
 
 \newcommand{\questionpointstext}[1]{ (#1 \pointorpoints{#1}) }
 
 \newcommand\rdxm at hook@exec at other@keys{}
 
-\newcommand{\execute at question@keys}[1]{%
-  \setkeys{exam at question}{#1}%
+\newrobustcmd\execute at question@keys{
   \rdxm at hook@exec at other@keys
-  \ifdefvoid{\rdxm at question@points}{}{\questionpointstext{\rdxm at question@points}}%
+  \ifdefvoid{\l at rdxm@question at points}{}{\questionpointstext{\l at rdxm@question at points}}
 }
 
-\newenvironment{questionreal}[1][]{%
-  \stepcounter{question}\setcounter{choice}{0}%
+\DeclareExamTemplate{questionbegin}{normal}{
   \ifresetnumber
     \ifonlyonequestion
       \renewcommand{\hangtext}{\qquad}%
     \else
-      \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{question number}{\arabic{question}}.}}\;\,}%
+      \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{question~number}{\arabic{question}}.}}\;\,}
     \fi
   \else
     \setcounter{questionreal}{\value{totalquestions}+\value{question}}%
-    \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{question number}{\arabic{questionreal}}.}}\;\,}%
+    \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{question~number}{\arabic{questionreal}}.}}\;\,}
   \fi
-  \settowidth{\hanglength}{\hangtext}%
+  \settowidth{\hanglength}{\hangtext}
   \description[leftmargin=\hanglength,labelwidth=0pt,labelsep=0pt,topsep=0pt,parsep=0pt]
-  \item[\hangtext]\execute at question@keys{#1}%
-}{\enddescription}
-\newenvironment{solutionreal}{%
-  \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{solution name}{\solutionname}.}}\;\,}%
-  \settowidth{\hanglength}{\hangtext}%
+  \item[\hangtext]\execute at question@keys
+}
+\SelectExamTemplate{questionbegin}{normal}
+
+\DeclareExamTemplate{questionend}{normal}{\enddescription}
+\SelectExamTemplate{questionend}{normal}
+
+\NewDocumentEnvironment{questionreal}{O{}}{
+  \stepcounter{question}
+  \setcounter{choice}{0}
+  \SetKeys[randexam-question]{#1}
+  \UseExamTemplate{questionbegin}{default}
+}{
+  \UseExamTemplate{questionend}{default}
+}
+
+\DeclareExamTemplate{solutionbegin}{normal}{
+  \renewcommand{\hangtext}{
+    \textbf{\textsf{\textcolor{solution~name}{\UseExamTranslation{solution-Solution}}.}}\;\,
+  }
+  \settowidth{\hanglength}{\hangtext}
   \description[leftmargin=\hanglength,labelwidth=0pt,labelsep=0pt,topsep=0pt,parsep=0pt]
   \item[\hangtext]
-}{\enddescription}
+}
+\SelectExamTemplate{solutionbegin}{normal}
 
+\DeclareExamTemplate{solutionend}{normal}{\enddescription}
+\SelectExamTemplate{solutionend}{normal}
+
+\NewDocumentEnvironment{solutionreal}{}{
+  \UseExamTemplate{solutionbegin}{default}
+}{
+  \UseExamTemplate{solutionend}{default}
+}
+
 \let \oldnewpage   = \newpage
 \let \oldvfill     = \vfill
 \let \oldsmallskip = \smallskip
@@ -480,28 +689,37 @@
 %% Command for answer tables: \answertable
 %% ---------------------------------------------------------------------------
 
+%% property .store is the same as .tl_set:N in ltkeys.
+%% you need to put .code before .initial:n.
+%% total: total number of questions in current exam part;
+%% column: number of questions in each answer row;
+%% strut: strut height in each answer rows;
+%% notice: notice text before the answer table.
+\DeclareKeys[randexam-answertable]{
+   total  .code      = \DeclareExamValue{answertable}{total}{#1}
+  ,column .code      = \DeclareExamValue{answertable}{column}{#1}
+  ,strut  .code      = \DeclareExamValue{answertable}{strut}{#1}
+  ,strut  .initial:n = 1em
+  ,notice .code      = \DeclareExamValue{answertable}{notice}{#1}
+  ,notice .initial:n = {Notice:~you~MUST~write~the~answers~in~the~following~tables.}
+}
+
 \gdef\answer at lines@temp{}%
 \newcommand{\answer at lines@add}[1]{%
   \xdef\answer at lines@temp{\answer at lines@temp#1}%
 }
 
-\newcommand\insertnumbertext{Number}
-\newcommand\insertanswertext{Answer}
-\newcommand\insertanswertabletext{%
-  Notice: you MUST write the answers in the following tables.%
+\newrobustcmd\answer at number@hided[1]{\UseExamTranslation{answertable-Number}}
+\newrobustcmd\answer at cell@strut[1]{
+  \parbox[c][#1][c]{2em}{\hbox{\UseExamTranslation{answertable-Answer}}}
 }
 
-\newrobustcmd{\answer at number@hided}[1]{\insertnumbertext} % 在 PDFLaTeX 中需要保护中文
-\newrobustcmd{\answer at cell@strut}[1]{\parbox[c][#1][c]{2em}{\hbox{\insertanswertext}}}
-
 \newcounter{answer at col}
 \newcounter{answer at row}
 \newcounter{answer at total}
 
+%% #1: strut; #2: total; #3: column.
 \newcommand{\answer at lines}[3]{%
-  % #1 答题栏各栏指定高度
-  % #2 答题栏总共答案个数
-  % #3 答题栏每行答案个数
   \setcounter{answer at row}{(#2-1)/#3+1}% 除法向下取整,改为向上取整
   \begingroup
   \let\hline=\relax  \let\\=\relax % 禁止展开
@@ -537,15 +755,24 @@
   \answer at lines@temp
 }
 
-\newcommand{\answertable}[3][1em]{%
-  \insertanswertabletext\par
-  \begin{tabularx}{\linewidth}{|c|*{#3}{Y|}}
+\DeclareExamTemplate{answertable}{normal}{
+  \UseExamValue{answertable}{notice}\par
+  \begin{tabularx}{\linewidth}{|c|*{\UseExamValue{answertable}{column}}{Y|}}
     \hline
-    \answer at lines{#1}{#2}{#3}
-  \end{tabularx}%
-  \par\vspace{0.8em}%
+    \answer at lines{\UseExamValue{answertable}{strut}}
+      {\UseExamValue{answertable}{total}}{\UseExamValue{answertable}{column}}
+  \end{tabularx}
 }
+\SelectExamTemplate{answertable}{normal}
 
+\NewDocumentCommand\answertable{O{}}{
+  \begingroup
+  \SetKeys[randexam-answertable]{#1}
+  \UseExamTemplate{answertable}{default}
+  \endgroup
+  \par\vspace{0.8em}
+}
+
 %% ---------------------------------------------------------------------------
 %% Command for toggling answers: \answer
 %% Command for true-or-false questions: \tickin and \tickout
@@ -940,3 +1167,5 @@
     \let \downwhitearrow = \Downarrow
 }}
 
+\IgnoreSpacesOff
+



More information about the tex-live-commits mailing list.