This is a Unison transcript file. It's used for creating typechecked documentation, test cases, and scripts.
It's just a markdown file that does some special interpretation of certain fenced code blocks. It can be passed to ucm
as a command line argument. ucm
will run through the file change events and commands in the file in order and output a new .md
file with the responses to these inputs. It exits when it's done, so this can also be used for scripting.
---
filename: scratch.u
---
x = 1 + 1
The above will create the file scratch.u
with the given contents, parse and typecheck it, and insert the ucm
output into the resulting markdown, as a new fenced code block, immediately following the unison
fenced block. If you leave off the frontmatter with the filename, that's okay too, no file will be created. If the file doesn't parse or typecheck, ucm
exits with an error.
If you are instead expecting an error and want to show the resulting error message and continue, use unison:error
as the code fence:
x = 1 + "hi" -- thankfully does not typecheck
Another fenced code type is ucm
(ucm:error
if you are expecting an error):
.> view base.List.map
.> execute IO.putText "hello, world!!"
This will run the ucm
command and show its output in a new fenced code block immediately below. A ucm
fenced block can have multiple commands, in which case the output is inserted after each command.
You can elide the cd
/namespace
commands and just directly indicate the namespace with the prompt, for instance:
.foo> find
.bar> find
This will output the command sequence cd .foo
, find
, cd .bar
, find
.
Sounds good, now what about creating test cases? We provide a couple new commands:
assert.execute expr
exitsucm
with failure ifexecute expr
fails or evaluates to false.assert.test
exitsucm
with failure if thetest
command returns a failing statusassert.todo
exitsucm
with failure if thetodo
command returns anything to doassert.view foo
exitsucm
with failure ifview
command gives no results- ... can add to this as needed
.> assert true
.> assert.test
It might not be obvious how to use the above to construct test cases, so I thought I'd give a few examples. Suppose I'd like to check that fork
creates a copy of a namespace. To make the transcript pretty self-contained, I'll create a namespace with some definitions in it, then fork
that, cd
into it, and verify that viewing one of the definitions works.
ns0.x = 42
ns0.y = 19
.> add
.> fork ns0 ns1
.ns1> assert.view x
.ns1> assert.view y
In the absence of a full-blown codebase API accessible from Unison programs, there may be some creativity needed to arrange things so that the transcript fails in a way that indicates what you want. The above test is a bit weak, it would be nice if we could assert that the x
in the fork is the same as the x
in ns0
. How could we do that? Easy: just write a Unison test!
use .test
use .base
test> ns1.forkIsCopy1 = (.ns0.x == .ns1.x) |> expect |> run
test> ns1.forkIsCopy1 = (.ns0.y == .ns1.y) |> expect |> run
.> add
.> assert.test
Now we're actually testing that the values are as expected in the fork.
Seems reasonable.
Ideas?
I think that is not enforced right now, but it probably should be. So I guess just if the expression fails then.
Just don't include the filename in the front-matter of the markdown.
Yes, just do
pull
to start things out.I guess you could add a
push
at the end of the transcript. Or maybe a flag passed toucm
that drops you into the regular prompt once the transcript completes.Seems doable - you could just emit HTML blocks manually in the markdown. Maybe not for v1.
No. Only state is just the codebase state. All the
unison
fenced blocks are syntactically self-contained. You canadd
to make previous definitions available for later files. However, if needed maybe we could add some "stitched"unison
fenced block series, which is combined into a singleunison
fenced block. I guess I'd prefer to wait on that until it's clear we need it though.I'd probably just start the transcript with a
pull
of the codebase you want to depend on. Seems like a rabbit hole to have any more elaborate transcript dependency / build system than this.