{"id":695,"date":"2017-03-08T13:18:34","date_gmt":"2017-03-08T13:18:34","guid":{"rendered":"http:\/\/dlang.org\/blog\/?p=695"},"modified":"2021-10-08T11:10:53","modified_gmt":"2021-10-08T11:10:53","slug":"editable-and-runnable-doc-examples-on-dlang-org","status":"publish","type":"post","link":"https:\/\/dlang.org\/blog\/2017\/03\/08\/editable-and-runnable-doc-examples-on-dlang-org\/","title":{"rendered":"Editable and Runnable Doc Examples on dlang.org"},"content":{"rendered":"<p><em><span style=\"font-weight: 400;\">Sebastian Wilzbach was a <\/span><a href=\"http:\/\/blog.mir.dlang.io\/random\/2016\/08\/19\/intro-to-random-sampling.html\"><span style=\"font-weight: 400;\">GSoC student<\/span><\/a><span style=\"font-weight: 400;\"> for the D Language Foundation in 2016 and has since become\u00a0a regular contributor to <a href=\"https:\/\/github.com\/dlang\/phobos\">Phobos<\/a>, D&#8217;s standard library,\u00a0<\/span><span style=\"font-weight: 400;\">and <a href=\"http:\/\/dlang.org\/\">dlang.org<\/a>.<\/span><\/em><\/p>\n<hr \/>\n<p>This article explains the steps that were needed to have editable and runnable examples in the documentation on <a href=\"http:\/\/dlang.org\/phobos\/index.html\">dlang.org<\/a>. First, let\u2019s begin with the building blocks.<\/p>\n<h3>Unit testing in D<\/h3>\n<p>One of D\u2019s coolest features is its <code>unittest<\/code> block, which allows the insertion of testable code anywhere in a program. It has become idiomatic for a function to be followed directly by its tests. For example, let\u2019s consider a simple function <code>add<\/code> which is accompanied by two tests:<\/p>\n<pre class=\"prettyprint lang-d\">auto add(int a, int b)\r\n{\r\n    return a + b;\r\n}\r\n\r\nunittest\r\n{\r\n    assert(2.add(2) == 4);\r\n    assert(3.add(4) == 7);\r\n}<\/pre>\n<p>By default, all <code>unittest<\/code> blocks will be ignored by the compiler. Specifying\u00a0<strong>-unittest<\/strong> on the compiler&#8217;s command line will cause the unit tests to be included in the compiled binary. Combined with <strong>-main<\/strong>, tests in D can be directly executed with:<\/p>\n<pre>rdmd -main -unittest add.d<\/pre>\n<p>If a <code>unittest<\/code> block is annotated with <a href=\"http:\/\/dlang.org\/spec\/ddoc.html\">embedded documentation<\/a>, a D documentation generator can also display the tests as examples in the generated documentation. The DMD compiler ships with a built-in documentation generator (<a href=\"http:\/\/dlang.org\/spec\/ddoc.html\">DDoc<\/a>), which can be run with the <strong>-D<\/strong> flag, so executing:<\/p>\n<pre>dmd -D -main add.d<\/pre>\n<p>would yield the documentation of the <code>add<\/code> function above with its tests displayed as examples, as demonstrated here:<\/p>\n<p><img loading=\"lazy\" class=\"aligncenter size-full wp-image-699\" src=\"http:\/\/dlang.org\/blog\/wp-content\/uploads\/2017\/03\/image00.png\" alt=\"\" width=\"223\" height=\"264\" \/><\/p>\n<p>Please note that the <a href=\"http:\/\/dlang.org\/phobos\">documentation on dlang.org<\/a> is generated with DDoc. However, in case you don\u2019t like DDoc, there are several <a href=\"https:\/\/wiki.dlang.org\/Documentation_Generators\">other options<\/a>.<\/p>\n<h3>Executing code on the web<\/h3>\n<p>Frequent readers of the D Blog might remember <a href=\"https:\/\/dlang.org\/blog\/2017\/01\/30\/project-highlight-dpaste\/\">Damian Ziemba\u2019s DPaste<\/a> &#8211; an online compiler for the D Programming language. In 2012, he <a href=\"https:\/\/github.com\/dlang\/dlang.org\/pull\/132\">made the examples on the front page<\/a> of D\u2019s website runnable via his service. Back in those old days, the website of the D Programming language looked like this:<\/p>\n<p><img loading=\"lazy\" class=\"aligncenter wp-image-700 size-large\" src=\"http:\/\/dlang.org\/blog\/wp-content\/uploads\/2017\/03\/image01-1024x378.png\" width=\"660\" height=\"244\" srcset=\"https:\/\/dlang.org\/blog\/wp-content\/uploads\/2017\/03\/image01-1024x378.png 1024w, https:\/\/dlang.org\/blog\/wp-content\/uploads\/2017\/03\/image01-300x111.png 300w, https:\/\/dlang.org\/blog\/wp-content\/uploads\/2017\/03\/image01-768x284.png 768w, https:\/\/dlang.org\/blog\/wp-content\/uploads\/2017\/03\/image01.png 1248w\" sizes=\"(max-width: 660px) 100vw, 660px\" \/><\/p>\n<p>As a matter of fact, until 2015, communication with DPaste <a href=\"https:\/\/github.com\/dlang\/dlang.org\/pull\/1112\">was done in XML<\/a>.<\/p>\n<h3>Putting things together<\/h3>\n<p>So D has a unit test system that allows placing executable unit tests next to the functions they test, the tests can also be rendered as examples in the generated documentation, and there exists a service, in the form of DPaste, that allows D code to be executed on the web. The only thing missing was to link them together to produce interactive documentation for a compiled language.<\/p>\n<p>There was one big caveat that needed to be addressed before that could happen. While D\u2019s test suite, which is run on <a href=\"http:\/\/auto-tester.puremagic.com\/\">ten different build machines<\/a>, ensures that <a href=\"https:\/\/dlang.org\/blog\/2017\/01\/20\/testing-in-the-d-standard-library\/\">all unit tests compile &amp; run without errors<\/a>, an extracted test might contain symbols that were imported at module scope and thus wouldn\u2019t be runnable on dlang.org. A <code>unittest<\/code> block can only be completely independent of the module in which it is declared if all of its symbols are imported locally in the test\u2019s scope. The solution was rather simple: <a href=\"https:\/\/github.com\/dlang\/tools\/blob\/master\/styles\/tests_extractor.d\">extract all tests from Phobos<\/a>, then compile and execute them separately to ensure that a user won\u2019t hit a \u201cmissing import\u201d error on dlang.org. Thanks to D\u2019s ultra-fast frontend, this step takes less than a minute on a typical machine in single-core build mode.<\/p>\n<p>Moreover, to prevent any regressions, this has been <a href=\"https:\/\/github.com\/dlang\/phobos\/blob\/master\/posix.mak#L545\">integrated into Phobos\u2019s test suite<\/a> and is run for every PR via <a href=\"https:\/\/circleci.com\/gh\/dlang\/phobos\">CircleCi<\/a>. As Phobos has <a href=\"http:\/\/codecov.io\/gh\/dlang\/phobos\">extensive coverage<\/a> with unit tests, we started this transition with a <a href=\"https:\/\/github.com\/dlang\/dlang.org\/blob\/master\/js\/run_examples.js#L49\">blacklist<\/a> and, <a href=\"https:\/\/github.com\/dlang\/phobos\/pull\/4966\">step-by-step<\/a>, removed modules for which all extracted tests compile. With continuous checking in place, we were certain that none of the exposed unit tests would throw any errors when executed in the documentation, so we could <a href=\"https:\/\/github.com\/dlang\/dlang.org\/pull\/1297\">do the flip<\/a> and replace the syntax-highlighted unit test examples with an interactive code editor.<\/p>\n<h3>Going one step further<\/h3>\n<p>With this setup in place, hitting the \u201cRun\u201d button would merely show the users \u201cAll tests passed\u201d. While that\u2019s always good feedback, it conveys less information than is usually desirable.<\/p>\n<p><a href=\"https:\/\/lodash.com\/docs\">Documentation<\/a> that supports runnable examples tends to send any output to <code>stdout<\/code>. This allows the reader to take the example and modify it as needed while still seeing useful output about the modifications. So, for example, instead of using assertions to validate the output of a function, which is idiomatic in D unit tests and examples:<\/p>\n<pre class=\"prettyprint lang-d\">assert(myFun() == 4);<\/pre>\n<p>Other documentation usually prints to <code>stdout<\/code> and shows the expected output in a comment. In D, that would look like this:<\/p>\n<pre class=\"prettyprint lang-d\">writeln(myFun()); \/\/ 4<\/pre>\n<p>I <a href=\"https:\/\/github.com\/dlang\/dlang.org\/pull\/1297\/files#diff-034369de775110cb179ed1e925b62a0fR10\">initially<\/a> tried to do such a transformation with regular expressions, but I was quickly <a href=\"http:\/\/forum.dlang.org\/post\/mxdwzkirgzutmbrlpzgb@forum.dlang.org\">bitten<\/a> by the complexity of a context-free language. So I made <a href=\"https:\/\/github.com\/dlang\/dlang.org\/pull\/1582\">another attempt<\/a> using Brian Schott\u2019s <a href=\"https:\/\/github.com\/Hackerpilot\/libdparse\">libdparse<\/a>, a library to parse and lex D source code. libdparse allows one to traverse the abstract syntax tree (AST) of a D source file. During the traversal of the AST, the transformation tool can rewrite all <strong>AssertExpressions<\/strong> into <code>writeln<\/code> calls, similar to the way other documentation displays examples. To speak in the\u00a0<a href=\"http:\/\/www.drdobbs.com\/architecture-and-design\/so-you-want-to-write-your-own-language\/240165488?pgno=2\">vocabulary<\/a> of compiler devs: we are <em>lowering<\/em> <strong>AssertExpressions<\/strong> into the more humanly digestible <code>writeln<\/code> calls!<\/p>\n<p>Once the AST has been traversed and modified, it needs to be transformed into source code again. This led to improvements in libdparse\u2019s formatting capabilities (<a href=\"https:\/\/github.com\/Hackerpilot\/libdparse\/pull\/128\">1<\/a>, <a href=\"https:\/\/github.com\/Hackerpilot\/libdparse\/pull\/130\">2<\/a>).<\/p>\n<h3>The future<\/h3>\n<p>As of now, there are still a small number of functions in Phobos that don\u2019t have a nice public example that is runnable on dlang.org. <a href=\"https:\/\/github.com\/dlang\/tools\/blob\/master\/styles\/has_public_example.d\">Tooling<\/a> to check for this has recently been <a href=\"https:\/\/github.com\/dlang\/phobos\/pull\/4998\">activated in Phobos<\/a>. So now you can use this tool (<strong>make -f posix.mak has_public_example<\/strong>) to find functions lacking public tests and remove those modules from the <a href=\"https:\/\/github.com\/dlang\/phobos\/blob\/master\/posix.mak#L554\">blacklist<\/a>.<\/p>\n<p>Another target for improvement is DPaste. For example, it currently doesn\u2019t cache incoming requests, which could improve the performance of executed examples on dlang.org. However, due to the fast compilation speed of the DMD compiler, this \u201cslow-down\u201d isn\u2019t noticeable and is more of a perfectionist wish.<\/p>\n<p>I hope you enjoy the new \u201cRun\u201d button on the documentation and have as much fun playing with it as I do. <a href=\"https:\/\/dlang.org\/phobos\/std_algorithm_searching.html#.minElement\">Click here<\/a> to get started.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sebastian Wilzbach was a GSoC student for the D Language Foundation in 2016 and has since become\u00a0a regular contributor to Phobos, D&#8217;s standard library,\u00a0and dlang.org. This article explains the steps that were needed to have editable and runnable examples in the documentation on dlang.org. First, let\u2019s begin with the building blocks. Unit testing in D [&hellip;]<\/p>\n","protected":false},"author":16,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[12,9,20],"tags":[],"_links":{"self":[{"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/posts\/695"}],"collection":[{"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/comments?post=695"}],"version-history":[{"count":5,"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/posts\/695\/revisions"}],"predecessor-version":[{"id":702,"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/posts\/695\/revisions\/702"}],"wp:attachment":[{"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/media?parent=695"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/categories?post=695"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/tags?post=695"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}