Working with a literate programming tool

Many Literate Programming (LP) tools are available. The essential ingredient, which varies from tool to tool, is the high-level markup language that separates the explanation from the code.

The source files that we write will contain the following three things:

  • Text with markup that constitutes the explanation and the description
  • Working Code in Python
  • High-level markup to separate the text (with markup) from the code

Because of the flexibility of XML, this can be used as the high-level markup for literate programming. It's not easy to write, however. There are tools that work with a LaTeX-like markup based on the original web (and later CWeb) tools. There are some tools that work with RST as the high-level markup.

The essential step in choosing a tool, then, is to take a look at the high-level markup that is used. If we find that the markup is easy to write, we can comfortably use it to produce the source document.

Python presents an interesting challenge. Because we have RST-based tools such as Sphinx, we can have very literate docstrings. This leads us to two tiers of documentation:

  • Explanations and background. This is outside the code. It provides supporting information on the design decisions that helped to organize the code.
  • Reference and API. This is inside the Python docstrings.

This leads to a pleasant, evolutionary approach to literate programming:

  • Initially, we can start by embedding the RST markup in our docstrings. A Sphinx-produced document looks good and provides a tidy explanation for the implementation choices.
  • We can step beyond the docstrings to create the background documentation. This might include information on the design decisions, architecture, requirements, and user stories. In particular, descriptions of non-functional quality requirements belong outside the code.
  • Once we've started to formalize this higher-level design documentation, we can more easily pick an LP tool. This tool will then dictate how we combine the documentation and code into a single, overall documentation structure. We can use an LP tool to extract the code and produce the documentation. Some LP tools can be used to run the test suite too.

Our goal is to create software that is not only well designed, but also trustworthy. As noted previously, we create trust in a number of ways, including providing a tidy, clear explanation of why our design is good.

We'll show some examples using PyLit3. For more information, see https://pypi.org/project/pylit3/3.1.1/.  The conversion from RST to HTML can be done with Python's docutils package, specifically, the rst2html.py script. The math typesetting can be handled through MathJax or one of the TeX tools. Refer to https://www.mathjax.org or  https://www.tug.org/texlive/

If we use a tool such as PyLit3, we might create RST files that look like the following code:

 
############# 
Combinations 
############# 
 
..  contents:: 
 
Definition 
========== 
 
For some deeper statistical calculations, 
we need the number of combinations of *n* things 
taken *k* at a time, :math:`inom{n}{k}`. 
 
..  math:: 
 
    inom{n}{k} = dfrac{n!}{k!(n-k)!} 
 
The function will use an internal ``fact()`` function because 
we don't need factorial anywhere else in the application. 
 
We'll rely on a simplistic factorial function without memoization. 
 
Test Case 
========= 
 
Here are two simple unit tests for this function provided 
as doctest examples. 
 
>>> from combo import combinations 
>>> combinations(4,2) 
6 
>>> combinations(8,4) 
70 
 
Implementation 
=============== 
 
Here's the essential function definition, with docstring: 
:: 
 
  def combinations(n: int, k: int) -> int: 
      """Compute :math:`inom{n}{k}`, the number of 
      combinations of *n* things taken *k* at a time. 
 
      :param n: integer size of population 
      :param k: groups within the population 
      :returns: :math:`inom{n}{k}` 
      """ 
 
An important consideration here is that someone hasn't confused 
the two argument values. 
:: 
 
      assert k <= n 
 
Here's the embedded factorial function. It's recursive. The Python 
stack limit is a limitation on the size of numbers we can use. 
:: 
 
      def fact(a: int) -> int: 
          if a == 0: return 1 
          return a*fact(a-1) 
 
Here's the final calculation. Note that we're using integer division. 
Otherwise, we'd get an unexpected conversion to float. 
:: 
 
      return fact(n)//(fact(k)*fact(n-k)) 
 

This is a file written entirely in an RST markup. It contains some explanatory text, some formal math, and even some test cases. These provide us with additional details to support the relevant code sections. Because of the way PyLit works, we named the file combo.py.txt. There are three things we can do with this file:

  • We can use PyLit3 to extract the code from this text file in the following manner:
python3 -m pylit combo.py.txt 

This creates combo.py from combo.py.txt. This is a Python module that is ready to be used.

  • We can also use docutils to format this RST into an HTML page that provides the documentation and code in a form that we can read more easily than the original single-font text:
rst2html.py combo.py.txt combo.py.html 

This creates combo.py.html ready for browsing. The mathjax package will be used by docutils to typeset the mathematical portions, leading to very nice-looking output.

  • We can, additionally, use PyLit to run doctest and confirm that this program really works:
python3 -m pylit --doctest combo.py.txt 

This will extract the doctest blocks from the code and run them through the doctest tool. We'll see that the three tests (the import and the two function evaluations) all produce the expected results.

The final web page produced by this would look something like the following screenshot:

The HTML details are handled seamlessly by the RST to HTML tool, letting us focus on simple markup and correct software.

Our goal is to create software that is trustworthy. A tidy, clear explanation of why our design is good is an important part of this trust. By writing the software and the documentation side-by-side in a single source text, we can be sure that our documentation is complete and provides a sensible review of the design decisions and the overall quality of the software. A simple tool can extract working code and documentation from a single source, making it easy for us to create the software and the documentation.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset