Literate Scala

April 23, 2016

Codedown is a little utility inspired by literate Haskell to extract code blocks of any given language from Markdown files. Essentially, all it does is look for code blocks marked as scala:

val x = 6
val y = 7
val z = x * y
println(z)

filters out the rest, and spits out the remaining code:

$ curl https://earldouglas.com/scala/literate.md |
  codedown scala
val x = 6
val y = 7
val z = x * y
println(z)

This output can be piped through scala to evaluate it:

$ curl https://earldouglas.com/scala/literate.md |
  codedown scala | scala
Welcome to Scala version 2.11.7 (OpenJDK Server VM, Java 1.8.0_76).
Type in expressions to have them evaluated.
Type :help for more information.

scala> val x = 6
x: Int = 6

scala> val y = 7
y: Int = 7

scala> val z = x * y
z: Int = 42

scala> println(z)
42

We can clean this up by passing it to Scala as a string to be evaluated:

$ curl https://earldouglas.com/scala/literate.md |
  codedown scala | xargs -0 scala -nc -e
42

This string of commands is getting rather unweildy, so let's make a reusable function out of it:

$ scodedown() {
  curl -L "$1" | codedown scala | xargs -0 scala "${@:2}" -e;
}

Now we can use scodedown to download, interpret, and run a literate Scala file:

$ scodedown https://earldouglas.com/literate-scala.md
42

A literate Scala file can't be run on its own if the code depends on external libraries.

For example, consider the code in JDBC database access in Scala. It uses an H2 database, so it can't work without access to the com.h2database:h2 library.

We need to grab the dependency and tell scala about it using -cp:

$ wget https://jcenter.bintray.com/com/h2database/h2/1.4.178/h2-1.4.178.jar
$ scodedown https://earldouglas.com/scala-jdbc.md -cp h2-1.4.178.jar
Books: List(Book(Surely You're Joking, Mr. Feynman!))

Manual dependency resolution isn't always practical. We can let Maven do it for us.

$ mvn org.apache.maven.plugins:maven-dependency-plugin:2.1:get \
  -DrepoUrl=url -Dartifact=com.h2database:h2:1.4.178
$ scodedown https://earldouglas.com/scala-jdbc.md \
  -cp ~/.m2/repository/com/h2database/h2/1.4.178/h2-1.4.178.jar
Books: List(Book(Surely You're Joking, Mr. Feynman!))

Using Maven and dealing with its local artifact repository isn't always practical either. We can instead let sbt handle dependency resolution for us.

In a normal sbt project, we would simply import this library in build.sbt:

libraryDependencies += "com.h2database" % "h2" % "1.4.178"

To get this working with codedown, we use sbt's script runner:

$ curl https://earldouglas.com/scala/jdbc.md |
  codedown scala > scala-jdbc.scala
$ sbt -Dsbt.main.class=sbt.ScriptMain scala-jdbc.scala
Books: List(Book(Surely You're Joking, Mr. Feynman!))