Return to String Basics

Where I try to give some life to poor “Bob”, but learn more about Clippy and Fmt

Pale robot face, is this the face of Bob?
I’m sorry “Bob”, I cannot do that.

Another sample programming problem and I am about to practice so string methods, but also learn about two Rust helpers: Cargo Clippy and Fmt. It is becoming apparent just how much help in Rust coding is embedded in the error messages and in cargo.

The next Exercism programming task was to have “Bob” respond in various ways to a passed in prompt. If you ask a question, Bob should respond with “Sure.” unless you are SCREAMING, in which case his response is “Calm down, I know what I’m doing!”. If you prompt “Bob” with nothing, he says “Fine. Be that way!”, but everything gets back a simple “Whatever.”

Coding Like a Rust Coder

Of course, there are many ways to check all these conditions. Still, I wanted to use the built-in helper methods and find the most Rust-idiomatic way. I was also cognizant of not repeating myself: not running the same method or checking the same test more than once and wasting clock cycles.

For instance, string.trim() removes leading and trailing whitespace, and combining that with a built-in test, we can see if the prompt is basically empty by using string.trim().is_empty()

I choose to see if “Bob” is being yelled at, but uppercasing the string and seeing if nothing changed – of course, that’s only true if the string includes at least 1 alphabetic character, so lets check that first with string.chars().any(char::is_alphabetic).

That will iterate using the chars() that we’ve seen before and tell me if any of them are a-z/A-Z. To uppercase the string (I’m only going to worry about the ASCII characters here; Rust also has to_uppercase which will follow the terms of the Unicode Derived Core Property Uppercase, see this for some issues with Unicode characters), so I’ll just use string.to_ascii_uppercase().




Searching for Possibilities

Lastly, it might be a “whispered question”, but I want to make sure the prompt isn’t entirely just a question mark – that doesn’t fit the premise of a question according to the Exercism-provided test I am still failing, so string.len() will give me the length of the string. I end up with this code:

 pub fn reply(message: &str) -> &str {
    let check_message = message.trim();

    if check_message.is_empty() {
        return "Fine. Be that way!";
    }

    let question = check_message.ends_with('?');

    if check_message.chars().any(char::is_alphabetic)
        && check_message.to_ascii_uppercase() == message
    {
        if question {
            return "Calm down, I know what I'm doing!";
        } else {
            return "Whoa, chill out!";
        }
    }

    if check_message.len() > 1 && question {
        return "Sure.";
    }
    "Whatever."
} 

So, “not running the same method or checking the same test more than once” meant I had to make a copy of the passed in string so I could trim() it just once at the beginning. I also didn’t want to test for a ‘?’ at the end of the prompt more than one time. Maybe my extra variable creation costs more than running trim() each time I would need it, I’m not sure!

Cargo Clippy and Fmt

Bad sci-fi movie robot, maybe his name can be Cargo Clippy
Cargo Clippy is here to help!

Another note: I used two Rust assistants: first, clippy to check my code before submitting it to Exercism. Clippy is basically a Rust lint program and will alert you to changes you can make to your code even though it compiles. For instance, I learned about is_empty() (instead of checking len() == 0) and I learned that ends_with() can apparently take a char OR a string (I originally had ends_with(“?”) since I was calling a method on a String type and I just assumed…)

You can get “clippy with it” (no, he didn’t!) by typing rustup component add clippy. I then ran it against my code by doing cargo clippy –all-targets.

Also, there is a prettifier called fmt; get it by doing rustup component add fmt and then run cargo fmt. This “fixed” my indentation and curly braces (and probably other things) to match what is commonly accepted correct-formatting for Rust scripts.