Skip to main content

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.