Auto merge of #75778 - AndyGauge:75521-rustdoc-book-improvements, r=jyn514

75521 rustdoc book improvements

Added some guidelines about documenting with rustdoc
Fixes #75521
This commit is contained in:
bors 2020-11-06 19:01:10 +00:00
commit a601302ff0
6 changed files with 283 additions and 31 deletions

View File

@ -2,6 +2,7 @@
- [What is rustdoc?](what-is-rustdoc.md)
- [How to write documentation](how-to-write-documentation.md)
- [What to include (and exclude)](what-to-include.md)
- [Command-line arguments](command-line-arguments.md)
- [The `#[doc]` attribute](the-doc-attribute.md)
- [Documentation tests](documentation-tests.md)
@ -10,3 +11,4 @@
- [Passes](passes.md)
- [Advanced features](advanced-features.md)
- [Unstable features](unstable-features.md)
- [References](references.md)

View File

@ -1,14 +1,85 @@
# How to write documentation
Good documentation is not natural. There are opposing goals that make writing
good documentation difficult. It requires expertise in the subject but also
writing to a novice perspective. Documentation therefore often glazes over
implementation detail, or leaves readers with unanswered questions.
There are a few tenets to Rust documentation that can help guide anyone through
the process of documenting libraries so that everyone has an ample opportunity
to use the code.
This chapter covers not only how to write documentation but specifically
how to write **good** documentation. Something to keep in mind when
writing documentation is that your audience is not just yourself but others
who simply don't have the context you do. It is important to be as clear
how to write **good** documentation. It is important to be as clear
as you can, and as complete as possible. As a rule of thumb: the more
documentation you write for your crate the better. If an item is public
then it should be documented.
## Basic structure
## Getting Started
Documenting a crate should begin with front-page documentation. As an
example, the [`hashbrown`] crate level documentation summarizes the role of
the crate, provides links to explain technical details, and explains why you
would want to use the crate.
After introducing the crate, it is important that the front-page gives
an example of how to use the crate in a real world setting. Stick to the
library's role in the example, but do so without shortcuts to benefit users who
may copy and paste the example to get started.
[`futures`] uses inline comments to explain line by line
the complexities of using a [`Future`], because a person's first exposure to
rust's [`Future`] may be this example.
The [`backtrace`] documentation walks through the whole process, explaining
changes made to the `Cargo.toml` file, passing command line arguments to the
compiler, and shows a quick example of backtrace in the wild.
Finally, the front-page can eventually become a comprehensive reference
how to use a crate, like [`regex`]. In this front page, all
requirements are outlined, the edge cases shown, and practical examples
provided. The front page goes on to show how to use regular expressions
then concludes with crate features.
Don't worry about comparing your crate, which is just beginning, to other more
developed crates. To get the documentation to something more polished, start
incrementally and put in an introduction, example, and features. Rome was not
built in a day!
The first lines within the `lib.rs` will compose the front-page, and they
use a different convention than the rest of the rustdocs. Lines should
start with `//!` which indicate module-level or crate-level documentation.
Here's a quick example of the difference:
```rust,ignore
//! Fast and easy queue abstraction.
//!
//! Provides an abstraction over a queue. When the abstraction is used
//! there are these advantages:
//! - Fast
//! - [`Easy`]
//!
//! [`Easy`]: http://thatwaseasy.example.com
/// This module makes it easy.
pub mod easy {
/// Use the abstract function to do this specific thing.
pub fn abstract() {}
}
```
Ideally, this first line of documentation is a sentence without highly
technical details, but with a good description of where this crate fits
within the rust ecosystem. Users should know whether this crate meets their use
case after reading this line.
## Documenting components
Whether it is modules, structs, functions, or macros: the public
API of all code should have documentation. Rarely does anyone
complain about too much documentation!
It is recommended that each item's documentation follows this basic structure:
@ -23,9 +94,9 @@ It is recommended that each item's documentation follows this basic structure:
```
This basic structure should be straightforward to follow when writing your
documentation and, while you might think that a code example is trivial,
the examples are really important because they can help your users to
understand what an item is, how it is used, and for what purpose it exists.
documentation; while you might think that a code example is trivial,
the examples are really important because they can help users understand
what an item is, how it is used, and for what purpose it exists.
Let's see an example coming from the [standard library] by taking a look at the
[`std::env::args()`][env::args] function:
@ -62,21 +133,40 @@ for argument in env::args() {
[`args_os`]: ./fn.args_os.html
``````
Everything before the first empty line will be reused to describe the component
in searches and module overviews. For example, the function `std::env::args()`
above will be shown on the [`std::env`] module documentation. It is good
practice to keep the summary to one line: concise writing is a goal of good
documentation.
Because the type system does a good job of defining what types a function
passes and returns, there is no benefit of explicitly writing it
into the documentation, especially since `rustdoc` adds hyper links to all types in the function signature.
In the example above, a 'Panics' section explains when the code might abruptly exit,
which can help the reader prevent reaching a panic. A panic section is recommended
every time edge cases in your code can be reached if known.
As you can see, it follows the structure detailed above: it starts with a short
sentence explaining what the functions does, then it provides more information
and finally provides a code example.
## Markdown
`rustdoc` is using the [commonmark markdown specification]. You might be
`rustdoc` uses the [commonmark markdown specification]. You might be
interested into taking a look at their website to see what's possible to do.
- [commonmark quick reference]
- [current spec]
## Lints
To be sure that you didn't miss any item without documentation or code examples,
you can take a look at the rustdoc lints [here][rustdoc-lints].
[standard library]: https://doc.rust-lang.org/stable/std/index.html
[env::args]: https://doc.rust-lang.org/stable/std/env/fn.args.html
[`backtrace`]: https://docs.rs/backtrace/0.3.50/backtrace/
[commonmark markdown specification]: https://commonmark.org/
[rustdoc-lints]: lints.md
[commonmark quick reference]: https://commonmark.org/help/
[env::args]: https://doc.rust-lang.org/stable/std/env/fn.args.html
[`Future`]: https://doc.rust-lang.org/std/future/trait.Future.html
[`futures`]: https://docs.rs/futures/0.3.5/futures/
[`hashbrown`]: https://docs.rs/hashbrown/0.8.2/hashbrown/
[`regex`]: https://docs.rs/regex/1.3.9/regex/
[standard library]: https://doc.rust-lang.org/stable/std/index.html
[current spec]: https://spec.commonmark.org/current/
[`std::env`]: https://doc.rust-lang.org/stable/std/env/index.html#functions

View File

@ -0,0 +1,31 @@
# References
There are many great `rustdoc` references out there.
If you know of other great resources, please submit a pull request!
## Official
- [Learn Rust]
- [Rust By Example]
- [Rust Reference]
- [RFC 1574: More API Documentation Conventions]
- [RFC 1946: Intra Rustdoc Links]
## Community
- [API Guidelines]
- [Github tagged RFCs]
- [Github tagged issues]
- [RFC (stalled) front page styleguide]
- [Guide on how to write documenation for a Rust crate]
[API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html
[Github tagged RFCs]: https://github.com/rust-lang/rfcs/issues?q=label%3AT-rustdoc
[Github tagged issues]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+label%3AT-rustdoc
[Guide on how to write documenation for a Rust crate]: https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate
[Learn Rust]: https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments
[RFC 1574: More API Documentation Conventions]: https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html
[RFC 1946: Intra Rustdoc Links]: https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html
[RFC (stalled) front page styleguide]: https://github.com/rust-lang/rfcs/pull/1687
[Rust By Example]: https://doc.rust-lang.org/stable/rust-by-example/meta/doc.html
[Rust Reference]: https://doc.rust-lang.org/stable/reference/comments.html#doc-comments

View File

@ -7,14 +7,14 @@ CSS, and JavaScript.
## Basic usage
Let's give it a try! Let's create a new project with Cargo:
Let's give it a try! Create a new project with Cargo:
```bash
$ cargo new docs
$ cd docs
```
In `src/lib.rs`, you'll find that Cargo has generated some sample code. Delete
In `src/lib.rs`, Cargo has generated some sample code. Delete
it and replace it with this:
```rust
@ -31,8 +31,12 @@ $ rustdoc src/lib.rs
This will create a new directory, `doc`, with a website inside! In our case,
the main page is located in `doc/lib/index.html`. If you open that up in
a web browser, you'll see a page with a search bar, and "Crate lib" at the
top, with no contents. There's two problems with this: first, why does it
a web browser, you will see a page with a search bar, and "Crate lib" at the
top, with no contents.
## Configuring rustdoc
There are two problems with this: first, why does it
think that our package is named "lib"? Second, why does it not have any
contents?
@ -46,7 +50,7 @@ $ rustdoc src/lib.rs --crate-name docs
Now, `doc/docs/index.html` will be generated, and the page says "Crate docs."
For the second issue, it's because our function `foo` is not public; `rustdoc`
For the second issue, it is because our function `foo` is not public; `rustdoc`
defaults to generating documentation for only public functions. If we change
our code...
@ -61,7 +65,7 @@ pub fn foo() {}
$ rustdoc src/lib.rs --crate-name docs
```
We'll have some generated documentation. Open up `doc/docs/index.html` and
We now have some generated documentation. Open up `doc/docs/index.html` and
check it out! It should show a link to the `foo` function's page, which
is located at `doc/docs/fn.foo.html`. On that page, you'll see the "foo is
a function" we put inside the documentation comment in our crate.
@ -85,13 +89,12 @@ dependency=<path>/docs/target/debug/deps
You can see this with `cargo doc --verbose`.
It generates the correct `--crate-name` for us, as well as pointing to
`src/lib.rs` But what about those other arguments? `-o` controls the
*o*utput of our docs. Instead of a top-level `doc` directory, you'll
notice that Cargo puts generated documentation under `target`. That's
the idiomatic place for generated files in Cargo projects. Also, it
passes `-L`, a flag that helps rustdoc find the dependencies
your code relies on. If our project used dependencies, we'd get
documentation for them as well!
`src/lib.rs`. But what about those other arguments?
- `-o` controls the *o*utput of our docs. Instead of a top-level
`doc` directory, notice that Cargo puts generated documentation under
`target`. That is the idiomatic place for generated files in Cargo projects.
- `-L` flag helps rustdoc find the dependencies your code relies on.
If our project used dependencies, we would get documentation for them as well!
## Outer and inner documentation
@ -118,7 +121,7 @@ For more information about the `//!` syntax, see [the Book].
## Using standalone Markdown files
`rustdoc` can also generate HTML from standalone Markdown files. Let's
`rustdoc` can also generate HTML from standalone Markdown files. Let' s
give it a try: create a `README.md` file with these contents:
````text
@ -128,7 +131,7 @@ This is a project to test out `rustdoc`.
[Here is a link!](https://www.rust-lang.org)
## Subheading
## Example
```rust
fn foo() -> i32 {
@ -143,7 +146,7 @@ And call `rustdoc` on it:
$ rustdoc README.md
```
You'll find an HTML file in `docs/doc/README.html` generated from its
You will find an HTML file in `docs/doc/README.html` generated from its
Markdown contents.
Cargo currently does not understand standalone Markdown files, unfortunately.

View File

@ -0,0 +1,125 @@
# What to include (and exclude)
It is easy to say everything must be documented in a project and often times
that is correct, but how can we get there, and are there things that don't
belong?
At the top of the `src/lib.rs` or `main.rs` file in your binary project, include
the following attribute:
```rust
#![warn(missing_docs)]
```
Now run `cargo doc` and examine the output. Here's a sample:
```text
Documenting docdemo v0.1.0 (/Users/username/docdemo)
warning: missing documentation for the crate
--> src/main.rs:1:1
|
1 | / #![warn(missing_docs)]
2 | |
3 | | fn main() {
4 | | println!("Hello, world!");
5 | | }
| |_^
|
note: the lint level is defined here
--> src/main.rs:1:9
|
1 | #![warn(missing_docs)]
| ^^^^^^^^^^^^
warning: 1 warning emitted
Finished dev [unoptimized + debuginfo] target(s) in 2.96s
```
As a library author, adding the lint `#![deny(missing_docs)]` is a great way to
ensure the project does not drift away from being documented well, and
`#![warn(missing_docs)]` is a good way to move towards comprehensive
documentation. In addition to docs, `#![deny(missing_doc_code_examples)]`
ensures each function contains a usage example. In our example above, the
warning is resolved by adding crate level documentation.
There are more lints in the upcoming chapter [Lints][rustdoc-lints].
## Examples
Of course this is contrived to be simple, but part of the power of documentation
is showing code that is easy to follow, rather than being realistic. Docs often
take shortcuts with error handling because examples can become complicated to
follow with all the necessary set up required for a simple example.
`Async` is a good example of this. In order to execute an `async` example, an
executor needs to be available. Examples will often shortcut this, and leave
users to figure out how to put the `async` code into their own runtime.
It is preferred that `unwrap()` not be used inside an example, and some of the
error handling components be hidden if they make the example too difficult to
follow.
``````text
/// Example
/// ```rust
/// let fourtytwo = "42".parse::<u32>()?;
/// println!("{} + 10 = {}", fourtytwo, fourtytwo+10);
/// ```
``````
When rustdoc wraps that in a main function, it will fail to compile because the
`ParseIntError` trait is not implemented. In order to help both your audience
and your test suite, this example needs some additional code:
``````text
/// Example
/// ```rust
/// # main() -> Result<(), std::num::ParseIntError> {
/// let fortytwo = "42".parse::<u32>()?;
/// println!("{} + 10 = {}", fortytwo, fortytwo+10);
/// # Ok(())
/// # }
/// ```
``````
The example is the same on the doc page, but has that extra information
available to anyone trying to use your crate. More about tests in the
upcoming [Documentation tests] chapter.
## What to Exclude
Certain parts of your public interface may be included by default in the output
of rustdoc. The attribute `#[doc(hidden)]` can hide implementation details
to encourage idiomatic use of the crate.
For example, an internal `macro!` that makes the crate easier to implement can
become a footgun for users when it appears in the public documentation. An
internal `Error` type may exist, and `impl` details should be hidden, as
detailed in the [API Guidelines].
## Customizing the output
It is possible to pass a custom css file to `rustdoc` and style the
documentation.
```bash
rustdoc --extend-css custom.css src/lib.rs
```
A good example of using this feature to create a dark theme is documented [on
this blog]. Just remember, dark theme is already included in the rustdoc output
by clicking on the paintbrush. Adding additional options to the themes are
as easy as creating a custom theme `.css` file and using the following syntax:
```bash
rustdoc --theme awesome.css src/lib.rs
```
Here is an example of a new theme, [Ayu].
[Ayu]: https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/static/themes/ayu.css
[API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html#rustdoc-does-not-show-unhelpful-implementation-details-c-hidden
[Documentation tests]: documentation-tests.md
[on this blog]: https://blog.guillaume-gomez.fr/articles/2016-09-16+Generating+doc+with+rustdoc+and+a+custom+theme
[rustdoc-lints]: lints.md

View File

@ -432,6 +432,7 @@ fn usage(argv0: &str) {
(option.apply)(&mut options);
}
println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
println!("More information available at https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html")
}
/// A result type used by several functions under `main()`.