When you’re writing documentation, it’s a good idea to use tools to keep code examples accurate. We’ve started to adopt tut, and that’s what this post is about.
What is tut?
The key feature is this: any unexpected error interpreting your code will cause the tut sbt command to fail. In other words, your code has to compile and run in order for your documentation to pass the build step.
You can see examples of tut output in the doobie documentation.
Writing with tut
tut interprets fenced code blocks. I know them from Github, and they look like this:
```scala val x = 1 + 2 ```
Github, and other sites, will render that markdown with Scala syntax highlighting:
val x = 1 + 2
Where tut fits in is adding new commands.
In place of
scala we write
```tut val x = 1 + 2 ```
The result will be another markdown file. tut replaces the code blocks with the interpreted output, itself in a code block:
```scala scala> val x = 1 + 2 x: Int = 3 ```
And that markdown you can render however you want.
There are a variety of modifiers to control the tut output.
We’ve contributed a
tut:book style for our documentation:
```tut:book val x = 1 + 2 ```
We want to show the REPL output, but that can get in the way when copying and pasting. So we comment all the REPL output:
val x = 1 + 2 // x: Int = 3
You can add tut to your project as an sbt plugin:
$ cat project/plugins.sbt addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.0")
You can configure what files to process and where to write processed markdown:
$ cat build.sbt scalaVersion := "2.11.7" tutSettings // Maybe I want output to go here: tutTargetDirectory := file(".")
The plugin adds the command
tut to process all files, with each file getting a separate REPL.
There are other modifiers and commands outlined in the project README.
Sometimes you’ll want to show an error, and tut supports that via the
For example, we demand the following will fail:
```tut:fail // An example of a compiler error message: List(1,2,3).sort ```
This produces the following rendered markdown:
scala> // An example of a compiler error message: | List(1,2,3).sort <console>:13: error: value sort is not a member of List[Int] List(1,2,3).sort ^
…but our build will succeed. If that block unexpectedly succeeded, our build would fail.
You can also add hidden checks. Maybe you want to ensure the results you’re showing are the results you’re expecting:
```tut:invisible assert(x == 3) ```
tut:invisible produces no output.
However, if it turned out
x wasn’t 3, the build would fail.
tut helps produce good quality, correct, documentation. We’re adopting it for our books.
There are plenty of other tools that can do similar things. Dexy is another good one to look at.
But tut happens to fit well with the workflow we use. Maybe it’ll work well for you.
Once you’ve tried it out, if you want to get more involved, join the tut gitter channel.