.. SPDX-FileCopyrightText: 2025 Xavier Bordoy .. .. SPDX-License-Identifier: CC-BY-SA-4.0 Tutorial ######## .. note:: You can visit the :doc:`worksheets` page if you are just interested to download the existing worksheets of exercises. This document is to show how to create exercises and templates to produce custom worksheets in your own computer. This tutorial is intended for new users of project worksheet.cc. It does not give an exhaustive account of all the features of worksheet.cc libraries, just of those that you are likely to use right away. Problem statement ================= Karl is a math secondary-level teacher. He brought math worksheets to students in order to practice routinary skills. In the past, Karl did it by hand, but he saw that he needed some computer program to do it automatically. He searched the internet and found project worksheet. Karl's problem is creating a worksheet for practicing fraction addition. He wants a sheet for each student and also wants to have the possibility of generating as many different worksheets as he wants. And he wants to do it *automatically*. He desires to generate a PDF document file using professional publication system like `LaTeX `__ or `ConTeXt `__. To do that, first of all, he needs to write an exercise. This exercise is simple: :: Sum $\frac{a}{b} + \frac{c}{d}$ where :math:`a`, :math:`b`, :math:`c` and :math:`d` are integers, with the constraint :math:`b, d \neq 0`. Thus, this exercise depends on four parameters. He decides to put extra conditions of those parameters: - :math:`1 \leq a, c \leq 100` to have resulting small numbers in the operations - :math:`d = b + 2` to assure some relation between :math:`d` and :math:`b` (for instance these are different numbers) and :math:`2 \leq b \leq 100` Creating the exercise ===================== With all of previous decissions and constraints, he writes his first exercise: :: --- parameters: a: random.randint(1,100) b: random.randint(2, 100) c: random.randint(1,100) d: params['b'] + 2 solution: | {% set sum = fractions.Fraction(params['a']*params['d'] + params['b']*params['c'], params['b']*params['d']) %} The solution is $\frac{ {{sum.numerator}} }{ {{sum.denominator}} }$. --- Calculate the sum of $\frac{ {{params['a']}} }{ {{params['b']}} } + \frac{ {{params['c']}} }{ {{params['d']}} }$ He saves as :download:`tutorial-exercise.md <../src/examples/tutorial-exercise.en.md>`. Note that: - The exercise has two parts: the `YAML `__ header which is enclosed by the symbols ``---``, and the rest of the file. By convention, we assume that the rest of the file corresponds to the text or statement of the exercise while in the YAML headers there is the extra information like solution, resolution, author, etc. The YAML-headers keys are totally optional. - The parameters are specified in the ``parameters`` key in the YAML header. - We could define relation among parameters using ``params[x]`` variable. The ``params`` corresponds to the evaluation of the ``parameters`` keys (see :py:meth:`wklib.Exercise.params` function). - The file uses `Jinja template system syntax `__: in this example, we call a variable ``foo`` value using ``{{foo}}``. Creating the template ====================== To generate an *instance* (mathematically, a *numerical value* or a *evaluation*) of the exercise, Karl needs a template. He needs it to compose the different components of the exercise: how statement and solution will be displayed. And also to set the appearance of the exercise sheet: headers, fonts, margins, etc. It can be said that it is the visual part of the resulting worksheet. To produce the final PDF file, he decides to use LaTeX. Therefore, he creates a simple template file, called :download:`mytemplate.tex <../src/examples/mytemplate.tex>`: :: \documentclass{article} \usepackage{amsmath} \usepackage{hyperref} \title{Fractions worksheet} \author{Karl Kronecker} \begin{document} \maketitle \section{Exercises} \begin{enumerate} {% for e in exercises %} \item\label{ {{e.id}} } {{e.text}} {% endfor %} \end{enumerate} \newpage \section{Solutions} \begin{enumerate} {% for e in exercises %} \item[\ref{ {{e.id}} }.] {{e.solution}} {% endfor %} \end{enumerate} \end{document} Here the ``exercises`` variable contains all the evaluations of the exercises. In our case, there is only one exercise for now. This template is very simple: it lists all exercises in the first page using ``enumerate`` environment. And it lists their solution in the second page. Karl intends to replace it with a more complex and improved one in the future. Running the terminal user interface =================================== With all of this, Karl runs the terminal user interface (also known as TUI), called :download:`wk.py <../src/wk.py>`: :: python wk.py mytemplate.tex tutorial-exercise.md > tutorial-sheet.tex which generates the LaTeX document :download:`tutorial-sheet.tex <../src/examples/tutorial-sheet.tex>`: :: $ cat src/tutorial-sheet.tex \documentclass{article} \usepackage{amsmath} \title{Fractions worksheet} \author{Karl Kronecker} \begin{document} \maketitle \section{Exercises} \begin{enumerate} \item\label{ 31cbc9a1428197e954f092692d3a6f29becbb607c683a855967c837726224692 } Calculate the sum of $\frac{ 19 }{ 65 } + \frac{ 8 }{ 67 }$ \end{enumerate} \newpage \section{Solutions} \begin{enumerate} \item[\ref{ 31cbc9a1428197e954f092692d3a6f29becbb607c683a855967c837726224692 }.] The solution is $\frac{ 1793 }{ 4355 }$. \end{enumerate} \end{document} Karl finally compiles ``tutorial-sheet.tex`` using ``pdflatex`` and he obtains the desired :download:`PDF file <../src/examples/tutorial-sheet.pdf>`. Adding more exercises ====================== Creating a worksheet with only one exercise is very poor. Worksheet usually have more! Therefore Karl adds more exercises to his worksheet. He simply repeats as many he wants ``tutorial-exercise.md`` in the invocation of ``wk.py`` in comand line: :: python wk.py mytemplate.tex tutorial-exercise.md tutorial-exercise.md tutorial-exercise.md tutorial-exercise.md > tutorial-sheet.tex Thus, repating the previous steps, Karl has a :download:`worksheet of 4 exercises <../src/examples/tutorial-sheet-with-four.tex>` and some :download:`promising PDF file <../src/examples/tutorial-sheet-with-four.pdf>` of what he desired at the beginning: :: pdflatex tutorial-sheet.tex # it generates tutorial-sheet.pdf Using extra variables ====================== Karl wants to make the template more abstract in order to use it in a more wide range of situations. In the first place, he decides to pass the title as an extra parameter. Thus, he :download:`modifies the template <../src/examples/mytemplate-v2.tex>`. :: \usepackage{hyperref} {% if title %} \title{ {{title}} } {% else %} \title{Worksheet} {% endif %} It allows to specify the title of the worksheet and if it is not specified, it is set to "Worksheet". The way to specify the title is using ``--metadata`` parameter: :: python wk.py mytemplate-v2.tex tutorial-exercise.md tutorial-exercise.md tutorial-exercise.md tutorial-exercise.md --metadata title="Fractions Worksheet (version 2)" > tutorial-sheet.tex pdflatex tutorial-sheet.tex # it generates tutorial-sheet.pdf But Karl thinks it is convenient to put the ``version`` of the document. However, it needs that it were an integer, not string, for example to see the ``revision`` of the document (which equals to :math:`version -1`). For that, he uses ``--evals`` shell parameter, specifying it: :: python wk.py mytemplate-v3.tex tutorial-exercise.md tutorial-exercise.md tutorial-exercise.md tutorial-exercise.md --metadata title="Fractions Worksheet" version="3" --evals version > tutorial-sheet.tex pdflatex tutorial-sheet.tex # it generates tutorial-sheet.pdf He modifies the :download:`template <../src/examples/mytemplate-v3.tex>` in order to incorporate that change: :: [...] {% if title %} {% if version %} \title{ {{title}} (version {{version}}) } {% else %} \title{ {{title}} } {% endif %} {% else %} \title{Worksheet} {% endif %} [...] {% if version %} This document has been revised {{version -1}} times. {% endif %} He obtains :download:`what he wants <../src/examples/tutorial-sheet-version3.pdf>`. Multiplicity ============= It is tedious to repeat the name of an exercise in command line to obtain a repeated exercise in the worksheet. For this reason, Karl uses ``--multiplicity`` argument. Then, the previous example is transformed to: :: python wk.py mytemplate-v3.tex tutorial-exercise.md --multiplicity 0:4 --metadata title="Fractions Worksheet" version="3" --evals version > tutorial-sheet.tex pdflatex tutorial-sheet.tex # it generates tutorial-sheet.pdf Note that the index of multiplicity begins at 0, not at 1. In this example, ``--multiplicity 0:4`` means that exercise at position 0 (``tutorial-exercise.md`` in this case) occurs 4 times. If Karl had two different exercises, he could specify their multiplicity also. For example: :: python wk.py mytemplate-v3.tex tutorial-exercise.md tutorial-exercise2.md --multiplicity 0:4 1:5 [...] which means that the first exercise ``tutorial-exercise.md`` is repeated 4 times and the second exercise ``tutorial-exercise2.md`` is repeated 5 times. Shortening the process ======================= Instead of using ``>`` in order to save result of ``wk.py`` in ``tutorial-sheet.tex``, Karl uses ``--outputfile`` option: :: python wk.py mytemplate-v3.tex tutorial-exercise.md --multiplicity 0:4 --metadata title="Fractions Worksheet" version="3" --evals version --outputfile tutorial-sheet.tex pdflatex tutorial-sheet.tex # it generates tutorial-sheet.pdf And, finally he uses ``--postprocess`` option to automatically run ``pdflatex`` just after save result to ``tutorial-sheet.tex`` file: :: python wk.py mytemplate-v3.tex tutorial-exercise.md --multiplicity 0:4 --metadata title="Fractions Worksheet" version="3" --evals version --outputfile tutorial-sheet.tex --postprocess pdflatex # it generates tutorial-sheet.pdf Karl, now, generates a reasonably good worksheet of fractions with just one line.