digitalmars.D - automatic code examples in documentation
- Gerrit Wichert (44/49) Oct 15 2010 This is a post i made deep in the 'improving the join function' thread.
- Andrei Alexandrescu (16/43) Oct 15 2010 I'm happy with a much more modest change that doesn't add anything to
- Lutger (9/75) Oct 15 2010 for reference: http://d.puremagic.com/issues/show_bug.cgi?id=2630
- Tomek =?UTF-8?B?U293acWEc2tp?= (9/19) Oct 15 2010 Well, a unittest making a trial run of the preceding declaration is a co...
- Lutger (18/41) Oct 16 2010 That's why I suggested ditto. Any comments can be put as regular code
- Tomek =?UTF-8?B?U293acWEc2tp?= (9/24) Oct 15 2010 Let's drill down on this:
- Andrei Alexandrescu (10/32) Oct 15 2010 From a ddoc perspective this should be the same as:
- Tomek =?UTF-8?B?U293acWEc2tp?= (14/34) Oct 15 2010 I see. That means unittests summarizing the whole of module's goodies wo...
- Tomek =?UTF-8?B?U293acWEc2tp?= (11/23) Oct 15 2010 Nevermind. It's little better than:
- Jonathan M Davis (72/109) Oct 15 2010 he
- Austin Hastings (22/46) Oct 16 2010 [ ... ]
This is a post i made deep in the 'improving the join function' thread. Steven asked me to open a new thread on it, so here it comes. Am 13.10.2010 22:07, schrieb Andrei Alexandrescu:I think the best way to explain the usage of a feature are *working* code-examples. Maybe it's possible to have a special unit-test block named such as 'example'. The compiler can completely ignore such sections or just syntax check them, or ... . For doc generation they are just taken as they are and put into (or linked to) the documentation. It may be even possible for the doc generator to compile and run these samples, so they become some kind of unit test and their possible output can be part of the documentation. Just an idea that comes to my mind This was the original post, now some more explanation: How can the syntax look like ? ... library code documentation( code) { //hello world example code import std.stdio; void main() { writeln( "Hello, world!"); } } more library code ... This is how a simple example code section may look like. The documentation annotation tells the compiler not to generate any code from the section. The minimal thing it has to do is generate a string from the section content and forward it to the document-generator. This should be sufficient for easily getting code examples into the documentation. I think its a good idea if the compiler executes a syntax check on the example section, like it does on the already implemented syntax checked strings. Then the compiler part is done with this. This are code examples, not unit tests. They are not run with the other unit tests. I think code examples are most usefull if they are self-contained little programs. Part of the document generation may be to compile and run the extracted examples. When a example does't compile it can be marked as defunct or excluded from the documentation. The doc-generator can catch the output of the running examples and add it to the documentation as result. Shurely there are some problems when trying to compile the examples like wich libs to link with, or what about GUI-code, or just code snippets, but for me this is all secondary, maybe we can make that work later. The most important part is to define the transfer mechanics to get the example code into the documentation. So what do you think? GerritGood point. On the other hand, an overly simplified documentation might hinder a good deal of legit uses for advanced users. I wonder how to please everyone.
Oct 15 2010
On 10/15/2010 10:18 AM, Gerrit Wichert wrote:This is a post i made deep in the 'improving the join function' thread. Steven asked me to open a new thread on it, so here it comes. Am 13.10.2010 22:07, schrieb Andrei Alexandrescu:[snip]I think the best way to explain the usage of a feature are*working* code-examples. Maybe it's possible to have a special unit-test block named such as 'example'. The compiler can completely ignore such sections or just syntax check them, or ... . For doc generation they are just taken as they are and put into (or linked to) the documentation. It may be even possible for the doc generator to compile and run these samples, so they become some kind of unit test and their possible output can be part of the documentation. Just an idea that comes to my mind This was the original post, now some more explanation: How can the syntax look like ? ... library code documentation( code) { //hello world example code import std.stdio; void main() { writeln( "Hello, world!"); } } more library code ...Good point. On the other hand, an overly simplified documentation might hinder a good deal of legit uses for advanced users. I wonder how to please everyone.So what do you think?I'm happy with a much more modest change that doesn't add anything to the syntax. Simply prefixing a unittest with a documentation comment makes it an example: /** The example below illustrates how D gets a basic arithmetic operation totally right. */ unittest { assert(1 + 1 == 2); } The documentation generator simply plops the comment and then formats the code as an example code. Andrei
Oct 15 2010
Andrei Alexandrescu wrote:On 10/15/2010 10:18 AM, Gerrit Wichert wrote:for reference: http://d.puremagic.com/issues/show_bug.cgi?id=2630 Tomasz Sowiński raises the point that each unittest should test the preceding declaration. I think that's a little inflexible, instead the following could work: - unittests marked with 'ditto' will document the preceding declaration - unittest not marked with ditto will be put in a hardwired macro like BODY is, so that you have control where it gets put in the generated documentation.This is a post i made deep in the 'improving the join function' thread. Steven asked me to open a new thread on it, so here it comes. Am 13.10.2010 22:07, schrieb Andrei Alexandrescu:[snip]I think the best way to explain the usage of a feature are*working* code-examples. Maybe it's possible to have a special unit-test block named such as 'example'. The compiler can completely ignore such sections or just syntax check them, or ... . For doc generation they are just taken as they are and put into (or linked to) the documentation. It may be even possible for the doc generator to compile and run these samples, so they become some kind of unit test and their possible output can be part of the documentation. Just an idea that comes to my mind This was the original post, now some more explanation: How can the syntax look like ? ... library code documentation( code) { //hello world example code import std.stdio; void main() { writeln( "Hello, world!"); } } more library code ...Good point. On the other hand, an overly simplified documentation might hinder a good deal of legit uses for advanced users. I wonder how to please everyone.So what do you think?I'm happy with a much more modest change that doesn't add anything to the syntax. Simply prefixing a unittest with a documentation comment makes it an example: /** The example below illustrates how D gets a basic arithmetic operation totally right. */ unittest { assert(1 + 1 == 2); } The documentation generator simply plops the comment and then formats the code as an example code. Andrei
Oct 15 2010
Lutger napisał:for reference: http://d.puremagic.com/issues/show_bug.cgi?id=2630 Tomasz Sowiński raises the point that each unittest should test the preceding declaration. I think that's a little inflexible, instead the following could work: - unittests marked with 'ditto' will document the preceding declarationWell, a unittest making a trial run of the preceding declaration is a convention, natural and widely adopted. That well-trodden path deserves to be acknowledged by the doc generator. Good thing about this idea is that *nothing* changes, no extra gimmicks around unittest blocks, the code's natural flow is intact.- unittest not marked with ditto will be put in a hardwired macro like BODY is, so that you have control where it gets put in the generated documentation.Hm.. would the hardwired macro name be same for all unittests? If so, the notion of implicit ownership by the preceding declaration is necessary so that the names wouldn't mix up. -- Tomek
Oct 15 2010
Tomek Sowiński wrote:Lutger napisał:That's why I suggested ditto. Any comments can be put as regular code comments inside the unittest itself, that will be marked up nicely by ddoc.for reference: http://d.puremagic.com/issues/show_bug.cgi?id=2630 Tomasz Sowiński raises the point that each unittest should test the preceding declaration. I think that's a little inflexible, instead the following could work: - unittests marked with 'ditto' will document the preceding declarationWell, a unittest making a trial run of the preceding declaration is a convention, natural and widely adopted. That well-trodden path deserves to be acknowledged by the doc generator.Good thing about this idea is that *nothing* changes, no extra gimmicks around unittest blocks, the code's natural flow is intact.Not necessarily. It could just be a container. With this macro: DDOC_UNITTEST_MEMBERS = <h2>unittests</h2> $0 /** one plus one*/ unittest { assert(1+1==2); } /** one minus one */ unittest { assert(1-1==0); } the above could expand to something like: <h2>unittests</h2> $(DDOC_SUMMARY one plus one) $(D_CODE unittest { assert(1+1==2); } ) $(DDOC_SUMMARY one minus one) $(D_CODE unittest { assert(1-1==0); } )- unittest not marked with ditto will be put in a hardwired macro like BODY is, so that you have control where it gets put in the generated documentation.Hm.. would the hardwired macro name be same for all unittests? If so, the notion of implicit ownership by the preceding declaration is necessary so that the names wouldn't mix up.
Oct 16 2010
Andrei Alexandrescu napisał:I'm happy with a much more modest change that doesn't add anything to the syntax. Simply prefixing a unittest with a documentation comment makes it an example: /** The example below illustrates how D gets a basic arithmetic operation totally right. */ unittest { assert(1 + 1 == 2); } The documentation generator simply plops the comment and then formats the code as an example code.Let's drill down on this: /// The ultimate foo. void foo(); /// The test. unittest { ... } What would be the <dl><dt><dd> outline of the above snippet? -- Tomek
Oct 15 2010
On 10/15/10 18:00 CDT, Tomek Sowiński wrote:Andrei Alexandrescu napisał:From a ddoc perspective this should be the same as: /** The ultimate foo. The test. ---- ... ---- */ void foo(); AndreiI'm happy with a much more modest change that doesn't add anything to the syntax. Simply prefixing a unittest with a documentation comment makes it an example: /** The example below illustrates how D gets a basic arithmetic operation totally right. */ unittest { assert(1 + 1 == 2); } The documentation generator simply plops the comment and then formats the code as an example code.Let's drill down on this: /// The ultimate foo. void foo(); /// The test. unittest { ... } What would be the<dl><dt><dd> outline of the above snippet?
Oct 15 2010
Andrei Alexandrescu napisał:I see. That means unittests summarizing the whole of module's goodies would have to be at the top, but that's passable. Otherwise it's a superb idea. As I mentioned in bugzilla, it opens the opportunity to kill the unittest naming problem with the same stone: void foo(); unittest(owner) { Log.info("Testing " ~ owner.stringof ~ "..."); scope(exit) Log.info("Testing " ~ owner.stringof ~ " complete"); } The syntax takes after the out(result) contract. 'owner' is an alias to the preceding symbol. The overall ROI looks positive, eh? -- TomekLet's drill down on this: /// The ultimate foo. void foo(); /// The test. unittest { ... } What would be the<dl><dt><dd> outline of the above snippet?From a ddoc perspective this should be the same as: /** The ultimate foo. The test. ---- ... ---- */ void foo();
Oct 15 2010
Tomek Sowiński napisał:As I mentioned in bugzilla, it opens the opportunity to kill the unittest naming problem with the same stone: void foo(); unittest(owner) { Log.info("Testing " ~ owner.stringof ~ "..."); scope(exit) Log.info("Testing " ~ owner.stringof ~ " complete"); } The syntax takes after the out(result) contract. 'owner' is an alias to the preceding symbol. The overall ROI looks positive, eh?Nevermind. It's little better than: unittest { alias foo owner; Log.info("Testing " ~ owner.stringof ~ "..."); scope(exit) Log.info("Testing " ~ owner.stringof ~ " complete"); } There must be a way to make it all work elegantly with, say, an IDE's unittest runner, but I won't find it posting at 2:28 a.m. -- Tomek
Oct 15 2010
On Friday, October 15, 2010 16:49:06 Tomek Sowi=C5=84ski wrote:Andrei Alexandrescu napisa=C5=82:ld=20 I see. That means unittests summarizing the whole of module's goodies wou=Let's drill down on this: =20 /// The ultimate foo. void foo(); =20 /// The test. unittest { ... } =20 What would be the<dl><dt><dd> outline of the above snippet?=20 From a ddoc perspective this should be the same as: =20 /** The ultimate foo. =20 The test. ---- ... ---- */ void foo();have to be at the top, but that's passable. Otherwise it's a superb idea. =20 As I mentioned in bugzilla, it opens the opportunity to kill the unittest naming problem with the same stone: =20 void foo(); =20 unittest(owner) { Log.info("Testing " ~ owner.stringof ~ "..."); scope(exit) Log.info("Testing " ~ owner.stringof ~ " complete"); } =20 The syntax takes after the out(result) contract. 'owner' is an alias to t=hepreceding symbol. The overall ROI looks positive, eh?I'd actually consider that to be a bad idea. 1. We should be able to name unit tests independently of any function or=20 functions that they're testing. 2. It should be fully possible to have more than one unit test for a single= =20 function or have one unit test for multiple functions and have names on tho= se=20 unittest blocks. Only a small portion of unit test code necessarily makes sense as an exampl= e.=20 So, while having syntax that indicates that a test goes with a particular=20 function as its example is a good idea, remember that there are going to be= =20 plenty of other unittest blocks that are _not_ intended as examples. I'm no= t=20 sure that we want to mix up named unit tests and unit tests which become=20 examples in ddoc comments. I fully support the syntax of unittest(testname) { } but I don't like the idea of unittest(owner) { } I think that it would make far more sense to do it in another way, perhaps example unittest { } or to have an example unit test with a name example unittest(testname) { } Or we could simple use a ddoc marker on it as Andrei suggested: /// unittest(testname) { } The one issue is templates. Putting a unittest in a block in a template doe= sn't=20 make much sense for examples. For an example, you'd need to be dealing with= a=20 concrete template instantiation, while a unittest block within a template t= ype=20 would be for all instantiations of that template. So, in that case, being a= ble=20 to indicate an owner would certainly be useful. But I'm loathe to do it in = away=20 that makes it harder to add proper unit test names. Maybe what we do is mak= e it=20 so that unit test names which match a function name within that module are= =20 associated with that function as its example and the test function is given= the=20 same name as the function with _example tacked on or something similar. So, void func() {} unittest(mytest) { } unittest(func) { } would result in a named unit test mytest which was not an example, and a na= med=20 unit test func_example which was the example for func() and was put in its = ddoc. =2D Jonathan M Davis
Oct 15 2010
Interspersed On 10/15/2010 11:18 AM, Gerrit Wichert wrote:This is a post i made deep in the 'improving the join function' thread. Steven asked me to open a new thread on it, so here it comes.[ ... ]I think its a good idea if the compiler executes a syntax check on the example section, like it does on the already implemented syntax checked strings.The perl and parrot guys do this with POD. The pod syntax is simple enough that it is trivial to write code that extracts the examples and tries to compile them. I think development of this started because some readers complained about book examples not compiling. The obvious (in perl) solution was to filter out the examples and verify them as part of a full build.Then the compiler part is done with this. This are code examples, not unit tests. They are not run with the other unit tests. I think code examples are most usefull if they are self-contained little programs. Part of the document generation may be to compile and run the extracted examples. When a example does't compile it can be marked as defunct or excluded from the documentation. The doc-generator can catch the output of the running examples and add it to the documentation as result. Shurely there are some problems when trying to compile the examples like wich libs to link with, or what about GUI-code, or just code snippets, but for me this is all secondary, maybe we can make that work later. The most important part is to define the transfer mechanics to get the example code into the documentation. So what do you think?Doxygen already supports something like this. Quoting the manual: http://www.stack.nl/~dimitri/doxygen/commands.html#cmdexample\example <file-name> Indicates that a comment block contains documentation for a source code example. The name of the source file is <file-name>. The text of this file will be included in the documentation, just after the documentation contained in the comment block. All examples are placed in a list. The source code is scanned for documented members and classes. If any are found, the names are cross-referenced with the documentation.The usage example looks like: /** \example example_test.cpp * This is an example of how to use the Test class. * More details about the example. */ Using this approach would have the benefit of nicely solving the "how do I compile the examples" question, since the examples become stand-alone files with the "usual" compilation semantics. (Doxygen supports a search path for this kind of thing, so putting the files in an examples/ subdirectory is trivial.) =Austin
Oct 16 2010