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}