Jump to page: 1 2
Thread overview
automatic code examples in documentation
Oct 15, 2010
Gerrit Wichert
Oct 15, 2010
Lutger
Oct 15, 2010
Tomek Sowiński
Oct 16, 2010
Lutger
Oct 15, 2010
Tomek Sowiński
Oct 15, 2010
Tomek Sowiński
Oct 16, 2010
Tomek Sowiński
Oct 16, 2010
Jonathan M Davis
Oct 16, 2010
Austin Hastings
October 15, 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:

> >
> > 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.
> 
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?


Gerrit



October 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:
>
>> >
>> >  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.
>>
> 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 ...
[snip]

> 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
October 15, 2010
Andrei Alexandrescu wrote:

> 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:
>>
>>> >
>>> >  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.
>>>
>> 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 ...
> [snip]
> 
>> 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

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.




October 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 declaration

Well, 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
October 15, 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
October 15, 2010
On 10/15/10 18:00 CDT, Tomek Sowiński wrote:
> 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?

From a ddoc perspective this should be the same as:

/** The ultimate foo.

The test.
----
...
----
*/
void foo();


Andrei
October 15, 2010
Andrei Alexandrescu napisał:

>> 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?
> 
> From a ddoc perspective this should be the same as:
> 
> /** The ultimate foo.
> 
> The test.
> ----
> ...
> ----
> */
> void foo();

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?

-- 
Tomek
October 16, 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
October 16, 2010
On Friday, October 15, 2010 16:49:06 Tomek Sowiński wrote:
> Andrei Alexandrescu napisał:
> >> 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?
> > 
> > From a ddoc perspective this should be the same as:
> > 
> > /** The ultimate foo.
> > 
> > The test.
> > ----
> > ...
> > ----
> > */
> > void foo();
> 
> 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?

I'd actually consider that to be a bad idea.

1. We should be able to name unit tests independently of any function or functions that they're testing.

2. It should be fully possible to have more than one unit test for a single function or have one unit test for multiple functions and have names on those unittest blocks.

Only a small portion of unit test code necessarily makes sense as an example. So, while having syntax that indicates that a test goes with a particular function as its example is a good idea, remember that there are going to be plenty of other unittest blocks that are _not_ intended as examples. I'm not sure that we want to mix up named unit tests and unit tests which become 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 doesn't make much sense for examples. For an example, you'd need to be dealing with a concrete template instantiation, while a unittest block within a template type would be for all instantiations of that template. So, in that case, being able to indicate an owner would certainly be useful. But I'm loathe to do it in away that makes it harder to add proper unit test names. Maybe what we do is make it so that unit test names which match a function name within that module are associated with that function as its example and the test function is given the 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 named unit test func_example which was the example for func() and was put in its ddoc.

- Jonathan M Davis
October 16, 2010
Tomek Sowiński wrote:

> 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 declaration
> 
> Well, 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.

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.

> 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.
>

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); } )







« First   ‹ Prev
1 2