doc_comment/lib.rs
1//
2// Doc comment
3//
4// Copyright (c) 2018 Guillaume Gomez
5//
6
7#![cfg_attr(feature = "no_core", feature(no_core))]
8#![cfg_attr(feature = "no_core", no_core)]
9#![cfg_attr(not(feature = "no_core"), no_std)]
10
11//! The point of this (small) crate is to allow you to add doc comments from macros or
12//! to test external markdown files' code blocks through `rustdoc`.
13//!
14//! Starting in Rust 1.54, this crate becomes useless as you can do the same thing
15//! with the `doc` attribute:
16//!
17//! ```ignore
18//! #[cfg_attr(doctest, doc = include_str!("../README.md"))]
19//! ```
20//!
21//! ## Including file(s) for testing
22//!
23//! Let's assume you want to test code examples in your `README.md` file which
24//! looks like this:
25//!
26//! ````text
27//! # A crate
28//!
29//! Here is a code example:
30//!
31//! ```rust
32//! let x = 2;
33//! assert!(x != 0);
34//! ```
35//! ````
36//!
37//! You can use the `doc_comment!` macro to test it like this:
38//!
39//! ```
40//! #[macro_use]
41//! extern crate doc_comment;
42//!
43//! // When running `cargo test`, rustdoc will check this file as well.
44//! doc_comment!(include_str!("../README.md"));
45//! # fn main() {}
46//! ```
47//!
48//! Please note that can also use the `doctest!` macro to have a shorter way to test an outer
49//! file:
50//!
51//! ```no_run
52//! #[macro_use]
53//! extern crate doc_comment;
54//!
55//! doctest!("../README.md");
56//! # fn main() {}
57//! ```
58//!
59//! Please also note that you can use `#[cfg(doctest)]`:
60//!
61//! ```no_run
62//! # #[macro_use]
63//! # extern crate doc_comment;
64//! #[cfg(doctest)]
65//! doctest!("../README.md");
66//! # fn main() {}
67//! ```
68//!
69//! In this case, the examples in the `README.md` file will only be run on `cargo test`. You
70//! can find more information about `#[cfg(doctest)]` in [this blogpost](https://blog.guillaume-gomez.fr/articles/2020-03-07+cfg%28doctest%29+is+stable+and+you+should+use+it).
71//!
72//! ## Generic documentation
73//!
74//! Now let's imagine you want to write documentation once for multiple types but
75//! still having examples specific to each type:
76//!
77//! ```
78//! // The macro which generates types
79//! macro_rules! gen_types {
80//! ($tyname:ident) => {
81//! /// This is a wonderful generated struct!
82//! ///
83//! /// You can use it as follow:
84//! ///
85//! /// ```
86//! /// let x = FirstOne {
87//! /// field1: 0,
88//! /// field2: 0,
89//! /// field3: 0,
90//! /// field4: 0,
91//! /// };
92//! ///
93//! /// println!("Created a new instance of FirstOne: {:?}", x);
94//! /// ```
95//! #[derive(Debug)]
96//! pub struct $tyname {
97//! pub field1: u8,
98//! pub field2: u16,
99//! pub field3: u32,
100//! pub field4: u64,
101//! }
102//! }
103//! }
104//!
105//! // Now let's actually generate types:
106//! gen_types!(FirstOne);
107//! gen_types!(SecondOne);
108//! gen_types!(Another);
109//! ```
110//!
111//! So now we have created three structs with different names, but they all have the exact same
112//! documentation, which is an issue for any structs not called `FirstOne`. That's where
113//! [`doc_comment!`] macro comes in handy!
114//!
115//! Let's rewrite the `gen_types!` macro:
116//!
117//! // Of course, we need to import the `doc_comment` macro:
118//! #[macro_use]
119//! extern crate doc_comment;
120//!
121//! macro_rules! gen_types {
122//! ($tyname:ident) => {
123//! doc_comment! {
124//! concat!("This is a wonderful generated struct!
125//!
126//! You can use it as follow:
127//!
128//! ```
129//! let x = ", stringify!($tyname), " {
130//! field1: 0,
131//! field2: 0,
132//! field3: 0,
133//! field4: 0,
134//! };
135//!
136//! println!(\"Created a new instance of ", stringify!($tyname), ": {:?}\", x);
137//! ```"),
138//! #[derive(Debug)]
139//! pub struct $tyname {
140//! pub field1: u8,
141//! pub field2: u16,
142//! pub field3: u32,
143//! pub field4: u64,
144//! }
145//! }
146//! }
147//! }
148//!
149//! gen_types!(FirstOne);
150//! gen_types!(SecondOne);
151//! gen_types!(Another);
152//! # fn main() {}
153//!
154//! Now each struct has doc which match itself!
155
156/// This macro can be used to generate documentation upon a type/item (or just to test outer
157/// markdown file code examples).
158///
159/// # Example
160///
161/// ```
162/// #[macro_use]
163/// extern crate doc_comment;
164///
165/// // If you just want to test an outer markdown file:
166/// doc_comment!(include_str!("../README.md"));
167///
168/// // If you want to document an item:
169/// doc_comment!("fooo", pub struct Foo {});
170/// # fn main() {}
171/// ```
172#[macro_export]
173macro_rules! doc_comment {
174 ($x:expr) => {
175 #[doc = $x]
176 extern {}
177 };
178 ($x:expr, $($tt:tt)*) => {
179 #[doc = $x]
180 $($tt)*
181 };
182}
183
184/// This macro provides a simpler way to test an outer markdown file.
185///
186/// # Example
187///
188/// ```
189/// extern crate doc_comment;
190///
191/// // The two next lines are doing exactly the same thing:
192/// doc_comment::doc_comment!(include_str!("../README.md"));
193/// doc_comment::doctest!("../README.md");
194///
195/// // If you want to have a name for your tests:
196/// doc_comment::doctest!("../README.md", another);
197/// # fn main() {}
198/// ```
199#[cfg(not(feature = "old_macros"))]
200#[macro_export]
201macro_rules! doctest {
202 ($x:expr) => {
203 doc_comment::doc_comment!(include_str!($x));
204 };
205 ($x:expr, $y:ident) => {
206 doc_comment::doc_comment!(include_str!($x), mod $y {});
207 };
208}
209
210/// This macro provides a simpler way to test an outer markdown file.
211///
212/// # Example
213///
214/// ```
215/// #[macro_use]
216/// extern crate doc_comment;
217///
218/// // The two next lines are doing exactly the same thing:
219/// doc_comment!(include_str!("../README.md"));
220/// doctest!("../README.md");
221///
222/// // If you want to have a name for your tests:
223/// doctest!("../README.md", another);
224/// # fn main() {}
225/// ```
226#[cfg(feature = "old_macros")]
227#[macro_export]
228macro_rules! doctest {
229 ($x:expr) => {
230 doc_comment!(include_str!($x));
231 };
232 ($x:expr, $y:ident) => {
233 doc_comment!(include_str!($x), mod $y {});
234 };
235}