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