diff options
Diffstat (limited to 'clap/examples')
26 files changed, 1550 insertions, 0 deletions
| diff --git a/clap/examples/01a_quick_example.rs b/clap/examples/01a_quick_example.rs new file mode 100644 index 0000000..c7fa20f --- /dev/null +++ b/clap/examples/01a_quick_example.rs @@ -0,0 +1,79 @@ +extern crate clap; + +use clap::{App, SubCommand}; + +fn main() { + +    // This example shows how to create an application with several arguments using usage strings, which can be +    // far less verbose that shown in 01b_QuickExample.rs, but is more readable. The downside is you cannot set +    // the more advanced configuration options using this method (well...actually you can, you'll see ;) ) +    // +    // The example below is functionally identical to the 01b_quick_example.rs and 01c_quick_example.rs +    // +    // Create an application with 5 possible arguments (2 auto generated) and 2 subcommands (1 auto generated) +    //    - A config file +    //        + Uses "-c filename" or "--config filename" +    //    - An output file +    //        + A positional argument (i.e. "$ myapp output_filename") +    //    - A debug flag +    //        + Uses "-d" or "--debug" +    //        + Allows multiple occurrences of such as "-dd" (for vary levels of debugging, as an example) +    //    - A help flag (automatically generated by clap) +    //        + Uses "-h" or "--help" (Only autogenerated if you do NOT specify your own "-h" or "--help") +    //    - A version flag (automatically generated by clap) +    //        + Uses "-V" or "--version" (Only autogenerated if you do NOT specify your own "-V" or "--version") +    //    - A subcommand "test" (subcommands behave like their own apps, with their own arguments +    //        + Used by "$ myapp test" with the following arguments +    //            > A list flag +    //                = Uses "-l" (usage is "$ myapp test -l" +    //            > A help flag (automatically generated by clap +    //                = Uses "-h" or "--help" (full usage "$ myapp test -h" or "$ myapp test --help") +    //            > A version flag (automatically generated by clap +    //                = Uses "-V" or "--version" (full usage "$ myapp test -V" or "$ myapp test --version") +    //    - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own) +    //        + Used by "$ myapp help" (same functionality as "-h" or "--help") +    let matches = App::new("MyApp") +                        .version("1.0") +                        .author("Kevin K. <kbknapp@gmail.com>") +                        .about("Does awesome things") +                        .args_from_usage("-c, --config=[FILE] 'Sets a custom config file' +                                         <output> 'Sets an optional output file' +                                         -d... 'Turn debugging information on'") +                        .subcommand(SubCommand::with_name("test") +                                                .about("does testing things") +                                                .arg_from_usage("-l, --list 'lists test values'")) +                        .get_matches(); + +    // You can check the value provided by positional arguments, or option arguments +    if let Some(o) = matches.value_of("output") { +        println!("Value for output: {}", o); +    } + +    if let Some(c) = matches.value_of("config") { +        println!("Value for config: {}", c); +    } + +    // You can see how many times a particular flag or argument occurred +    // Note, only flags can have multiple occurrences +    match matches.occurrences_of("d") { +        0 => println!("Debug mode is off"), +        1 => println!("Debug mode is kind of on"), +        2 => println!("Debug mode is on"), +        3 | _ => println!("Don't be crazy"), +     } + +    // You can check for the existence of subcommands, and if found use their +    // matches just as you would the top level app +    if let Some(matches) = matches.subcommand_matches("test") { +        // "$ myapp test" was run +        if matches.is_present("list") { +            // "$ myapp test -l" was run +            println!("Printing testing lists..."); +        } else { +            println!("Not printing testing lists..."); +        } +    } + + +    // Continued program logic goes here... +} diff --git a/clap/examples/01b_quick_example.rs b/clap/examples/01b_quick_example.rs new file mode 100644 index 0000000..7f455a8 --- /dev/null +++ b/clap/examples/01b_quick_example.rs @@ -0,0 +1,93 @@ +extern crate clap; + +use clap::{App, Arg, SubCommand}; + +fn main() { + +    // This method shows the traditional, and slightly more configurable way to set up arguments. This method is +    // more verbose, but allows setting more configuration options, and even supports easier dynamic generation. +    // +    // The example below is functionally identical to the 01a_quick_example.rs and 01c_quick_example.rs +    // +    // *NOTE:* You can actually achieve the best of both worlds by using Arg::from_usage() (instead of Arg::with_name()) +    // and *then* setting any additional properties. +    // +    // Create an application with 5 possible arguments (2 auto generated) and 2 subcommands (1 auto generated) +    //    - A config file +    //        + Uses "-c filename" or "--config filename" +    //    - An output file +    //        + A positional argument (i.e. "$ myapp output_filename") +    //    - A debug flag +    //        + Uses "-d" or "--debug" +    //        + Allows multiple occurrences of such as "-dd" (for vary levels of debugging, as an example) +    //    - A help flag (automatically generated by clap) +    //        + Uses "-h" or "--help" (Only autogenerated if you do NOT specify your own "-h" or "--help") +    //    - A version flag (automatically generated by clap) +    //        + Uses "-V" or "--version" (Only autogenerated if you do NOT specify your own "-V" or "--version") +    //    - A subcommand "test" (subcommands behave like their own apps, with their own arguments +    //        + Used by "$ myapp test" with the following arguments +    //            > A list flag +    //                = Uses "-l" (usage is "$ myapp test -l" +    //            > A help flag (automatically generated by clap +    //                = Uses "-h" or "--help" (full usage "$ myapp test -h" or "$ myapp test --help") +    //            > A version flag (automatically generated by clap +    //                = Uses "-V" or "--version" (full usage "$ myapp test -V" or "$ myapp test --version") +    //    - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own) +    //        + Used by "$ myapp help" (same functionality as "-h" or "--help") +    let matches = App::new("MyApp") +                        .version("1.0") +                        .author("Kevin K. <kbknapp@gmail.com>") +                        .about("Does awesome things") +                        .arg(Arg::with_name("config") +                                    .short("c") +                                    .long("config") +                                    .value_name("FILE") +                                    .help("Sets a custom config file") +                                    .takes_value(true)) +                        .arg(Arg::with_name("output") +                                    .help("Sets an optional output file") +                                    .index(1)) +                        .arg(Arg::with_name("debug") +                                    .short("d") +                                    .multiple(true) +                                    .help("Turn debugging information on")) +                        .subcommand(SubCommand::with_name("test") +                                                .about("does testing things") +                                                .arg(Arg::with_name("list") +                                                    .short("l") +                                                    .help("lists test values"))) +                        .get_matches(); + +    // You can check the value provided by positional arguments, or option arguments +    if let Some(o) = matches.value_of("output") { +        println!("Value for output: {}", o); +    } + +    if let Some(c) = matches.value_of("config") { +        println!("Value for config: {}", c); +    } + +    // You can see how many times a particular flag or argument occurred +    // Note, only flags can have multiple occurrences +    match matches.occurrences_of("debug") { +        0 => println!("Debug mode is off"), +        1 => println!("Debug mode is kind of on"), +        2 => println!("Debug mode is on"), +        3 | _ => println!("Don't be crazy"), +     } + +    // You can check for the existence of subcommands, and if found use their +    // matches just as you would the top level app +    if let Some(matches) = matches.subcommand_matches("test") { +        // "$ myapp test" was run +        if matches.is_present("list") { +            // "$ myapp test -l" was run +            println!("Printing testing lists..."); +        } else { +            println!("Not printing testing lists..."); +        } +    } + + +    // Continued program logic goes here... +} diff --git a/clap/examples/01c_quick_example.rs b/clap/examples/01c_quick_example.rs new file mode 100644 index 0000000..071bdc0 --- /dev/null +++ b/clap/examples/01c_quick_example.rs @@ -0,0 +1,75 @@ +#[macro_use] +extern crate clap; + +fn main() { +    // This example shows how to create an application with several arguments using macro builder. +    // It combines the simplicity of the from_usage methods and the performance of the Builder Pattern. +    // +    // The example below is functionally identical to the one in 01a_quick_example.rs and 01b_quick_example.rs +    // +    // Create an application with 5 possible arguments (2 auto generated) and 2 subcommands (1 auto generated) +    //    - A config file +    //        + Uses "-c filename" or "--config filename" +    //    - An output file +    //        + A positional argument (i.e. "$ myapp output_filename") +    //    - A debug flag +    //        + Uses "-d" or "--debug" +    //        + Allows multiple occurrences of such as "-dd" (for vary levels of debugging, as an example) +    //    - A help flag (automatically generated by clap) +    //        + Uses "-h" or "--help" (Only autogenerated if you do NOT specify your own "-h" or "--help") +    //    - A version flag (automatically generated by clap) +    //        + Uses "-V" or "--version" (Only autogenerated if you do NOT specify your own "-V" or "--version") +    //    - A subcommand "test" (subcommands behave like their own apps, with their own arguments +    //        + Used by "$ myapp test" with the following arguments +    //            > A list flag +    //                = Uses "-l" (usage is "$ myapp test -l" +    //            > A help flag (automatically generated by clap +    //                = Uses "-h" or "--help" (full usage "$ myapp test -h" or "$ myapp test --help") +    //            > A version flag (automatically generated by clap +    //                = Uses "-V" or "--version" (full usage "$ myapp test -V" or "$ myapp test --version") +    //    - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own) +    //        + Used by "$ myapp help" (same functionality as "-h" or "--help") +    let matches = clap_app!(myapp => +        (version: "1.0") +        (author: "Kevin K. <kbknapp@gmail.com>") +        (about: "Does awesome things") +        (@arg CONFIG: -c --config +takes_value "Sets a custom config file") +        (@arg INPUT: +required "Sets the input file to use") +        (@arg debug: -d ... "Sets the level of debugging information") +        (@subcommand test => +            (about: "controls testing features") +            (version: "1.3") +            (author: "Someone E. <someone_else@other.com>") +            (@arg verbose: -v --verbose "Print test information verbosely") +        ) +    ).get_matches(); + +    // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't +    // required we could have used an 'if let' to conditionally get the value) +    println!("Using input file: {}", matches.value_of("INPUT").unwrap()); + +    // Gets a value for config if supplied by user, or defaults to "default.conf" +    let config = matches.value_of("CONFIG").unwrap_or("default.conf"); +    println!("Value for config: {}", config); + +    // Vary the output based on how many times the user used the "debug" flag +    // (i.e. 'myapp -d -d -d' or 'myapp -ddd' vs 'myapp -d' +    match matches.occurrences_of("debug") { +        0 => println!("Debug mode is off"), +        1 => println!("Debug mode is kind of on"), +        2 => println!("Debug mode is on"), +        3 | _ => println!("Don't be crazy"), +    } + +    // You can information about subcommands by requesting their matches by name +    // (as below), requesting just the name used, or both at the same time +    if let Some(matches) = matches.subcommand_matches("test") { +        if matches.is_present("verbose") { +            println!("Printing verbosely..."); +        } else { +            println!("Printing normally..."); +        } +    } + +    // more program logic goes here... +} diff --git a/clap/examples/02_apps.rs b/clap/examples/02_apps.rs new file mode 100644 index 0000000..8e45640 --- /dev/null +++ b/clap/examples/02_apps.rs @@ -0,0 +1,30 @@ +extern crate clap; + +use clap::App; + +fn main() { +    // Apps describe the top level application +    // +    // You create an App and set various options on that App using the "builder pattern" +    // +    // The options (version(), author(), about()) aren't mandatory, but recommended. There is +    // another option, usage(), which is an exception to the rule. This should only be used when +    // the default usage string automatically generated by clap doesn't suffice. +    // +    // You also set all the valid arguments your App should accept via the arg(), args(), arg_from_usage() +    // and args_from_usage() (as well as subcommands via the subcommand() and subcommands() methods) which +    // will be covered later. +    // +    // Once all options have been set, call one of the .get_matches* family of methods in order to +    // start the parsing and find all valid command line arguments that supplied by the user at +    // runtime. The name given to new() will be displayed when the version or help flags are used. +    App::new("MyApp") +        .version("1.0") +        .author("Kevin K. <kbknapp@gmail.com>") +        .about("Does awesome things") +        .get_matches(); + +    // This example doesn't do much, but it *does* give automatic -h, --help, -V, and --version functionality ;) + +    // Continued program logic goes here... +} diff --git a/clap/examples/03_args.rs b/clap/examples/03_args.rs new file mode 100644 index 0000000..c62d576 --- /dev/null +++ b/clap/examples/03_args.rs @@ -0,0 +1,84 @@ +extern crate clap; + +use clap::{App, Arg}; + +fn main() { +    // Args describe a possible valid argument which may be supplied by the user at runtime. There +    // are three different types of arguments (flags, options, and positional) as well as a fourth +    // special type of argument, called SubCommands (which will be discussed separately). +    // +    // Args are described in the same manner as Apps using the "builder pattern" with multiple +    // methods describing various settings for the individual arguments. Or by supplying a "usage" +    // string. Both methods have their pros and cons. +    // +    // Arguments can be added to applications in two manners, one at a time with the arg(), and +    // arg_from_usage() method, or multiple arguments at once via a Vec<Arg> inside the args() method, +    // or a single &str describing multiple Args (one per line) supplied to args_from_usage(). +    // +    // There are various options which can be set for a given argument, some apply to any of the +    // three types of arguments, some only apply one or two of the types. *NOTE* if you set +    // incompatible options on a single argument, clap will panic! at runtime. This is by design, +    // so that you know right away an error was made by the developer, not the end user. +    // +    // # Help and Version +    // clap automatically generates a help and version flag for you, unless you specify your +    // own. By default help uses "-h" and "--help", and version uses "-V" and "--version". You can +    // safely override "-V" and "-h" to your own arguments, and "--help" and "--version" will still +    // be automatically generated for you. +    let matches = App::new("MyApp") +                        // All application settings go here... + +                        // A simple "Flag" argument example (i.e. "-d") using the builder pattern +                        .arg(Arg::with_name("debug") +                                    .help("turn on debugging information") +                                    .short("d")) + +                        // Two arguments, one "Option" argument (i.e. one that takes a value) such +                        // as "-c some", and one positional argument (i.e. "myapp some_file") +                        .args(&[ +                            Arg::with_name("config") +                                    .help("sets the config file to use") +                                    .takes_value(true) +                                    .short("c") +                                    .long("config"), +                            Arg::with_name("input") +                                    .help("the input file to use") +                                    .index(1) +                                    .required(true) +                        ]) + +                        // *Note* the following two examples are convenience methods, if you wish +                        // to still get the full configurability of Arg::with_name() and the readability +                        // of arg_from_usage(), you can instantiate a new Arg with Arg::from_usage() and +                        // still be able to set all the additional properties, just like Arg::with_name() +                        // +                        // +                        // One "Flag" using a usage string +                        .arg_from_usage("--license 'display the license file'") + +                        // Two args, one "Positional", and one "Option" using a usage string +                        .args_from_usage("[output] 'Supply an output file to use' +                                          -i, --int=[IFACE] 'Set an interface to use'") +                        .get_matches(); + +    // Here are some examples of using the arguments defined above. Keep in mind that this is only +    // an example, and may be somewhat contrived +    // +    // First we check if debugging should be on or not +    println!("Debugging mode is: {}", if matches.is_present("debug") { "ON" } else { "OFF" }); + +    // Next we print the config file we're using, if any was defined with either -c <file> or +    // --config <file> +    if let Some(config) = matches.value_of("config") { +        println!("A config file was passed in: {}", config); +    } + +    // Let's print the <INPUT> file the user passed in. We can use .unwrap() here becase the arg is +    // required, and parsing would have failed if the user forgot it +    println!("Using input file: {}", matches.value_of("input").unwrap()); + +    // We could continue checking for and using arguments in this manner, such as "license", +    // "output", and "interface". Keep in mind that "output" and "interface" are optional, so you +    // shouldn't call .unwrap(). Instead, prefer using an 'if let' expression as we did with +    // "config" +} diff --git a/clap/examples/04_using_matches.rs b/clap/examples/04_using_matches.rs new file mode 100644 index 0000000..a0a986f --- /dev/null +++ b/clap/examples/04_using_matches.rs @@ -0,0 +1,54 @@ +extern crate clap; + +use clap::{App, Arg}; + +fn main() { + +    // Once all App settings (including all arguments) have been set, you call get_matches() which +    // parses the string provided by the user, and returns all the valid matches to the ones you +    // specified. +    // +    // You can then query the matches struct to get information about how the user ran the program +    // at startup. +    // +    // For this example, let's assume you created an App which accepts three arguments (plus two +    // generated by clap), a flag to display debugging information triggered with "-d" or +    // "--debug" as well as an option argument which specifies a custom configuration file to use +    // triggered with "-c file" or "--config file" or "--config=file" and finally a positional +    // argument which is the input file we want to work with, this will be the only required +    // argument. +    let matches = App::new("MyApp") +                        .about("Parses an input file to do awesome things") +                        .version("1.0") +                        .author("Kevin K. <kbknapp@gmail.com>") +                        .arg(Arg::with_name("debug") +                                    .help("turn on debugging information") +                                    .short("d") +                                    .long("debug")) +                        .arg(Arg::with_name("config") +                                    .help("sets the config file to use") +                                    .short("c") +                                    .long("config")) +                        .arg(Arg::with_name("input") +                                    .help("the input file to use") +                                    .index(1) +                                    .required(true)) +                        .get_matches(); + +    // We can find out whether or not debugging was turned on +    if matches.is_present("debug") { +        println!("Debugging is turned on"); +    } + +    // If we wanted to do some custom initialization based off some configuration file +    // provided by the user, we could get the file (A string of the file) +    if let Some(file) = matches.value_of("config") { +        println!("Using config file: {}", file); +    } + +    // Because "input" is required we can safely call unwrap() because had the user NOT +    // specified a value, clap would have explained the error the user, and exited. +    println!("Doing real work with file: {}", matches.value_of("input").unwrap() ); + +    // Continued program logic goes here... +} diff --git a/clap/examples/05_flag_args.rs b/clap/examples/05_flag_args.rs new file mode 100644 index 0000000..a6b8945 --- /dev/null +++ b/clap/examples/05_flag_args.rs @@ -0,0 +1,56 @@ +extern crate clap; + +use clap::{App, Arg}; + +fn main() { + +    // Of the three argument types, flags are the most simple. Flags are simple switches which can +    // be either "on" or "off" +    // +    // clap also supports multiple occurrences of flags, the common example is "verbosity" where a +    // user could want a little information with "-v" or tons of information with "-v -v" or "-vv" +    let matches = App::new("MyApp") +                        // Regular App configuration goes here... + +                        // We'll add a flag that represents an awesome meter... +                        // +                        // I'll explain each possible setting that "flags" accept. Keep in mind +                        // that you DO NOT need to set each of these for every flag, only the ones +                        // you want for your individual case. +                        .arg(Arg::with_name("awesome") +                                    .help("turns up the awesome") // Displayed when showing help info +                                    .short("a")                   // Trigger this arg with "-a" +                                    .long("awesome")              // Trigger this arg with "--awesome" +                                    .multiple(true)               // This flag should allow multiple +                                                                  // occurrences such as "-aaa" or "-a -a" +                                    .requires("config")           // Says, "If the user uses -a, they MUST +                                                                  // also use this other 'config' arg too" +                                                                  // Can also specify a list using +                                                                  // requires_all(Vec<&str>) +                                    .conflicts_with("output")     // Opposite of requires(), says "if the +                                                                  // user uses -a, they CANNOT use 'output'" +                                                                  // also has a conflicts_with_all(Vec<&str>) +                        ) +                        // NOTE: In order to compile this example, comment out requires() and +                        // conflicts_with() because we have not defined an "output" or "config" +                        // argument. +                        .get_matches(); + +    // We can find out whether or not awesome was used +    if matches.is_present("awesome") { +        println!("Awesomeness is turned on"); +    } + +    // If we set the multiple() option of a flag we can check how many times the user specified +    // +    // Note: if we did not specify the multiple() option, and the user used "awesome" we would get +    // a 1 (no matter how many times they actually used it), or a 0 if they didn't use it at all +    match matches.occurrences_of("awesome") { +        0 => println!("Nothing is awesome"), +        1 => println!("Some things are awesome"), +        2 => println!("Lots of things are awesome"), +        3 | _ => println!("EVERYTHING is awesome!"), +    } + +    // Continued program logic goes here... +} diff --git a/clap/examples/06_positional_args.rs b/clap/examples/06_positional_args.rs new file mode 100644 index 0000000..1f29612 --- /dev/null +++ b/clap/examples/06_positional_args.rs @@ -0,0 +1,56 @@ +extern crate clap; + +use clap::{App, Arg}; + +fn main() { + +    // Positional arguments are those values after the program name which are not preceded by any +    // identifier (such as "myapp some_file"). Positionals support many of the same options as +    // flags, as well as a few additional ones. +    let matches = App::new("MyApp") +                        // Regular App configuration goes here... + +                        // We'll add two positional arguments, a input file, and a config file. +                        // +                        // I'll explain each possible setting that "positionals" accept. Keep in +                        // mind that you DO NOT need to set each of these for every flag, only the +                        // ones that apply to your individual case. +                        .arg(Arg::with_name("input") +                                    .help("the input file to use") // Displayed when showing help info +                                    .index(1)                      // Set the order in which the user must +                                                                   // specify this argument (Starts at 1) +                                    .requires("config")            // Says, "If the user uses "input", they MUST +                                                                   // also use this other 'config' arg too" +                                                                   // Can also specify a list using +                                                                   // requires_all(Vec<&str>) +                                    .conflicts_with("output")      // Opposite of requires(), says "if the +                                                                   // user uses -a, they CANNOT use 'output'" +                                                                   // also has a conflicts_with_all(Vec<&str>) +                                    .required(true)                // By default this argument MUST be present +                                                                   // NOTE: mutual exclusions take precedence over +                                                                   // required arguments +                        ) +                        .arg(Arg::with_name("config") +                                    .help("the config file to use") +                                    .index(2))                     // Note, we do not need to specify required(true) +                                                                   // if we don't want to, because "input" already +                                                                   // requires "config" +                                                                   // Note, we also do not need to specify requires("input") +                                                                   // because requires lists are automatically two-way + +                        // NOTE: In order to compile this example, comment out conflicts_with() +                        // because we have not defined an "output" argument. +                        .get_matches(); + +    // We can find out whether or not "input" or "config" were used +    if matches.is_present("input") { +        println!("An input file was specified"); +    } + +    // We can also get the values for those arguments +    if let Some(in_file) = matches.value_of("input") { +        // It's safe to call unwrap() because of the required options we set above +        println!("Doing work with {} and {}", in_file, matches.value_of("config").unwrap()); +    } +    // Continued program logic goes here... +} diff --git a/clap/examples/07_option_args.rs b/clap/examples/07_option_args.rs new file mode 100644 index 0000000..85ff0e5 --- /dev/null +++ b/clap/examples/07_option_args.rs @@ -0,0 +1,71 @@ +extern crate clap; + +use clap::{App, Arg}; + +fn main() { + +    // Option arguments are those that take an additional value, such as "-c value". In clap they +    // support three types of specification, those with short() as "-o some", or those with long() +    // as "--option value" or "--option=value" +    // +    // Options also support a multiple setting, which is discussed in the example below. +    let matches = App::new("MyApp") +                        // Regular App configuration goes here... + +                        // Assume we have an application that accepts an input file via the "-i file" +                        // or the "--input file" (as well as "--input=file"). +                        // Below every setting supported by option arguments is discussed. +                        // NOTE: You DO NOT need to specify each setting, only those which apply +                        // to your particular case. +                        .arg(Arg::with_name("input") +                                    .help("the input file to use") // Displayed when showing help info +                                    .takes_value(true)             // MUST be set to true in order to be an "option" argument +                                    .short("i")                    // This argument is triggered with "-i" +                                    .long("input")                 // This argument is triggered with "--input" +                                    .multiple(true)                // Set to true if you wish to allow multiple occurrences +                                                                   // such as "-i file -i other_file -i third_file" +                                    .required(true)                // By default this argument MUST be present +                                                                   // NOTE: mutual exclusions take precedence over +                                                                   // required arguments +                                    .requires("config")            // Says, "If the user uses "input", they MUST +                                                                   // also use this other 'config' arg too" +                                                                   // Can also specify a list using +                                                                   // requires_all(Vec<&str>) +                                    .conflicts_with("output")      // Opposite of requires(), says "if the +                                                                   // user uses -a, they CANNOT use 'output'" +                                                                   // also has a conflicts_with_all(Vec<&str>) +                        ) +                        // NOTE: In order to compile this example, comment out conflicts_with() +                        // and requires() because we have not defined an "output" or "config" +                        // argument. +                        .get_matches(); + +    // We can find out whether or not "input" was used +    if matches.is_present("input") { +        println!("An input file was specified"); +    } + +    // We can also get the value for "input" +    // +    // NOTE: If we specified multiple(), this will only return the _FIRST_ +    // occurrence +    if let Some(in_file) = matches.value_of("input") { +        println!("An input file: {}", in_file); +    } + +    // If we specified the multiple() setting we can get all the values +    if let Some(in_v) = matches.values_of("input") { +        for in_file in in_v { +            println!("An input file: {}", in_file); +        } +    } + +    // We can see how many times the option was used with the occurrences_of() method +    // +    // NOTE: Just like with flags, if we did not specify the multiple() setting this will only +    // return 1 no matter how many times the argument was used (unless it wasn't used at all, in +    // in which case 0 is returned) +    println!("The \"input\" argument was used {} times", matches.occurrences_of("input")); + +    // Continued program logic goes here... +} diff --git a/clap/examples/08_subcommands.rs b/clap/examples/08_subcommands.rs new file mode 100644 index 0000000..73bd098 --- /dev/null +++ b/clap/examples/08_subcommands.rs @@ -0,0 +1,57 @@ +extern crate clap; + +use clap::{App, Arg, SubCommand}; + +fn main() { + +    // SubCommands function exactly like sub-Apps, because that's exactly what they are. Each +    // instance of a SubCommand can have it's own version, author(s), Args, and even it's own +    // subcommands. +    // +    // # Help and Version +    // Just like Apps, each subcommand will get it's own "help" and "version" flags automatically +    // generated. Also, like Apps, you can override "-V" or "-h" safely and still get "--help" and +    // "--version" auto generated. +    // +    // NOTE: If you specify a subcommand for your App, clap will also autogenerate a "help" +    // subcommand along with "-h" and "--help" (applies to sub-subcommands as well). +    // +    // Just like arg() and args(), subcommands can be specified one at a time via subcommand() or +    // multiple ones at once with a Vec<SubCommand> provided to subcommands(). +    let matches = App::new("MyApp") +                        // Normal App and Arg configuration goes here... + +                        // In the following example assume we wanted an application which +                        // supported an "add" subcommand, this "add" subcommand also took +                        // one positional argument of a file to add: +                        .subcommand(SubCommand::with_name("add")                        // The name we call argument with +                                                .about("Adds files to myapp")           // The message displayed in "myapp -h" +                                                                                        // or "myapp help" +                                                .version("0.1")                         // Subcommands can have independent version +                                                .author("Kevin K.")                     // And authors +                                                .arg(Arg::with_name("input")            // And their own arguments +                                                            .help("the file to add") +                                                            .index(1) +                                                            .required(true))) +                        .get_matches(); + +    // You can check if a subcommand was used like normal +    if matches.is_present("add") { +        println!("'myapp add' was run."); +    } + +    // You can get the independent subcommand matches (which function exactly like App matches) +    if let Some(matches) = matches.subcommand_matches("add") { +        // Safe to use unwrap() because of the required() option +        println!("Adding file: {}", matches.value_of("input").unwrap()); +    } + +    // You can also match on a subcommand's name +    match matches.subcommand_name() { +        Some("add") => println!("'myapp add' was used"), +        None        => println!("No subcommand was used"), +        _           => println!("Some other subcommand was used"), +    } + +    // Continued program logic goes here... +} diff --git a/clap/examples/09_auto_version.rs b/clap/examples/09_auto_version.rs new file mode 100644 index 0000000..dfd221f --- /dev/null +++ b/clap/examples/09_auto_version.rs @@ -0,0 +1,29 @@ +#[macro_use] +extern crate clap; + +use clap::App; + +fn main() { +    // You can have clap pull the application version directly from your Cargo.toml starting with +    // clap v0.4.14 on crates.io (or master#a81f915 on github). Using Rust's env! macro like this: +    // +    // let version = format!("{}.{}.{}{}", +    //                  env!("CARGO_PKG_VERSION_MAJOR"), +    //                  env!("CARGO_PKG_VERSION_MINOR"), +    //                  env!("CARGO_PKG_VERSION_PATCH"), +    //                  option_env!("CARGO_PKG_VERSION_PRE").unwrap_or("")); +    // +    // Starting from v0.6.6 on crates.io you can also use the crate_version!() macro instead of +    // manually using the env!() macros. Under the hood, the macro uses this exact method to get +    // the version. +    // +    // Thanks to https://github.com/jhelwig for pointing this out +    App::new("myapp") +        .about("does awesome things") +       // use crate_version! to pull the version number +       .version(crate_version!()) +       .get_matches(); + +    // running this app with the -V or --version will display whatever version is in your +    // Cargo.toml, the default being: myapp 0.0.1 +} diff --git a/clap/examples/10_default_values.rs b/clap/examples/10_default_values.rs new file mode 100644 index 0000000..ca50981 --- /dev/null +++ b/clap/examples/10_default_values.rs @@ -0,0 +1,40 @@ +extern crate clap; + +use clap::{App, Arg}; + +fn main() { +    // There are two ways in which to get a default value, one is to use claps Arg::default_value +    // method, and the other is to use Rust's built in Option::unwrap_or method. +    // +    // I'll demo both here. +    // +    // First, we'll use clap's Arg::default_value with an "INPUT" file. +    let matches = App::new("myapp").about("does awesome things") +                        .arg(Arg::with_name("INPUT") +                                .help("The input file to use") // Note, we don't need to specify +                                                               // anything like, "Defaults to..." +                                                               // because clap will automatically +                                                               // generate that for us, and place +                                                               // it in the help text +                                .default_value("input.txt") +                                .index(1)) + +                        // Next we'll use the Option::unwrap_or method on this "CONFIG" option +                        .arg(Arg::with_name("CONFIG") +                                // Note that we have to manually include some verbiage to the user +                                // telling them what the default will be. +                                .help("The config file to use (default is \"config.json\")") +                                .short("c") +                                .takes_value(true)) +                        .get_matches(); + +    // It's safe to call unwrap because the value with either be what the user input at runtime +    // or "input.txt" +    let input = matches.value_of("INPUT").unwrap(); + +    // Using Option::unwrap_or we get the same affect, but without the added help text injection +    let config_file = matches.value_of("CONFIG").unwrap_or("config.json"); + +    println!("The input file is: {}", input); +    println!("The config file is: {}", config_file); +} diff --git a/clap/examples/11_only_specific_values.rs b/clap/examples/11_only_specific_values.rs new file mode 100644 index 0000000..3445218 --- /dev/null +++ b/clap/examples/11_only_specific_values.rs @@ -0,0 +1,33 @@ +extern crate clap; + +use clap::{App, Arg}; + +fn main() { +    // If you have arguments of specific values you want to test for, you can use the +    // .possible_values() method of Arg +    // +    // This allows you specify the valid values for that argument. If the user does not use one of +    // those specific values, they will receive a graceful exit with error message informing them +    // of the mistake, and what the possible valid values are +    // +    // For this example, assume you want one positional argument of either "fast" or "slow" +    // i.e. the only possible ways to run the program are "myprog fast" or "myprog slow" +    let matches = App::new("myapp").about("does awesome things") +                        .arg(Arg::with_name("MODE") +                                .help("What mode to run the program in") +                                .index(1) +                                .possible_values(&["fast", "slow"]) +                                .required(true)) +                        .get_matches(); + +    // Note, it's safe to call unwrap() because the arg is required +    match matches.value_of("MODE").unwrap() { +        "fast" => { +            // Do fast things... +        }, +        "slow" => { +            // Do slow things... +        }, +        _      => unreachable!() +    } +} diff --git a/clap/examples/12_typed_values.rs b/clap/examples/12_typed_values.rs new file mode 100644 index 0000000..3d03e4f --- /dev/null +++ b/clap/examples/12_typed_values.rs @@ -0,0 +1,50 @@ +#[macro_use] +extern crate clap; + +use clap::App; + +fn main() { +    // You can use some convenience macros provided by clap to get typed values, so long as the +    // type you specify implements std::str::FromStr +    // +    // This works for both single, and multiple values (multiple values returns a Vec<T>) +    // +    // There are also two ways in which to get types, those where failures cause the program to exit +    // with an error and usage string, and those which return a Result<T,String> or Result<Vec<T>,String> +    // respectively. Both methods support single and multiple values. +    // +    // The macro which returns a Result allows you decide what to do upon a failure, exit, provide a +    // default value, etc. You have control. But it also means you have to write the code or boiler plate +    // to handle those instances. +    // +    // That is why the second method exists, so you can simply get a T or Vec<T> back, or be sure the +    // program will exit gracefully. The catch is, the second method should *only* be used on required +    // arguments, because if the argument isn't found, it exits. Just FYI ;) +    // +    // The following example shows both methods. +    // +    // **NOTE:** to use the macros, you must include #[macro_use] just above the 'extern crate clap;' +    // declaration in your crate root. +    let matches = App::new("myapp") +                        // Create two arguments, a required positional which accepts multiple values +                        // and an optional '-l value' +                        .args_from_usage( +                            "<seq>... 'A sequence of whole positive numbers, i.e. 20 25 30' +                            -l [len] 'A length to use, defaults to 10 when omitted'") +                        .get_matches(); + +    // Here we get a value of type u32 from our optional -l argument. +    // If the value provided to len fails to parse, we default to 10 +    // +    // Using other methods such as unwrap_or_else(|e| println!("{}",e)) +    // are possible too. +    let len = value_t!(matches, "len", u32).unwrap_or(10); + +    println!("len ({}) + 2 = {}", len, len + 2); + +    // This code loops through all the values provided to "seq" and adds 2 +    // If seq fails to parse, the program exits, you don't have an option +    for v in values_t!(matches, "seq", u32).unwrap_or_else(|e| e.exit()) { +        println!("Sequence part {} + 2: {}", v, v + 2); +    } +} diff --git a/clap/examples/13a_enum_values_automatic.rs b/clap/examples/13a_enum_values_automatic.rs new file mode 100644 index 0000000..1abe5cb --- /dev/null +++ b/clap/examples/13a_enum_values_automatic.rs @@ -0,0 +1,68 @@ +// You can use clap's value_t! macro with a custom enum by implementing the std::str::FromStr +// trait which is very straight forward. There are three ways to do this, for simple enums +// meaning those that don't require 'pub' or any '#[derive()]' directives you can use clap's +// simple_enum! macro. For those that require 'pub' or any '#[derive()]'s you can use clap's +// arg_enum! macro. The third way is to implement std::str::FromStr manually. +// +// In most circumstances using either simple_enum! or arg_enum! is fine. +// +// In the following example we will create two enums using macros, assign a positional argument +// that accepts only one of those values, and use clap to parse the argument. + +// Add clap like normal +#[macro_use] +extern crate clap; + +use clap::{App, Arg}; + +// Using arg_enum! is more like traditional enum declarations +// +// **NOTE:** Only bare variants are supported +arg_enum!{ +    #[derive(Debug)] +    pub enum Oof { +        Rab, +        Zab, +        Xuq +    } +} + +arg_enum!{ +    #[derive(Debug)] +    enum Foo { +        Bar, +        Baz, +        Qux +    } +} + +fn main() { +    // Create the application like normal +    let enum_vals = ["fast", "slow"]; +    let m = App::new("myapp") +                    // Use a single positional argument that is required +                    .arg(Arg::from_usage("<foo> 'The Foo to use'") +                        .possible_values(&Foo::variants())) +                    .arg(Arg::from_usage("<speed> 'The speed to use'") +                            // You can define a list of possible values if you want the values to be +                            // displayed in the help information. Whether you use possible_values() or +                            // not, the valid values will ALWAYS be displayed on a failed parse. +                            .possible_values(&enum_vals)) +                    // For the second positional, lets not use possible_values() just to show the difference +                    .arg_from_usage("<oof> 'The Oof to use'") +                    .get_matches(); + +    let t = value_t!(m.value_of("foo"), Foo).unwrap_or_else(|e| e.exit()); +    let t2 = value_t!(m.value_of("oof"), Oof).unwrap_or_else(|e| e.exit()); + + +    // Now we can use our enum like normal. +    match t { +        Foo::Bar => println!("Found a Bar"), +        Foo::Baz => println!("Found a Baz"), +        Foo::Qux => println!("Found a Qux") +    } + +    // Since our Oof derives Debug, we can do this: +    println!("Oof: {:?}", t2); +} diff --git a/clap/examples/13b_enum_values_manual.rs b/clap/examples/13b_enum_values_manual.rs new file mode 100644 index 0000000..81ffe5e --- /dev/null +++ b/clap/examples/13b_enum_values_manual.rs @@ -0,0 +1,54 @@ +// In the following example we will create an enum with 4 values, assign a positional argument +// that accepts only one of those values, and use clap to parse the argument. +// +// Start with bringing the trait into scope. +use std::str::FromStr; + +// Add clap like normal +#[macro_use] +extern crate clap; + +use clap::{App, Arg}; + +// Define your enum +enum Vals { +    Foo, +    Bar, +    Baz, +    Qux +} + +// Implement the trait +impl FromStr for Vals { +    type Err = &'static str; + +    fn from_str(s: &str) -> Result<Self, Self::Err> { +        match s { +            "Foo" => Ok(Vals::Foo), +            "Bar" => Ok(Vals::Bar), +            "Baz" => Ok(Vals::Baz), +            "Qux" => Ok(Vals::Qux), +            _     => Err("no match") +        } +    } +} + +fn main() { +    // Create the application like normal +    let m = App::new("myapp") +                    // Use a single positional argument that is required +                    .arg(Arg::from_usage("<type> 'The type to use'") +                            // Define the list of possible values +                            .possible_values(&["Foo", "Bar", "Baz", "Qux"])) +                    .get_matches(); + +    let t = value_t!(m, "type", Vals).unwrap_or_else(|e| e.exit()); + +    // Now we can use our enum like normal. +    match t { +        Vals::Foo => println!("Found a Foo"), +        Vals::Bar => println!("Found a Bar"), +        Vals::Baz => println!("Found a Baz"), +        Vals::Qux => println!("Found a Qux") +    } +} diff --git a/clap/examples/14_groups.rs b/clap/examples/14_groups.rs new file mode 100644 index 0000000..e160464 --- /dev/null +++ b/clap/examples/14_groups.rs @@ -0,0 +1,87 @@ +/// `ArgGroup`s are a family of related arguments and way for you to say, "Any of these arguments". +/// By placing arguments in a logical group, you can make easier requirement and exclusion rules +/// instead of having to list each individually, or when you want a rule to apply "any but not all" +/// arguments. +/// +/// For instance, you can make an entire `ArgGroup` required, this means that one (and *only* one) +/// argument from that group must be present. Using more than one argument from an `ArgGroup` causes +/// a failure (graceful exit). +/// +/// You can also do things such as name an `ArgGroup` as a confliction or requirement, meaning any +/// of the arguments that belong to that group will cause a failure if present, or must present +/// respectively. +/// +/// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be +/// present out of a given set. Imagine that you had multiple arguments, and you want one of them to +/// be required, but making all of them required isn't feasible because perhaps they conflict with +/// each other. For example, lets say that you were building an application where one could set a +/// given version number by supplying a string with an option argument, i.e. `--set-ver v1.2.3`, you +/// also wanted to support automatically using a previous version number and simply incrementing one +/// of the three numbers. So you create three flags `--major`, `--minor`, and `--patch`. All of +/// these arguments shouldn't be used at one time but you want to specify that *at least one* of +/// them is used. For this, you can create a group. + +extern crate clap; + +use clap::{App, Arg, ArgGroup}; + +fn main() { +    // Create application like normal +    let matches = App::new("myapp") +                      // Add the version arguments +                      .args_from_usage("--set-ver [ver] 'set version manually' +                                        --major         'auto inc major' +                                        --minor         'auto inc minor' +                                        --patch         'auto inc patch'") +                      // Create a group, make it required, and add the above arguments +                      .group(ArgGroup::with_name("vers") +                                          .required(true) +                                          .args(&["ver", "major", "minor", "patch"])) +                      // Arguments can also be added to a group individually, these two arguments +                      // are part of the "input" group which is not required +                      .arg(Arg::from_usage("[INPUT_FILE] 'some regular input'") +                        .group("input")) +                      .arg(Arg::from_usage("--spec-in [SPEC_IN] 'some special input argument'") +                        .group("input")) +                      // Now let's assume we have a -c [config] argument which requires one of +                      // (but **not** both) the "input" arguments +                      .arg(Arg::with_name("config") +                        .short("c") +                        .takes_value(true) +                        .requires("input")) +                      .get_matches(); + +    // Let's assume the old version 1.2.3 +    let mut major = 1; +    let mut minor = 2; +    let mut patch = 3; + +    // See if --set-ver was used to set the version manually +    let version = if let Some(ver) = matches.value_of("ver") { +        format!("{}", ver) +    } else { +        // Increment the one requested (in a real program, we'd reset the lower numbers) +        let (maj, min, pat) = (matches.is_present("major"), +                                     matches.is_present("minor"), +                                     matches.is_present("patch")); +        match (maj, min, pat) { +            (true, _, _) => major += 1, +            (_, true, _) => minor += 1, +            (_, _, true) => patch += 1, +            _            => unreachable!(), +        }; +        format!("{}.{}.{}", major, minor, patch) +    }; + +    println!("Version: {}", version); + +    // Check for usage of -c +    if matches.is_present("config") { +        let input = matches.value_of("INPUT_FILE").unwrap_or(matches.value_of("SPEC_IN").unwrap()); +        println!("Doing work using input {} and config {}", +                                                     input, +                                                     matches.value_of("config").unwrap()); +    } + + +} diff --git a/clap/examples/15_custom_validator.rs b/clap/examples/15_custom_validator.rs new file mode 100644 index 0000000..a5c0d42 --- /dev/null +++ b/clap/examples/15_custom_validator.rs @@ -0,0 +1,37 @@ +extern crate clap; + +use clap::{App, Arg}; + +fn main() { +    // You can define a function (or a closure) to use as a validator to argument values. The +    // function must accept a String and return Result<(), String> where Err(String) is the message +    // displayed to the user. + +    let matches = App::new("myapp") +                        // Application logic goes here... +                        .arg(Arg::with_name("input") +                                     .help("the input file to use") +                                     .index(1) +                                     .required(true) +                                     // You can pass in a closure, or a function +                                     .validator(is_png)) +                        .get_matches(); + +    // Here we can call .unwrap() because the argument is required. +    println!("The .PNG file is: {}", matches.value_of("input").unwrap()); +} + +fn is_png(val: String) -> Result<(), String> { +    // val is the argument value passed in by the user +    // val has type of String. +    if val.ends_with(".png") { +        Ok(()) +    } else { +        // clap automatically adds "error: " to the beginning +        // of the message. +        Err(String::from("the file format must be png.")) +    } +    // Of course, you can do more complicated validation as +    // well, but for the simplicity, this example only checks +    // if the value passed in ends with ".png" or not. +} diff --git a/clap/examples/16_app_settings.rs b/clap/examples/16_app_settings.rs new file mode 100644 index 0000000..ab1d185 --- /dev/null +++ b/clap/examples/16_app_settings.rs @@ -0,0 +1,41 @@ +extern crate clap; + +use clap::{App, AppSettings, SubCommand}; + +fn main() { +    // You can use AppSettings to change the application level behavior of clap. .setting() function +    // of App struct takes AppSettings enum as argument. There is also .settings() function which +    // takes slice of AppSettings enum.  You can learn more about AppSettings in the documentation, +    // which also has examples on each setting. +    // +    // This example will only show usage of one AppSettings setting. See documentation for more +    // information. + +    let matches = App::new("myapp") +                        .setting(AppSettings::SubcommandsNegateReqs) +                                            // Negates requirement of parent command. + +                        .arg_from_usage("<input> 'input file to use'") +                                            // Required positional argument called input.  This +                                            // will be only required if subcommand is not present. + +                        .subcommand(SubCommand::with_name("test") +                                                .about("does some testing")) +                                            // if program is invoked with subcommand, you do not +                                            // need to specify the <input> argument anymore due to +                                            // the AppSettings::SubcommandsNegateReqs setting. + +                        .get_matches(); + +    // Calling unwrap() on "input" would not be advised here, because although it's required, +    // if the user uses a subcommand, those requirements are no longer required. Hence, we should +    // use some sort of 'if let' construct +    if let Some(inp) = matches.value_of("input") { +        println!("The input file is: {}", inp); +    } + +    match matches.subcommand() { +        ("test", _) => println!("The 'test' subcommand was used"), +        _           => unreachable!() +    } +} diff --git a/clap/examples/17_yaml.rs b/clap/examples/17_yaml.rs new file mode 100644 index 0000000..3353d73 --- /dev/null +++ b/clap/examples/17_yaml.rs @@ -0,0 +1,53 @@ +// In order to use YAML to define your CLI you must compile clap with the "yaml" feature because +// it's **not** included by default. +// +// In order to do this, ensure your Cargo.toml looks like one of the following: +// +// [dependencies.clap] +// features = ["yaml"] +// +// __OR__ +// +// [dependencies] +// clap = { features = ["yaml"] } + + +// Using yaml requires calling a clap macro `load_yaml!()` so we must use the '#[macro_use]' +// directive +#[macro_use] +extern crate clap; + +#[cfg(feature = "yaml")] +fn main() { +    use clap::App; + +    // To load a yaml file containing our CLI definition such as the example '17_yaml.yml' we can +    // use the convenience macro which loads the file at compile relative to the current file +    // similar to how modules are found. +    // +    // Then we pass that yaml object to App to build the CLI. +    // +    // Finally we call get_matches() to start the parsing process. We use the matches just as we +    // normally would +    let yml = load_yaml!("17_yaml.yml"); +    let m = App::from_yaml(yml).get_matches(); + +    // Because the example 17_yaml.yml is rather large we'll just look a single arg so you can +    // see that it works... +    if let Some(mode) = m.value_of("mode") { +        match mode { +            "vi" => println!("You are using vi"), +            "emacs" => println!("You are using emacs..."), +            _      => unreachable!() +        } +    } else { +        println!("--mode <MODE> wasn't used..."); +    } +} + +#[cfg(not(feature = "yaml"))] +fn main() { +    // As stated above, if clap is not compiled with the YAML feature, it is disabled. +    println!("YAML feature is disabled."); +    println!("Pass --features yaml to cargo when trying this example."); +} diff --git a/clap/examples/17_yaml.yml b/clap/examples/17_yaml.yml new file mode 100644 index 0000000..b0d58b3 --- /dev/null +++ b/clap/examples/17_yaml.yml @@ -0,0 +1,97 @@ +name: yml_app +version: "1.0" +about: an example using a .yml file to build a CLI +author: Kevin K. <kbknapp@gmail.com> + +# AppSettings can be defined as a list and are **not** ascii case sensitive +settings: +    - ArgRequiredElseHelp + +# All Args must be defined in the 'args:' list where the name of the arg, is the +# key to a Hash object +args: +    # The name of this argument, is 'opt' which will be used to access the value +    # later in your Rust code +    - opt: +        help: example option argument from yaml +        short: o +        long: option +        multiple: true +        takes_value: true +    - pos: +        help: example positional argument from yaml +        index: 1 +        # A list of possible values can be defined as a list +        possible_values: +            - fast +            - slow +    - flag: +        help: demo flag argument +        short: F +        multiple: true +        global: true +        # Conflicts, mutual overrides, and requirements can all be defined as a +        # list, where the key is the name of the other argument +        conflicts_with: +            - opt +        requires: +            - pos +    - mode: +        long: mode +        help: shows an option with specific values +        # possible_values can also be defined in this list format +        possible_values: [ vi, emacs ] +        takes_value: true +    - mvals: +        long: mult-vals +        help: demos an option which has two named values +        # value names can be described in a list, where the help will be shown +        # --mult-vals <one> <two> +        value_names: +            - one +            - two +    - minvals: +        long: min-vals +        multiple: true +        help: you must supply at least two values to satisfy me +        min_values: 2 +    - maxvals: +        long: max-vals +        multiple: true +        help: you can only supply a max of 3 values for me! +        max_values: 3 + +# All subcommands must be listed in the 'subcommand:' object, where the key to +# the list is the name of the subcommand, and all settings for that command are +# are part of a Hash object +subcommands: +    # The name of this subcommand will be 'subcmd' which can be accessed in your +    # Rust code later +    - subcmd: +        about: demos subcommands from yaml +        version: "0.1" +        author: Kevin K. <kbknapp@gmail.com> +        # Subcommand args are exactly like App args +        args: +            - scopt: +                short: B +                multiple: true +                help: example subcommand option +                takes_value: true +            - scpos1: +                help: example subcommand positional +                index: 1 + +# ArgGroups are supported as well, and must be sepcified in the 'groups:' +# object of this file +groups: +    # the name of the ArgGoup is specified here +    - min-max-vals: +        # All args and groups that are a part of this group are set here +        args: +            - minvals +            - maxvals +        # setting conflicts is done the same manner as setting 'args:' +        # +        # to make this group required, you could set 'required: true' but for +        # this example we won't do that. diff --git a/clap/examples/18_builder_macro.rs b/clap/examples/18_builder_macro.rs new file mode 100644 index 0000000..6bdce47 --- /dev/null +++ b/clap/examples/18_builder_macro.rs @@ -0,0 +1,84 @@ +#[macro_use] +extern crate clap; + +// Note, there isn't a need for "use clap::{ ... };" Because the clap_app! macro uses +// $crate:: internally + +fn main() { + +    // Validation example testing that a file exists +    let file_exists = |path| { +        if std::fs::metadata(path).is_ok() { +            Ok(()) +        } else { +            Err(String::from("File doesn't exist")) +        } +    }; + +    // External module may contain this subcommand. If this exists in another module, a function is +    // required to access it. Recommend `fn clap() -> Clap::SubCommand`. +    let external_sub_command = clap_app!( @subcommand foo => +        (@arg bar: -b "Bar") +    ); + +    let matches = clap_app!(MyApp => +        (@setting SubcommandRequiredElseHelp) +        (version: "1.0") +        (author: "Alice") +        (about: "Does awesome things") +        (@arg config: -c --config <conf> #{1, 2} {file_exists} "Sets a custom config file") +        (@arg proxyHostname: --("proxy-hostname") +takes_value "Sets the hostname of the proxy to use") +        (@arg input: * "Input file") +        (@group test => +            (@attributes +required) +            (@arg output: "Sets an optional output file") +            (@arg debug: -d ... "Turn debugging information on") +        ) +        (subcommand: external_sub_command) +        (@subcommand test => +            (about: "does testing things") +            (version: "2.5") +            (@arg list: -l "Lists test values") +            (@arg test_req: -r requires[list] "Tests requirement for listing") +            (@arg aaaa: --aaaa +takes_value { +                    |a| if a.contains('a') { +                        Ok(()) +                    } else { +                        Err(String::from("string does not contain at least one a")) +                    } +                } "Test if the argument contains an a") +        ) +    ).get_matches(); + +    // You can check the value provided by positional arguments, or option arguments +    if let Some(o) = matches.value_of("output") { +        println!("Value for output: {}", o); +    } + +    if let Some(c) = matches.value_of("config") { +        println!("Value for config: {}", c); +    } + +    // You can see how many times a particular flag or argument occurred +    // Note, only flags can have multiple occurrences +    match matches.occurrences_of("debug") { +        0 => println!("Debug mode is off"), +        1 => println!("Debug mode is kind of on"), +        2 => println!("Debug mode is on"), +        3 | _ => println!("Don't be crazy"), +    } + +    // You can check for the existence of subcommands, and if found use their +    // matches just as you would the top level app +    if let Some(matches) = matches.subcommand_matches("test") { +        // "$ myapp test" was run +        if matches.is_present("list") { +            // "$ myapp test -l" was run +            println!("Printing testing lists..."); +        } else { +            println!("Not printing testing lists..."); +        } +    } + +    // Continued program logic goes here... +} diff --git a/clap/examples/19_auto_authors.rs b/clap/examples/19_auto_authors.rs new file mode 100644 index 0000000..afbb985 --- /dev/null +++ b/clap/examples/19_auto_authors.rs @@ -0,0 +1,15 @@ +#[macro_use] +extern crate clap; + +use clap::App; + +fn main() { +    App::new("myapp") +        .about("does awesome things") +       // use crate_authors! to pull the author(s) names from the Cargo.toml +       .author(crate_authors!()) +       .get_matches(); + +    // running this app with -h will display whatever author(s) are in your +    // Cargo.toml +} diff --git a/clap/examples/20_subcommands.rs b/clap/examples/20_subcommands.rs new file mode 100644 index 0000000..f80f46d --- /dev/null +++ b/clap/examples/20_subcommands.rs @@ -0,0 +1,143 @@ +// Working with subcommands is simple. There are a few key points to remember when working with +// subcommands in clap. First, SubCommands are really just Apps. This means they can have their own +// settings, version, authors, args, and even their own subcommands. The next thing to remember is +// that subcommands are set up in a tree like hierarchy. +// +// An ASCII art depiction may help explain this better. Using a fictional version of git as the demo +// subject. Imagine the following are all subcommands of git (note, the author is aware these aren't +// actually all subcommands in the real git interface, but it makes explanation easier) +// +//            Top Level App (git)                         TOP +//                           | +//    ----------------------------------------- +//   /             |                \          \ +// clone          push              add       commit      LEVEL 1 +//   |           /    \            /    \       | +//  url      origin   remote    ref    name   message     LEVEL 2 +//           /                  /\ +//        path            remote  local                   LEVEL 3 +// +// Given the above fictional subcommand hierarchy, valid runtime uses would be (not an all inclusive +// list): +// +// $ git clone url +// $ git push origin path +// $ git add ref local +// $ git commit message +// +// Notice only one command per "level" may be used. You could not, for example, do: +// +// $ git clone url push origin path +// +// It's also important to know that subcommands each have their own set of matches and may have args +// with the same name as other subcommands in a different part of the tree hierarchy (i.e. the arg +// names aren't in a flat namespace). +// +// In order to use subcommands in clap, you only need to know which subcommand you're at in your +// tree, and which args are defined on that subcommand. +// +// Let's make a quick program to illustrate. We'll be using the same example as above but for +// brevity sake we won't implement all of the subcommands, only a few. + +extern crate clap; + +use clap::{App, Arg, SubCommand, AppSettings}; + +fn main() { + +    let matches = App::new("git") +        .about("A fictional versioning CLI") +        .version("1.0") +        .author("Me") +        .subcommand(SubCommand::with_name("clone") +            .about("clones repos") +            .arg(Arg::with_name("repo") +                .help("The repo to clone") +                .required(true))) +        .subcommand(SubCommand::with_name("push") +            .about("pushes things") +            .setting(AppSettings::SubcommandRequiredElseHelp) +            .subcommand(SubCommand::with_name("remote")  // Subcommands can have their own subcommands, +                                                         // which in turn have their own subcommands +                .about("pushes remote things") +                .arg(Arg::with_name("repo") +                    .required(true) +                    .help("The remote repo to push things to"))) +            .subcommand(SubCommand::with_name("local") +                .about("pushes local things"))) +        .subcommand(SubCommand::with_name("add") +            .about("adds things") +            .author("Someone Else")                     // Subcommands can list different authors +            .version("v2.0 (I'm versioned differently") // or different version from their parents +            .setting(AppSettings::ArgRequiredElseHelp)  // They can even have different settings +            .arg(Arg::with_name("stuff") +                .long("stuff") +                .help("Stuff to add") +                .takes_value(true) +                .multiple(true))) +        .get_matches(); + +    // At this point, the matches we have point to git. Keep this in mind... + +    // You can check if one of git's subcommands was used +    if matches.is_present("clone") { +        println!("'git clone' was run."); +    } + +    // You can see which subcommand was used +    if let Some(subcommand) = matches.subcommand_name() { +        println!("'git {}' was used", subcommand); + +        // It's important to note, this *only* check's git's DIRECT children, **NOT** it's +        // grandchildren, great grandchildren, etc. +        // +        // i.e. if the command `git push remove --stuff foo` was run, the above will only print out, +        // `git push` was used. We'd need to get push's matches to see further into the tree +    } + +    // An alternative to checking the name is matching on known names. Again notice that only the +    // direct children are matched here. +    match matches.subcommand_name() { +        Some("clone") => println!("'git clone' was used"), +        Some("push") => println!("'git push' was used"), +        Some("add") => println!("'git add' was used"), +        None        => println!("No subcommand was used"), +        _           => unreachable!(), // Assuming you've listed all direct children above, this is unreachable +    } + +    // You could get the independent subcommand matches, although this is less common +    if let Some(clone_matches) = matches.subcommand_matches("clone") { +        // Now we have a reference to clone's matches +        println!("Cloning repo: {}", clone_matches.value_of("repo").unwrap()); +    } + +    // The most common way to handle subcommands is via a combined approach using +    // `ArgMatches::subcommand` which returns a tuple of both the name and matches +    match matches.subcommand() { +        ("clone", Some(clone_matches)) =>{ +            // Now we have a reference to clone's matches +            println!("Cloning {}", clone_matches.value_of("repo").unwrap()); +        }, +        ("push", Some(push_matches)) =>{ +            // Now we have a reference to push's matches +            match push_matches.subcommand() { +                ("remote", Some(remote_matches)) =>{ +                    // Now we have a reference to remote's matches +                    println!("Pushing to {}", remote_matches.value_of("repo").unwrap()); +                }, +                ("local", Some(_)) =>{ +                    println!("'git push local' was used"); +                }, +                _            => unreachable!(), +            } +        }, +        ("add", Some(add_matches)) =>{ +            // Now we have a reference to add's matches +            println!("Adding {}", add_matches.values_of("stuff").unwrap().collect::<Vec<_>>().join(", ")); +        }, +        ("", None)   => println!("No subcommand was used"), // If no subcommand was used it'll match the tuple ("", None) +        _            => unreachable!(), // If all subcommands are defined above, anything else is unreachable!() +    } + +    // Continued program logic goes here... +} diff --git a/clap/examples/21_aliases.rs b/clap/examples/21_aliases.rs new file mode 100644 index 0000000..3be0445 --- /dev/null +++ b/clap/examples/21_aliases.rs @@ -0,0 +1,39 @@ +extern crate clap; + +use clap::{App, Arg, SubCommand}; + +fn main() { + +    let matches = App::new("MyApp") +                        .subcommand(SubCommand::with_name("ls") +                                                .aliases(&["list", "dir"]) +                                                .about("Adds files to myapp") +                                                .version("0.1") +                                                .author("Kevin K.") +                                                .arg(Arg::with_name("input") +                                                            .help("the file to add") +                                                            .index(1) +                                                            .required(true)) +                                                ) +                        .get_matches(); + +    // You can check if a subcommand was used like normal +    if matches.is_present("add") { +        println!("'myapp add' was run."); +    } + +    // You can get the independent subcommand matches (which function exactly like App matches) +    if let Some(matches) = matches.subcommand_matches("add") { +        // Safe to use unwrap() because of the required() option +        println!("Adding file: {}", matches.value_of("input").unwrap()); +    } + +    // You can also match on a subcommand's name +    match matches.subcommand_name() { +        Some("add") => println!("'myapp add' was used"), +        None        => println!("No subcommand was used"), +        _           => println!("Some other subcommand was used"), +    } + +    // Continued program logic goes here... +} diff --git a/clap/examples/22_stop_parsing_with_--.rs b/clap/examples/22_stop_parsing_with_--.rs new file mode 100644 index 0000000..a5ba5b3 --- /dev/null +++ b/clap/examples/22_stop_parsing_with_--.rs @@ -0,0 +1,25 @@ +extern crate clap; + +use clap::{App, Arg}; + +/// myprog -f -p=bob -- sloppy slop slop +fn main() { + +    let matches = App::new("myprog") +        .arg(Arg::with_name("eff") +            .short("f")) +        .arg(Arg::with_name("pea") +             .short("p") +             .takes_value(true)) +        .arg(Arg::with_name("slop") +             .multiple(true) +             .last(true)) +        .get_matches(); + + +    println!("-f used: {:?}", matches.is_present("eff")); +    println!("-p's value: {:?}", matches.value_of("pea")); +    println!("'slops' values: {:?}", matches.values_of("slop").map(|vals| vals.collect::<Vec<_>>())); + +    // Continued program logic goes here... +} | 
