| 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 ] |
| 166 | macro_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 ] |
| 194 | macro_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 ] |
| 221 | macro_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 | } |
| 229 | |