Capstone: wordfreq CLI
| The spec | |
| Parse argv | |
| HashMap counting | |
| Unit tests for count |
The spec
Build wordfreq: a tool that takes one file path, counts how often each word appears, and prints the top ten lines as word plus count. No flags, no subcommands, just argv, files, and a HashMap.
Success means running wordfreq on this very lesson text and seeing small words like the and and near the top. The three sections below build it piece by piece, and the last one locks the counting logic behind tests.
Parse argv
The tool needs exactly one argument, the file path. Demand it with the usage pattern from lesson 41 and keep the path for the next step:
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() != 2 {
eprintln!("usage: wordfreq <file>");
std::process::exit(1);
}
println!("counting words in {}", args[1]);
}
HashMap counting
Counting is the heart of the tool. Take a vector of word slices, then let the entry API create each counter on first sight and bump it after:
use std::collections::HashMap;
fn count(words: Vec<&str>) -> HashMap<String, u32> {
let mut freq = HashMap::new();
for w in words {
*freq.entry(w.to_string()).or_insert(0) += 1;
}
freq
}
The entry call borrows the map once and or_insert supplies zero for new words. Pure functions like count are a joy to test, which is exactly next.
Unit tests for count
Pin the counter down with a test function beside the code. Feed known words and assert the exact tallies:
#[test]
fn counts_repeats() {
let got = count(vec!["a", "b", "a"]);
assert_eq!(got["a"], 2);
assert_eq!(got["b"], 1);
}
Run with cargo test and green means the core logic is frozen. File reading and sorting are then just wiring around a tested heart.
Next: Capstone: tiny HTTP server
Article author: Arthur Isaev