A week or two ago I started on creating a rust program that would accomplish two things:
- Improve my understanding of the package management system for Rust. More specifically, I wanted to understand how to organize modules a little bit better
- Create something that I could use to create challenges for myself using an automated and randomized method
I worked on it for a while and then get hung up on the specifics for parsing command line arguments. The approaches I thought about either seemed way too complicated, or were way too hacky to really be proud of writing them. I let the project for a sit for a little bit.
After some time, I realized that I could probably just outsource the parsing logic. Given that I was, at the time, the furthest from the first person ever needing to parse command line arguments, there had to be a library for it.
I was indeed correct and found clap. This library turned my project from a headache into a neat little organized oasis. More on that later. First, I’m gonna describe how the program works.
How the program works
The utility will look at a set of text files that you give it and create a set of challenges. For example, you could have some text files that describe pixel art challenges you can try.
theme.txt
Draw a house
Draw a mountain
Draw a bear
size.txt
at 128x64 pixels
at 256x128 pixels
at 64x64 pixels
palette.txt
with Midnight Ablaze Palette
with Oil 6 Palette
with Apollo Palette
with Spanish sunset palette
With these files in the root directory, you can run something like this:
cargo run -- -f theme.txt size.txt palette.txt -c 5
This will…
- Look through the listed files indicated by
-f
- Print out the challenges’ details in the order they were listed, randomly picking an entry in each file. This will be done five times, as indicated by the
-c 5
argument.--count
can also be used instead.
One example output could be the following:
Draw a house at 64x64 pixels with Midnight Ablaze Palette
Draw a mountain at 256x128 pixels with Oil 6 Palette
Draw a house at 128x64 pixels with Apollo Palette
Draw a bear at 128x64 pixels with Midnight Ablaze Palette
Draw a mountain at 256x128 pixels with Midnight Ablaze Palette
Now I have 5 challenges for pixel art I can work with! This is great for generating ideas, especially if you fill a text file with a million different ideas, then also fill another text file with a million other ideas to combine with it.
This could also be good for quizzing yourself, learning a new language, inspiration, you name it.
Anyway, so on the topic of my code being a neat organized oasis, Here is the parser and how it is used by my main program:
Parser & friends
cli.rs
use clap::Parser;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Args {
#[arg(short, long, num_args = 1.., required = true)]
pub files: Vec<String>,
#[arg(short, long, default_value_t = String::from(" "))]
pub separator: String,
#[arg(short, long, default_value_t = 1)]
pub count: i32
}
main.rs
use chalgen::{file_processor, cli};
use clap::Parser;
fn main() {
let args = cli::Args::parse();
file_processor::output_challenges(args);
}
The code above does the following:
- Define the command line arguments for the library to look for and what characteristics they should have (
cli.rs
) - Pass configuration that was gathered from command line arguments to the program doing the actual work (
main.rs
)
To provide some context for cli.rs
, the following keywords are important:
short
: the flag can be represented by the first letter of the property name. e.g.files
can be referred to as-f
when calling the command line utilitylong
: Effectively the same sort of option asshort
, except the flag is able to be represented by its full name. e.g.count
can be represented as--count
when calling the command line utilitydefault_value_t
: Essentially, this is what the flag will be set to if it is not mentioned when calling the command line utilitynum_args
: How many arguments that are expected from the flag. In this case, I use it once withfiles
and the number of arguments is represented by1..
which essentially means “at least 1.” I specify it like this to provide the user the ability to provide any number of files they wantrequired
: The flag must be used. In this case, thefiles
flag is required
All of the restrictions and allowances defined above are automatically enforced by the clap library. This is a huge weight off my back and allowed me to focus on the actual program (AKA the file_processor::output_challenges(args)
part of the code that I don’t show.
Anyway, that’s about it. Here is the repository for the curious! Stay safe and make good choices.