This project demonstrates how to use literate programming inside of Emacs. Using this README.org as the source, you can generate markdown documentation as well as source code. This strategy has several advantages.
- It keeps documentation and source code always in sync. Source code is never edited separately from the documentation. They are tightly coupled.
- It allows you to present your code in a way that better suits human understanding. Source can be rearranged when it is generated to accommodate a compiler or interpreter.
- It allows you to take advantage of all the other features of org-mode that naturally enhance your documentation (embedding diagrams, running code snippets inline, embedding TODO items, time-tracking, and much more)
- Since Org-mode is very easy to customize, it allows you to further specialize your personal workflow.
- Is allows you to reuse code and reduce code duplication in ways that can be difficult directly in source code.
This document demonstrates many of these benefits and is hopefully a useful starting point for your own literate programming projects.
When Donald Knuth presented literate programming in 1984, he described two fundamental transformations that can be applied to a literate source document, a tangle and a weave. A tangle generates source code documents in the format appropriate for a compiler or interpreter. A weave produces well formatted documentation with embedded code snippets.
A literate source document, therefore, contains all the source and documentation necessary for these two transformations. For this document, Donald Knuth uses a hybrid of latex and source code. As you would expect, his exported documents are beautifully typeset.
I opted for a little less intensive solution (one day I’ll learn latex) that uses org-mode for my literate source document. Org-mode is well suited to this because it allows prose and code snippets to naturally co-exist. Most importantly, it already has built-in support for basic weaving and tangling.
Below is a diagram illustrating my basic approach. From your README.org file, you “tangle” all your source code, and “weave” your documentation. When I collaborate with people not using Emacs, I typically commit my markdown file and source code, versioning my org file separately in a system of my own–and no one’s the wiser ;)
digraph G {
A -> B [label="tangle"];
A -> C [label="weave"];
A [label="README.org"];
B [label="source code"];
C [label="README.md"];
}To tangle the current file (in other words, to generate the source code), run the following elisp command:
(org-babel-tangle)The keyboard shortcut for this command is C-c C-v t. To tangle only
the file where the cursor is located use the prefix command C-u. So
the full command would be C-u C-c C-v t.
To tangle a file into another buffer and not to a file on disk, run
C-c C-v C-v with your cursor on the section you would like to
tangle. This is a handy way to check how your file will be arranged.
To weave the current file (in other words, to generate documentation), run the following command:
(org-gfm-export-to-markdown)To install golang follow these instructions for your operating system.d
https://golang.org/doc/install
The following command will build your project and deposit a executable file called demo in the current directory.
go buildTo run a built project, execute the following. After following the steps outlined in “Build Instructions” above:
./demoTo run tests for this project:
go testThe go vet command can report additional potential problems that the
compiler will not catch:
go vetFor more information and options refer to the go documentation.
The go fmt will format your source code in a standard way. It is
like a linter that actually corrects the problems it finds automatically.
go fmt .Add a snippet file, to make adding literate programming files easier.
file:~/.emacs.d/snippets/org-mode/lit-file
# -*- mode: snippet -*-
# name: add literate file
# key: lit-file
# --
file:$1
#+begin_src $2 :tangle $1 :noweb no-export
$0
#+end_srcAfter tangling the above file, run the following to make it available:
(yas-reload-all)Add a snippet file, to make adding literate programming sections easier.
file:~/.emacs.d/snippets/org-mode/lit-sec
# -*- mode: snippet -*-
# name: add literate section
# key: lit-sec
# --
$1+=
#+begin_src $2 :noweb no-export :noweb-ref $1
$0
#+end_srcAfter tangling the above file, run the following to make it available:
(yas-reload-all)Below is the framework for the main file
file:main.go.m4
package main
import (
<<imports>>
)
<<functions>>
func main() {
<<main>>
}In main, we say hello and then give you a random number
main+=
SayHello()
GiveRandomNumber()Say Hello needs to import fmt to be able to print to stdout.
imports+=
"fmt"SayHello, says hello to you.
functions+=
func SayHello() {
__("SayHello()")
}Go provides a library for random numbers.
imports+=
"math/rand"
"time"Print a non-negative number from 0-n
functions+=
func GiveRandomNumber() {
rand.Seed(time.Now().UnixNano())
__(rand.Intn(100))
}Tangle is effectively a light-weight preprocessor. But, sometimes it is nice to use a macro language that is a little more powerful than the tangling features available in org-mode. In that case, it is simple to use a preprocessor like m4 in concert with the regular literate programming features demonstrated above. If you find yourself wanting to pass an argument to a noweb section, this is what you can do instead.
Run the following to execute m4 on your source file using the m4 macro file defined below:
m4 macros.m4 main.go.m4 > main.goDefine a macro that allows you to replace fmt.Printf with a simple
symbol __ that is illegal in golang itself. This is not a very
useful macro in and of itself, but demonstrates the ability to do even
more advanced preprocessing than tangle provides, when needed.
file:macros.m4
define(`__', `fmt.Println($1, time.Now().String())')