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