str_case_conv 0.1.0

Provides utility functions for converting strings to different cases.
Documentation
fn lowercase(s: &str) -> String {
    s.to_lowercase()
}

fn uppercase(s: &str) -> String {
    s.to_uppercase()
}

fn capitalize(s: &str) -> String {
    let mut chars = s.chars();
    match chars.next() {
        Some(first) => first
            .to_uppercase()
            .chain(chars.map(|c| c.to_ascii_lowercase()))
            .collect(),
        None => String::new(),
    }
}

fn capitalize_words(s: &str) -> String {
    s.split_whitespace()
        .map(capitalize)
        .collect::<Vec<_>>()
        .join(" ")
}

fn decapitalize(s: &str) -> String {
    let mut chars = s.chars();
    match chars.next() {
        Some(first) => first.to_lowercase().chain(chars).collect(),
        None => String::new(),
    }
}

fn replace(s: &str, from: &str, to: &str) -> String {
    s.replace(from, to)
}

fn strip_dashes(s: &str) -> String {
    replace(s, "-", " ")
}

fn strip_underscores(s: &str) -> String {
    replace(s, "_", " ")
}

fn strip_whitespace(s: &str) -> String {
    replace(s, " ", "")
}

fn add_dashes(s: &str) -> String {
    replace(s, " ", "-")
}

fn add_underscores(s: &str) -> String {
    replace(s, " ", "_")
}

fn pipe(a: impl Fn(&str) -> String, b: impl Fn(&str) -> String) -> impl Fn(&str) -> String {
    move |s: &str| b(&a(s))
}

fn strip(s: &str) -> String {
    pipe(strip_underscores, strip_dashes)(s)
}

/// Transforms `s` into Start Case
///
/// # Examples
///
/// ```
/// use str_case_conv::start_case;
///
/// assert_eq!(start_case("hello_world"), String::from("Hello World"))
/// ```
pub fn start_case(s: &str) -> String {
    pipe(strip, capitalize_words)(s)
}

/// Transforms `s` into PascalCase
///
/// # Examples
///
/// ```
/// use str_case_conv::pascal_case;
///
/// assert_eq!(pascal_case("hello_world"), String::from("HelloWorld"))
/// ```
pub fn pascal_case(s: &str) -> String {
    pipe(start_case, strip_whitespace)(s)
}

/// Transforms `s` into camelCase
///
/// # Examples
///
/// ```
/// use str_case_conv::camel_case;
///
/// assert_eq!(camel_case("hello_world"), String::from("helloWorld"))
/// ```
pub fn camel_case(s: &str) -> String {
    pipe(pascal_case, decapitalize)(s)
}

/// Transforms `s` into kebab-case
///
/// # Examples
///
/// ```
/// use str_case_conv::kebab_case;
///
/// assert_eq!(kebab_case("hello_world"), String::from("hello-world"))
/// ```
pub fn kebab_case(s: &str) -> String {
    pipe(lowercase, pipe(strip, add_dashes))(s)
}

/// Transforms `s` into snake_case
///
/// # Examples
///
/// ```
/// use str_case_conv::snake_case;
///
/// assert_eq!(snake_case("hello-world"), String::from("hello_world"))
/// ```
pub fn snake_case(s: &str) -> String {
    pipe(lowercase, pipe(strip, add_underscores))(s)
}

/// Transforms `s` into CONSTANT_CASE
///
/// # Examples
///
/// ```
/// use str_case_conv::constant_case;
///
/// assert_eq!(constant_case("hello_world"), String::from("HELLO_WORLD"))
/// ```
pub fn constant_case(s: &str) -> String {
    pipe(uppercase, pipe(strip, add_underscores))(s)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_start_case() {
        assert_eq!(start_case("hello world"), String::from("Hello World"));
        assert_eq!(start_case("hello_world"), String::from("Hello World"));
        assert_eq!(start_case("hello-world"), String::from("Hello World"));
        assert_eq!(start_case("Hello World"), String::from("Hello World"));
    }

    #[test]
    fn test_pascal_case() {
        assert_eq!(pascal_case("hello world"), String::from("HelloWorld"));
        assert_eq!(pascal_case("hello_world"), String::from("HelloWorld"));
        assert_eq!(pascal_case("hello-world"), String::from("HelloWorld"));
        assert_eq!(pascal_case("Hello World"), String::from("HelloWorld"));
    }

    #[test]
    fn test_camel_case() {
        assert_eq!(camel_case("hello world"), String::from("helloWorld"));
        assert_eq!(camel_case("hello_world"), String::from("helloWorld"));
        assert_eq!(camel_case("hello-world"), String::from("helloWorld"));
        assert_eq!(camel_case("Hello World"), String::from("helloWorld"));
    }

    #[test]
    fn test_kebab_case() {
        assert_eq!(kebab_case("hello world"), String::from("hello-world"));
        assert_eq!(kebab_case("hello_world"), String::from("hello-world"));
        assert_eq!(kebab_case("hello-world"), String::from("hello-world"));
        assert_eq!(kebab_case("Hello World"), String::from("hello-world"));
    }

    #[test]
    fn test_snake_case() {
        assert_eq!(snake_case("hello world"), String::from("hello_world"));
        assert_eq!(snake_case("hello-world"), String::from("hello_world"));
        assert_eq!(snake_case("hello_world"), String::from("hello_world"));
        assert_eq!(snake_case("Hello World"), String::from("hello_world"));
    }

    #[test]
    fn test_constant_case() {
        assert_eq!(constant_case("hello world"), String::from("HELLO_WORLD"));
        assert_eq!(constant_case("hello-world"), String::from("HELLO_WORLD"));
        assert_eq!(constant_case("hello_world"), String::from("HELLO_WORLD"));
        assert_eq!(constant_case("Hello World"), String::from("HELLO_WORLD"));
    }
}