Moldable Emacs: examples for docs, demos and ERT tests!
Too long; didn't read
Add examples of usage to the software. You can make examples into (automated) tests, documentation and even demos/previews.
The problem
The person behind the GitHub user ikappaki gave me a wonderful gift: they enabled CI for moldable-emacs. I am grateful for that kindness. I find Continous Integration vital for projects. My moldable-emacs started as a prototype to see how many moldable ideas could fit in Emacs. Learning how to setup CI for a (possibly-failing) prototype was a bit out of scope at the time. At this point, though, it is very much needed! Now a change here causes an error there. Not good!
That's why ikappaki saved the day! We now have CI and we can test things with eldev and ERT, the Emacs' regression testing library.
We have few tests for now and... I hope it stays that way!
The core issue is how to test molds. I hope to check that molds are healthy without writing a test for each of them. Tests are code and need maintenance too (and I want to save my time)!
How to achieve that?
It is a problem indeed
This is a problem that I would like to solve in other places too. When I program, I have a problem. I think about how to solve it. I write a function. Then I write a test to avoid regressions (if I am TDDing, I write the test to describe the problem). And then? Then time passes and my completion framework shows me this function. But I don't remember how to use it! So I need to hope I added docs or a test at the time (assume the test passes) or worse read the function's code.
This seems a waste of time! If I have the test, I defined an example of usage there. Why cannot I make that part of the function itself? That way I could check if the function applies to the specific problem I have by seeing the use case it was written for. Even when you have static types, an example still helps!
AND with examples I could also test the function without writing a test! I would just need to write the example WITH the function.
This would also make my completion more helpful! I could see an example of usage (maybe even run it live) to pick the best fit while I am developing.
Can we try this approach in moldable-emacs?
And there is a solution
Even if I didn't setup CI, I gave this problem a thought from the start (lucky me)! It is just merit of the amazing GlamorousToolkit's community really: you can watch Tudor Girba explaining how the idea works in GT.
This is how a mold looks in Elisp.
(me-register-mold :key "Playground" :given (:fn 't) :then (:fn ...) :examples (( :name "Empty file" :given (:type file :name "/tmp/test.txt" :mode text-mode :contents "") :then (:type buffer :name "Playground" :mode emacs-lisp-mode :contents ";; Tips: ;; Use `self' to access the mold context. ;; You can access the previous mold context through `mold-data'. "))))
If you see a mold as a function (there is also a cool discussion
ongoing), then the :examples
bit is what I described earlier. That
is our example of usage!
The examples have 3 properties: a name, a given clause and a then
clause. That gives us enough information to show a demo to users. You
just have to call me-mold-docs
and choose "Playground" to see a
documentation buffer using the example. It shows the following text:
You can write any Elisp here. Then you can evaluate with `EvalSexp'. This mold saves structured data of the previous buffer in the local variable `self'. Given the "/tmp/test.txt" file with the following contents: ---------- ---------- The mold returns the "Playground" buffer with the following contents: ---------- ;; Tips: ;; Use `self' to access the mold context. ;; You can access the previous mold context through `mold-data'. ----------
If you use the mold "AllMolds" (thanks to alanz) or "WhatMoldsCanIuse?", you can even see the example as a demo of the mold.
So with examples we get both documentation and preview. I want to
experiment with showing the preview when you pick a mold to use with
me-mold
. That would cover the completion issue I mentioned before.
The properties of an example provide enough context for testing as
well. We could show a demo by setting buffers with name, contents and
mode as defined in the :given
clause. Now we can setup a test with
the same information. The demo only creates mock buffers. The test
should set the precondition (the example :given
) and then run the
mold starting from that. If the output is the same as the example
:then
clause, the test passes.
The code for that is a bit ugly at the moment, but it works! The following code is an example of a successful run.
(me-check-mold-examples (me-find-mold "Playground"))
While the following is an example of failure.
(me-check-mold-examples (me-find-mold "Evaluate Arithmetic Expression"))
By the way, the above shows that the infrastructure is a prototype.
Some molds expect to set the point in a certain position and I cannot
express that yet in the example's :given
clause.
Assuming I can come up with a better infra, I expect to add a single test to the ERT suite. It will go through all the molds with examples and run its examples as tests. This means that I will run tens of tests in a few lines of code! And even if you think that the examples are code themselves, well I can at least use them also for demos and documentation. 3 in 1: what a deal! Better than just tests.
Also, examples need to be easy to add, right? The way I do it in
moldable-emacs is to run a mold, and then call
me-insert-last-example
.
Note: this inserts the example wherever you are and it also misses the
:name
! For now, you should go to the :examples
section of the mold
and put your cursor in the first element of the list. And add a name.
I will make this even more user friendly soon (by asking the name and
inserting the example in the right place), but it already saves you
from adding :given
and :then
yourself!
This means that you can capture examples while you use molds! How cool is it when machines can do most of the work?!
(Caveat: it is still a work in progress, things will not work for molds that expect images or certain states of your machine -- like files to be present)
Conclusion
Make more out of examples! Look into how to make the examples in your tests more useful. And if you use moldable-emacs, add examples to your molds. If you do, you get free docs, demos and even tests!!!
Merry exampling!