flagon-io/hello

public

Greets people from the command line. The sample repository for g1t.

Add a --shout flag that upper-cases the greeting #25

Mergedg1tbot merged into maing1t-agenton g1t

Approved by g1t-agent

  1. Note

    Running on Claude Sonnet 5.5.

  2. Prompt

    You are a coding agent working in the git repository checked out in the current directory.

    Issue #20: Add a --shout flag that upper-cases the greeting

    Add pub shout: bool to Options in src/lib.rs, set by --shout in parse_args. In src/main.rs, when set, print the greeting upper-cased (HELLO, ADA!). Add unit tests in src/lib.rs for parsing the flag (in any position relative to the name) and for the upper-casing behaviour; put the upper-casing in a small pub function so it is testable.

    These commands must pass when you are done. Run them if the tools are installed:

    • cargo test
    • cargo run -- --shout Ada

    Make the change and keep it focused on the issue. Commit your work with a clear message. Do not push; that is done for you. Finish with a short summary of what you changed and why. It becomes the description of your pull request, so write it for a reviewer: plain sentences, no headings, no emoji, no checklists, and nothing about whether anything was committed or pushed. Say what you did not verify.

  3. Read/work/repo/src/lib.rs
    /work/repo/src/lib.rs
  4. Read/work/repo/src/main.rs
    /work/repo/src/main.rs
  5. result→ 1 use std::env;
    1	use std::env;
    2	
    3	use hello::{greeting, parse_args};
    4	
    5	fn main() {
    6	    // The name given, or whoever is signed in.
    7	    let name = parse_args(env::args().skip(1))
    8	        .name
    9	        .or_else(|| env::var("USER").ok())
    10	        .unwrap_or_else(|| "world".to_owned());
    11	    println!("{}", greeting(&name));
    12	}
    13
  6. result→ 1 //! Greetings.
    1	//! Greetings.
    2	
    3	/// Parsed command-line options.
    4	#[derive(Debug, Default, PartialEq, Eq)]
    5	pub struct Options {
    6	    /// The name to greet, if one was given.
    7	    pub name: Option<String>,
    8	}
    9	
    10	/// Parses command-line arguments (excluding the program name).
    11	///
    12	/// Arguments starting with `--` are treated as flags and skipped; the name is
    13	/// the first remaining argument.
    14	pub fn parse_args<I: IntoIterator<Item = String>>(args: I) -> Options {
    15	    let name = args.into_iter().find(|arg| !arg.starts_with("--"));
    16	    Options { name }
    17	}
    18	
    19	/// The greeting for `name`.
    20	pub fn greeting(name: &str) -> String {
    21	    let trimmed = name.trim();
    22	    let display_name = if trimmed.is_empty() { "world" } else { trimmed };
    23	    format!("Hello, {display_name}!")
    24	}
    25	
    26	/// The farewell for `name`.
    27	pub fn farewell(name: &str) -> String {
    28	    let trimmed = name.trim();
    29	    let display_name = if trimmed.is_empty() { "world" } else { trimmed };
    30	    format!("Goodbye, {display_name}!")
    31	}
    32	
    33	#[cfg(test)]
    34	mod tests {
    35	    use super::*;
    36	
    37	    fn args(list: &[&str]) -> Vec<String> {
    38	        list.iter().map(|s| s.to_string()).collect()
    39	    }
    40	
    41	    #[test]
    42	    fn parse_args_no_args() {
    43	        assert_eq!(parse_args(args(&[])).name, None);
    44	    }
    45	
    46	    #[test]
    47	    fn parse_args_name() {
    48	        assert_eq!(parse_args(args(&["Ada"])).name.as_deref(), Some("Ada"));
    49	    }
    50	
    51	    #[test]
    52	    fn parse_args_skips_leading_flag() {
    53	        assert_eq!(
    54	            parse_args(args(&["--unknown", "Ada"])).name.as_deref(),
    55	            Some("Ada")
    56	        );
    57	    }
    58	
    59	    #[test]
    60	    fn greets_by_name() {
    61	        assert_eq!(greeting("Ada"), "Hello, Ada!");
    62	    }
    63	
    64	    #[test]
    65	    fn greets_world_with_empty_string() {
    66	        assert_eq!(greeting(""), "Hello, world!");
    67	    }
    68	
    69	    #[test]
    70	    fn greets_world_with_whitespace_only() {
    71	        assert_eq!(greeting("  "), "Hello, world!");
    72	    }
    73	
    74	    #[test]
    75	    fn trims_whitespace_from_name() {
    76	        assert_eq!(greeting("  Ada  "), "Hello, Ada!");
    77	    }
    78	
    79	    #[test]
    80	    fn says_goodbye_by_name() {
    81	        assert_eq!(farewell("Ada"), "Goodbye, Ada!");
    82	    }
    83	
    84	    #[test]
    85	    fn says_goodbye_to_world_when_blank() {
    86	        assert_eq!(farewell("  "), "Goodbye, world!");
    87	    }
    88	
    89	    #[test]
    90	    fn farewell_trims_whitespace() {
    91	        assert_eq!(farewell("  Ada  "), "Goodbye, Ada!");
    92	    }
    93	}
    94
  7. Edit/work/repo/src/lib.rs
    /work/repo/src/lib.rs
  8. result→ The file /work/repo/src/lib.rs has been updated successfully. (file state is current in your context — no need to Read it back)
    The file /work/repo/src/lib.rs has been updated successfully. (file state is current in your context — no need to Read it back)
  9. Edit/work/repo/src/lib.rs
    /work/repo/src/lib.rs
  10. result→ The file /work/repo/src/lib.rs has been updated successfully. (file state is current in your context — no need to Read it back)
    The file /work/repo/src/lib.rs has been updated successfully. (file state is current in your context — no need to Read it back)
  11. Edit/work/repo/src/lib.rs
    /work/repo/src/lib.rs
  12. result→ The file /work/repo/src/lib.rs has been updated successfully. (file state is current in your context — no need to Read it back)
    The file /work/repo/src/lib.rs has been updated successfully. (file state is current in your context — no need to Read it back)
  13. Edit/work/repo/src/main.rs
    /work/repo/src/main.rs
  14. result→ The file /work/repo/src/main.rs has been updated successfully. (file state is current in your context — no need to Read it back)
    The file /work/repo/src/main.rs has been updated successfully. (file state is current in your context — no need to Read it back)
  15. Bashcargo test 2>&1 | tail -8 && cargo run -q -- --shout Ada
    cargo test 2>&1 | tail -8 && cargo run -q -- --shout Ada
  16. result→ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
    test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
    
       Doc-tests hello
    
    running 0 tests
    
    test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
    
    HELLO, ADA!
  17. Bashcargo test 2>&1 | grep "test result" | head -1; git commit -qam "Add --shout flag that upper-cases the greeting" && git log --oneline | head -1
    cargo test 2>&1 | grep "test result" | head -1; git commit -qam "Add --shout flag that upper-cases the greeting" && git log --oneline | head -1
  18. result→ test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
    test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
    d48f3a7 Add --shout flag that upper-cases the greeting
  19. g1t-agent

    I added a --shout flag that upper-cases the greeting. cargo test passes (15 tests), and cargo run -- --shout Ada prints HELLO, ADA!.

    Options in src/lib.rs now has pub shout: bool. parse_args sets it when it sees --shout, whether the flag comes before or after the name. It still skips other -- flags and takes the first non-flag argument as the name. I rewrote parse_args as a loop over the arguments to handle both, instead of the single find it used before.

    A new pub fn shout(text: &str) -> String does the upper-casing, so it can be tested directly. src/main.rs calls it on the greeting when the flag is set.

    The new unit tests cover:

    • shout defaulting to false.
    • --shout before the name, after the name, and with no name.
    • The upper-casing itself.

    I didn't test --shout with no name, where the name falls back to $USER, or the printed output of the non-shout path beyond the existing tests.

  20. Note

    This run cost $0.0694 over 9 turns.

  21. Note

    Pushed d48f3a772944.