Your docs are a program

Zainab Ali

https://kebab-ca.se/presentations.html

catphoto

Questions

  • How do I get started?

  • Why should I store cat photos?

  • How do I get my photo?

  • What should I pass to the addPhoto function?

Types of docs

  • Tutorial: Getting started

  • Conceptual guide: Motivation and model

  • How-to: Task focused

  • Reference: Code focused

Doc Tools

Why

  • Functional programmer

  • Scala ambassador

  • Educator

Docs are artifacts

Reference docs

catphoto.scala

/** Gets the url of a random photo of a given cat.
  *
  * {{{
  * >>> val album = Album()
  * >>> val nextAlbum = album.addPhoto("Mao", "mao.png")
  *
  * >>> nextAlbum.getPhoto("Mao")
  * mao.png
  * }}}
  * @name The name of the cat
  */
def getPhoto(name: String): String = ???

Reference docs

Doctest

catphoto.scala

/** Gets the url of a random photo of a given cat.
  *
  * {{{
  * >>> val album = Album()
  * >>> val nextAlbum = album.addPhoto("Mao", "mao.png")
  *
  * >>> nextAlbum.getPhoto("Mao")
  * mao.png
  *
  * }}}
  */
def getPhoto(name: String): String = ...
sbt> test
+ CatPhoto.DocTest
[success]

Doctest

catphoto.scala

/** Gets the url of a random photo of a given cat.
  *
  * {{{
  * >>> val album = Album()
  * >>> val nextAlbum = album.addPhoto("Mao", "mao.png")
  *
  * >>> nextAlbum.getPhoto("Mao")
  * mao.png
  *
  * }}}
  */
def getPhoto(name: String): Option[String] = ...
sbt> test
- CatPhoto.DocTest
[error] Failed tests

Doctest

catphoto.scala

/** Gets the url of a random photo of a given cat.
  *
  * {{{
  * >>> val album = Album()
  * >>> val nextAlbum = album.addPhoto("Mao", "mao.png")
  *
  * >>> nextAlbum.getPhoto("Mao")
  * Some("mao.png")
  *
  * }}}
  */
def getPhoto(name: String): Option[String] = ???
sbt> test
+ CatPhoto.DocTest
[success]

Guides

getting-started.md

# Getting started

Create a photo album.
```scala
val album = Album()
```

Add a photo for a cat named `Mao`.
```scala
val nextAlbum = album.addPhoto("Mao", "mao.png")
```

mdoc

getting-started.md

# Getting started

Create a photo album.
```scala mdoc
val album = Album()
```

Add a photo for a cat named `Mao`.
```scala mdoc
val nextAlbum = album.addPhoto("Mao", "mao.png")
```
> mdoc --in getting-started.md
error: getting-started.md:6:13:
Not found: Album - did you mean album?
val album = Album()
            ^^^^^

getting-started.md

# Getting started

Import `catphoto.Album`.
```scala mdoc
import catphoto.Album
```
> mdoc --in getting-started.md
[success]

out/getting-started.md

# Getting started

Import `catphoto.Album`
```scala
import catphoto.Album
```
Create a photo album.

```scala
val album = Album()
// album: Album = Album()
```

getting-started.md

# Getting started

This guide is for @@VERSION@@.
> mdoc --site.VERSION="0.1.42" --in getting-started.md

out/getting-started.md

# Getting started

This guide is for 0.1.42.

CatPhotoModifier.scala

class CatPhotoModifier extends PostModifier {
  val name = "catphoto"
  def process(ctx: PostModifierContext): String = {
    ctx.lastValue match {
      case Some(url) =>
        s"""```scala
           |${ctx.outputCode}
           |```
           |![A cat photo]($url)"""
      case _ => ""
    }
  }
}

getting-started.md

Get a random photo for Mao.

```scala mdoc:catphoto
nextAlbum.getPhoto("Mao")
```

out/getting-started.md

Get a random photo for Mao.

```scala
nextAlbum.getPhoto("Mao")
// mao.png
```

![A cat photo](mao.png)

Docs are artifacts

  • Compile, test and validate

  • Integrate into CI pipelines

  • Variable substitution

  • Manipulate output

Docs are trees

# Getting started

Import `catphoto.Album`
<html>
<h1>Getting started</h1>
<p>
  Import
  <span>catphoto.Album</span>
</p>
</html>

Docs are code

getting-started.md

# Getting started

This guide is for @@VERSION@@.

Import `catphoto.Album`.

```scala mdoc
import catphoto.Album
```
...

Add a photo for a cat named `Mao`.
```scala mdoc
val nextAlbum = album.addPhoto("Mao", "mao.png")
```

thank-you.md

# Thank you!
The following cats need lots of treats:

 - Mao
 - Popcorn

Bugs

getting-started.md

Add a photo for Cinder.
<html>
<h1>Getting started</h1>
<p>
  Import
  <span>catphoto.Album</span>
</p>
</html>
(html
(h1 Getting started  h1)
(p
  Import
  (span catphoto.Album  span)
  p)
  html)
(html
(h1 Getting started    )
(p
  Import
  (span catphoto.Album      )
   )
     )

Racket

cats.rkt

#lang racket

(define myCat "Mao")

(define myCats '("Mao" "Popcorn"))

(define (stroke name) (string-append "Stroking " name))
> racket
λ>
λ> (require "cats.rkt")
λ> myCat
"Mao"
λ> (stroke myCat)
"Stroking Mao"

A language to write languages

thank-you.html.pmd

#lang pollen

# Thank you!
The following cats need lots of treats:

 - Mao
 - Popcorn
> racket
λ> (require "thank-you.html.pmd")
λ> doc
'(root
  (h1 ((id "thank-you")) "Thank you!")
  (p "The following cats need lots of treats:")
  (ul (li "Mao") (li "Popcorn")))

catname.rkt

#lang racket

(require "thank-you.html.pmd")

;; Get the cats from the doc
(define cats (select* 'li doc))

;; catname is a function
(define (catname name)
   (if (member name cats)
       name
       (error "A cat wasn’t thanked!" name)))

getting-started.html.pmd

#lang pollen

(require "catname.rkt")

Add a photo for (catname "Cinder").
λ> (require "getting-started.html.pmd")
A cat wasn't thanked! "Cinder"

Docs are programs

Using the browser

  • Docs are artifacts

  • Docs are trees

  • Docs are code

  • Docs are programs

Where next?

Find me

Thank you!

Questions?