tut

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?

tut is a Typelevel project for documentation. It does one thing, and it does it well: it reads markdown and runs code blocks through the REPL.

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:

```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.

More Styles

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

Running tut

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.

Errors

Sometimes you’ll want to show an error, and tut supports that via the tut:fail modifier.

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.

Assertions

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.

Summary

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.


Like what you're reading?

Join our newsletter


Comments

We encourage discussion of our blog posts on our Gitter channel. Please review our Community Guidelines before posting there. We encourage discussion in good faith, but do not allow combative, exclusionary, or harassing behaviour. If you have any questions, contact us!