auto_args/guide.rs
1//! # A user's guide for auto_args.
2//!
3//! AutoArgs allows you to parse command line arguments by defining a
4//! struct. It combines [clap](https://crates.io/crates/clap) with
5//! custom derive.
6//!
7//! The basic idea is that you define a type that represents the
8//! information you want on the command-line from the person running
9//! your program, and `derive(AutoArgs)` on that type, and then call
10//! `YourType::from_args()` to find out what your user gave you.
11//! To begin with, let's look at an example of how you might actually
12//! use `AutoArgs` in a real program.
13//!
14//! ```should_panic
15//! #[macro_use]
16//! extern crate auto_args;
17//!
18//! use std::path::PathBuf;
19//! use auto_args::AutoArgs;
20//!
21//! #[derive(Debug, AutoArgs)]
22//! struct Opt {
23//! /// Filling fraction
24//! filling_fraction: f64,
25//! /// Number of atoms
26//! N: u32,
27//! /// Output directory, working directory if not present
28//! dir: Option<PathBuf>,
29//! /// Activate verbose printing
30//! verbose: bool,
31//! }
32//!
33//! fn main() {
34//! let opt = Opt::from_args();
35//! println!("{:?}", opt);
36//! }
37//! ```
38//! The remainder of this guide will give examples of how the
39//! command-line flags are constructed from your type, starting with
40//! simple cases and moving gradually to more complex ones. In no
41//! case does your code involve more than defining a type, deriving
42//! `AutoArgs` and calling the `from_args` method of your type.
43//! I want to note that `AutoArgs` *almost always* produces long flags.
44//! This is because I feel that long flags are generally the easiest
45//! to use. If you want to fine-tune your command-line interface,
46//! `AutoArgs` may not be for you.
47//! ## Just a flag
48//! Most often, you will define a struct as your type. We'll
49//! start out with the simplest case, which is a single boolean
50//! field within that struct.
51//! ```
52//! struct Foo {
53//! foo: bool,
54//! }
55//! ```
56//! This gives the following usage.
57//! ```ignore
58//! USAGE:
59//! create_guide-5214c7bad433b4e9 [--foo]
60//!
61//! For more information try --help
62//! ```
63//! and the following help message.
64//! ```ignore
65//! USAGE:
66//! create_guide-5214c7bad433b4e9 [--foo]
67//!
68//! [--foo]
69//!
70//!
71//! For more information try --help
72//! ```
73//! A single boolean flag is treated as an optional flag.
74//! ## Adding help information
75//! We add help information simply by adding ordinary doc comments
76//! to our struct.
77//! ```
78//! struct Help {
79//! /// Print excess messages.
80//! verbose: bool,
81//! /// The temperature.
82//! T: bool,
83//! }
84//! ```
85//! This gives the following usage.
86//! ```ignore
87//! USAGE:
88//! create_guide-5214c7bad433b4e9 [--verbose] [--T]
89//!
90//! For more information try --help
91//! ```
92//! and the following help message.
93//! ```ignore
94//! USAGE:
95//! create_guide-5214c7bad433b4e9 [--verbose] [--T]
96//!
97//! [--verbose] Print excess messages.
98//! [--T] The temperature.
99//!
100//!
101//! For more information try --help
102//! ```
103//! I would always documentation for actual projects, so I'll try
104//! to model that here, even though these examples are all
105//! fictitious.
106//! ## How the flag is determined
107//! We saw above that the flag just had `--` prepended to the
108//! field name. The rule in general is only slightly more
109//! complicated: every underscore is replaced with a `-`.
110//! ```
111//! struct Flags {
112//! /// a simple word has "--" prepended to it.
113//! verbose: bool,
114//! /// Underscores are replaced with "-" ...
115//! blue_is_nice_: bool,
116//! /// and capital letters are preserved.
117//! min_T: bool,
118//! }
119//! ```
120//! This gives the following usage.
121//! ```ignore
122//! USAGE:
123//! create_guide-5214c7bad433b4e9 [--verbose] [--blue-is-nice-] [--min-T]
124//!
125//! [--verbose] a simple word has "--" prepended to it.
126//! [--blue-is-nice-] Underscores are replaced with "-" ...
127//! [--min-T] and capital letters are preserved.
128//!
129//!
130//! For more information try --help
131//! ```
132//! Thus you can create most any flag name you care for, and it is
133//! easy to tell which flag corresponds to which field in your
134//! struct.
135//! ## Other types
136//! You can add most standard library types to your struct,
137//! basically anything that can be read or parsed from a `&str`.
138//! I'd recommend sticking to owned types.
139//! ```
140//! struct Types {
141//! /// The name of the type
142//! name: String,
143//! /// The temperature of the type
144//! T: f64,
145//! /// The place where it is
146//! directory: std::path::PathBuf,
147//! }
148//! ```
149//! This gives the following usage.
150//! ```ignore
151//! USAGE:
152//! create_guide-5214c7bad433b4e9 --name STRING --T FLOAT --directory STRING
153//!
154//! --name STRING The name of the type
155//! --T FLOAT The temperature of the type
156//! --directory STRING The place where it is
157//!
158//!
159//! For more information try --help
160//! ```
161//! I should note that integer types do allow their value to be
162//! specified using scientific notation, as in `1e6` rather than
163//! `1000000`. This is in different from rust's `FromStr`
164//! implementation. AutoArgs does reject floating point values that
165//! cannot be reversibly converted to the integer type that is
166//! requested.
167//!
168//! Furthermore, when providing numerical user input, users may
169//! specify an expression such as `1/3` or `sqrt(2)`. This is
170//! most useful for floating point input where makes it easier to
171//! give high-precision input when needed, but may also be helpful
172//! for integers.
173//! ## Optional flags
174//! In the previous examples, every flag (except a `bool` flag)
175//! was required to be specified by the user. If you want a flag
176//! to be optional, you just use the standard `Option` type.
177//! ```
178//! struct Optional {
179//! /// The name is an optional argument.
180//! name: Option<String>,
181//! }
182//! ```
183//! This gives the following usage.
184//! ```ignore
185//! USAGE:
186//! create_guide-5214c7bad433b4e9 [--name STRING]
187//!
188//! [--name STRING] The name is an optional argument.
189//!
190//!
191//! For more information try --help
192//! ```
193//! The value is then `None` if the user did not specify that flag.
194//! ## Exclusive flags
195//! If you want to make certain flags/values mutually exclusive,
196//! you use an `enum` (just as always, in rust).
197//! ```
198//! enum Exclusive {
199//! /// In this context, the doc comment for the variant is not
200//! /// used by auto_args.
201//! First {
202//! /// This is the "a" value
203//! a: String,
204//! /// Only the first line of comment shows up in help.
205//! /// This is the "b" value, which you cannot specify unless
206//! /// you also specify the "a" value.
207//! b: String,
208//! },
209//! /// A string that cannot be used with any other flag
210//! SecondFlag(String),
211//! /// A flag with no value, and with a capital letter.
212//! Third_,
213//! }
214//! ```
215//! This gives the following usage.
216//! ```ignore
217//! USAGE:
218//! create_guide-5214c7bad433b4e9 ( --first-a STRING --first-b STRING | --second-flag STRING | --Third )
219//!
220//! For more information try --help
221//! ```
222//! and the following help message.
223//! ```ignore
224//! USAGE:
225//! create_guide-5214c7bad433b4e9 ( --first-a STRING --first-b STRING | --second-flag STRING | --Third )
226//!
227//! EITHER
228//! --first-a STRING This is the "a" value
229//! --first-b STRING Only the first line of comment shows up in help.
230//! OR
231//! --second-flag STRING A string that cannot be used with any other flag
232//! OR
233//! --Third A flag with no value, and with a capital letter.
234//!
235//!
236//!
237//! For more information try --help
238//! ```
239//! This example illustrates the three kinds of `enum` variants.
240//! Sadly, the help message does not indicate that these flags are
241//! exlusive. However, if a user tries to specify both `--third`
242//! and `--second FOO`, however, they will get a nice error
243//! message. Note that you cannot use a tuple variant with more
244//! than one field.
245//! Note that the rules for constructing flags from enum variants
246//! are more complicated than for struct fields. This is because
247//! by convention variants are given `CamelCase` names, which
248//! aren't suitable as flags. If a variant name contains an
249//! underscore, then it is treated like a field name (as described
250//! above), with any trailing underscores removed. Otherwise the
251//! name is converted from `CamelCase` to `kebab-case`.
252//! ## Nesting types
253//! You can use any `AutoArgs` type as a field within a struct or
254//! enum. Doing so will give flag names that combine the nested
255//! field names.
256//! ```ignore
257//! #[derive(AutoArgs)]
258//! /// I'm not putting doc-comments on `x` and `y`, because auto_args
259//! /// would give the same help message for `--position-x` as for
260//! /// `--velocity-x`, which would be pretty useless.
261//! struct Vec2d {
262//! x: f64,
263//! y: f64,
264//! }
265//! #[derive(AutoArgs)]
266//! struct Nested {
267//! /// We would like for this to be the help for both components
268//! /// of the position, but auto_args is not that clever. Ideally
269//! /// the help should read something like: the x component of
270//! /// the position/velocity, but that would require combining
271//! /// information at multiple levels and sounds hard.
272//! position: Vec2d,
273//! velocity: Vec2d,
274//! }
275//! ```
276//! This gives the following usage.
277//! ```ignore
278//! USAGE:
279//! create_guide-5214c7bad433b4e9 --position-x FLOAT --position-y FLOAT --velocity-x FLOAT --velocity-y FLOAT
280//!
281//! --position-x FLOAT
282//! --position-y FLOAT
283//! --velocity-x FLOAT
284//! --velocity-y FLOAT
285//!
286//!
287//! For more information try --help
288//! ```
289//! ## Flattened nesting types
290//! As you say in the last example, nesting types allows you to
291//! make your own complex types that can be reused. Sometimes,
292//! however, you would like to nest structs for a different
293//! reason: to separate concerns in the code. In this case, you
294//! may not want the nesting to be visible in the user interface.
295//! This can be acheived with a leading underscore on a field
296//! name. The catch is that when you do this, you could run into
297//! a runtime error if you have duplicate field names.
298//! ```ignore
299//! #[derive(AutoArgs)]
300//! struct MyConfig {
301//! /// The user's name
302//! name: String,
303//! }
304//! #[derive(AutoArgs)]
305//! struct YourConfig {
306//! /// The user's address
307//! address: String,
308//! }
309//! #[derive(AutoArgs)]
310//! struct Flattened {
311//! _mine: MyConfig,
312//! _yours: YourConfig,
313//! }
314//! ```
315//! This gives the following usage.
316//! ```ignore
317//! USAGE:
318//! create_guide-5214c7bad433b4e9 --name STRING --address STRING
319//!
320//! For more information try --help
321//! ```
322//! and the following help message.
323//! ```ignore
324//! USAGE:
325//! create_guide-5214c7bad433b4e9 --name STRING --address STRING
326//!
327//! --name STRING The user's name
328//! --address STRING The user's address
329//!
330//!
331//! For more information try --help
332//! ```
333//! This may be a good idea if `MyConfig` and `YourConfig` are
334//! implementation details that your user need not be aware of.
335//! ## Other possibilities
336//! There may be a few other features that auto_args has, for which I
337//! have not bothered to create an entire example. I will list
338//! them here when they come to mind.
339//! 1. You can use a `Vec<T>` for many values of `T` to create an
340//! option that can be specified more than once.
341//! ## Conclusion
342//! There is more that could be said and more possible examples,
343//! but I think this is enough to get you started using `AutoArgs`.
344//! The intent is that any reasonable type that *can* be obtained
345//! from one or more strings should work with auto_args. Please fill
346//! an issue on github if there is a type that you would like to
347//! have supported by auto_args. Pull requests are most welcome.