]> git.lizzy.rs Git - rust.git/commitdiff
Added Rustdoc book sections for linting and embedding more examples
authorAndrew Gauger <andygauge@gmail.com>
Sat, 22 Aug 2020 00:19:56 +0000 (17:19 -0700)
committerAndrew Gauger <andygauge@gmail.com>
Thu, 5 Nov 2020 01:47:50 +0000 (17:47 -0800)
Co-authored-by: Joshua Nelson <joshua@yottadb.com>
src/doc/rustdoc/src/SUMMARY.md
src/doc/rustdoc/src/how-to-write-documentation.md
src/doc/rustdoc/src/references.md [new file with mode: 0644]
src/doc/rustdoc/src/what-is-rustdoc.md
src/doc/rustdoc/src/what-to-include.md [new file with mode: 0644]
src/librustdoc/lib.rs

index a3fa525be1db0efa94421f9d9926d4eeadbde16a..943aa09f678d7570967c6d7143c8507a25d73d32 100644 (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)
index dd3aa5d4b6988ebf5ae47bd4b681f5bf19cc7c72..ca6db26da3130aadfdc61fcb9f2428ac566076d7 100644 (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
diff --git a/src/doc/rustdoc/src/references.md b/src/doc/rustdoc/src/references.md
new file mode 100644 (file)
index 0000000..1e050e3
--- /dev/null
@@ -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
\ No newline at end of file
index 7a38c96d7147b57a0a947f4a022c6b4d3d159680..1f6dced180b96dab02bb71ba53116477da6667fe 100644 (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.
diff --git a/src/doc/rustdoc/src/what-to-include.md b/src/doc/rustdoc/src/what-to-include.md
new file mode 100644 (file)
index 0000000..878c75b
--- /dev/null
@@ -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
\ No newline at end of file
index 12726d2bd9a3e048013f0b555cd4a64abb56ef65..752b24bc929111b3ae16d0a515dbd3f6c205dc5b 100644 (file)
@@ -418,6 +418,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()`.