# Comprehensive Usage Examples

This document provides detailed examples for using `rok-utils`.

## Table of Contents

1. [String Utilities](#string-utilities)
2. [Fluent Builder](#fluent-builder)
3. [Array/Collection Utilities](#arraycollection-utilities)
4. [Error Handling](#error-handling)
5. [Functional Patterns](#functional-patterns)
6. [Data Utilities](#data-utilities)
7. [File System Helpers](#file-system-helpers)
8. [Type Guards](#type-guards)

---

## String Utilities

### Case Conversion

```rust
use rok_utils::{to_snake_case, to_camel_case, to_kebab_case, to_pascal_case};

let snake = to_snake_case("HelloWorld");      // "hello_world"
let camel = to_camel_case("hello_world");    // "helloWorld"
let kebab = to_kebab_case("HelloWorld");      // "hello-world"
let pascal = to_pascal_case("hello_world");  // "HelloWorld"
```

### Truncation

```rust
use rok_utils::truncate;

let short = truncate("Hello World", 5);           // "Hello..."
let complete = truncate("Hello World", 5);       // Already short, unchanged
```

### Slug Generation

```rust
use rok_utils::slug;

let slug = slug("Hello World!");        // "hello-world"
let custom = slug("Hello World!", '_'); // "hello_world"
```

### Pluralization (feature: "unicode")

```rust
use rok_utils::pluralize;

assert_eq!(pluralize("cat", 1), "cat");
assert_eq!(pluralize("cat", 2), "cats");
assert_eq!(pluralize("box", 3), "boxes");
```

### Base64 Encoding

```rust
use rok_utils::to_base64;

let encoded = to_base64("Hello");  // "SGVsbG8="
```

### String Inspection

```rust
use rok_utils::{
    is_empty, is_ascii, is_url, starts_with, ends_with, contains,
    word_count, length
};

assert!(!is_empty("hello"));
assert!(is_ascii("hello"));
assert!(is_url("https://example.com"));
assert!(starts_with("hello world", "hello"));
assert!(ends_with("hello world", "world"));
assert!(contains("hello world", "lo"));
assert_eq!(word_count("hello world"), 2);
assert_eq!(length("hello"), 5);
```

---

## Fluent Builder

The `Str::of()` builder provides a chainable API for complex string transformations.

### Basic Chaining

```rust
use rok_utils::str::Str;

let result = Str::of("  Hello World  ")
    .trim()
    .to_snake_case()
    .value();
assert_eq!(result, "hello_world");
```

### Conditional Transformations

```rust
use rok_utils::str::Str;

let result = Str::of("hello")
    .when(true, |s| s.append(" world"))
    .when(false, |s| s.append(" hidden"))
    .value();
assert_eq!(result, "hello world");
```

### Empty Handling

```rust
use rok_utils::str::Str;

let result = Str::of("")
    .when_empty(|s| s.append("default"))
    .value();
assert_eq!(result, "default");
```

### Content-Based Conditionals

```rust
use rok_utils::str::Str;

let result = Str::of("user@example.com")
    .when_contains("@", |s| s.replace("@", " [at] "))
    .value();
assert_eq!(result, "user [at] example.com");
```

### Prefix/Suffix Operations

```rust
use rok_utils::str::Str;

let result = Str::of("world")
    .ensure_start("hello ")
    .finish("!")
    .value();
assert_eq!(result, "hello world!");
```

### Text Wrapping

```rust
use rok_utils::str::Str;

let result = Str::of("content")
    .wrap("[", "]")
    .value();
assert_eq!(result, "[content]");
```

### Side Effects with Tap

```rust
use rok_utils::str::Str;

let mut collected = Vec::new();
let _ = Str::of("hello")
    .tap(|s| collected.push(s.len()))
    .tap(|s| collected.push(s.chars().count()))
    .value();
// collected: [5, 5]
```

### Custom Transformations with Pipe

```rust
use rok_utils::str::Str;

let result = Str::of("hello")
    .pipe(|s| s.to_uppercase())
    .pipe(|s| format!("{s}!"))
    .value();
assert_eq!(result, "HELLO!");
```

### Complete Real-World Example

```rust
use rok_utils::str::Str;

fn format_username(name: &str) -> String {
    Str::of(name)
        .trim()
        .lower()
        .when_empty(|s| s.append("anonymous"))
        .replace(" ", "_")
        .prepend("@")
        .value()
}

assert_eq!(format_username("  John Doe  "), "@john_doe");
assert_eq!(format_username("   "), "@anonymous");
```

---

## Array/Collection Utilities

### Mapping and Filtering

```rust
use rok_utils::arr::{map, filter};

let numbers = [1, 2, 3, 4, 5];

let doubled = map(&numbers, |x| x * 2);
assert_eq!(doubled, vec![2, 4, 6, 8, 10]);

let evens = filter(&numbers, |x| x % 2 == 0);
assert_eq!(evens, vec![2, 4]);
```

### Finding Elements

```rust
use rok_utils::arr::{first, last, find};

let items = ["a", "b", "c"];

assert_eq!(first(&items), Some(&"a"));
assert_eq!(last(&items), Some(&"c"));

let found = find(&items, |x| *x == "b");
assert_eq!(found, Some(&"b"));
```

### Chunking and Flipping

```rust
use rok_utils::arr::{chunk, reverse};

let numbers = [1, 2, 3, 4, 5, 6];

let chunks = chunk(&numbers, 2);
assert_eq!(chunks, vec![vec![1, 2], vec![3, 4], vec![5, 6]]);

let reversed = reverse(&numbers);
assert_eq!(reversed, vec![6, 5, 4, 3, 2, 1]);
```

### Set Operations

```rust
use rok_utils::arr::{unique, diff, intersect, without};

let a = [1, 2, 3, 2, 1];

let uniq = unique(&a);
assert_eq!(uniq, vec![1, 2, 3]);

let difference = diff(&[1, 2, 3], &[2]);
assert_eq!(difference, vec![1, 3]);

let intersection = intersect(&[1, 2, 3], &[2, 3, 4]);
assert_eq!(intersection, vec![2, 3]);

let filtered = without(&[1, 2, 3, 4], &[2, 4]);
assert_eq!(filtered, vec![1, 3]);
```

### Membership Testing

```rust
use rok_utils::arr::contains;

let items = ["a", "b", "c"];

assert!(contains(&items, &"b"));
assert!(!contains(&items, &"d"));
```

### Reducing

```rust
use rok_utils::arr::reduce;

let numbers = [1, 2, 3, 4];
let sum = reduce(&numbers, 0, |acc, x| acc + x);
assert_eq!(sum, 10);
```

---

## Error Handling

### Basic Error Creation

```rust
use rok_utils::RokError;

let err = RokError::NotFound("User #42".into());
assert_eq!(err.code(), "E_NOT_FOUND");
assert_eq!(err.status(), 404);
assert!(err.is_self_handled());
```

### Result Extension

```rust
use rok_utils::{RokResultExt, RokError};

fn find_user(id: u64) -> Result<String, RokError> {
    if id == 42 {
        Ok("Alice".to_string())
    } else {
        Err(RokError::NotFound(format!("User #{id}")))
    }
}

let result = find_user(42).context("Database query failed");
assert!(result.is_ok());

let result = find_user(0).or_not_found("User");
assert!(matches!(result, Err(RokError::NotFound(_))));
```

### Contextual Errors

```rust
use rok_utils::{RokResultExt, RokError};

let data = vec![1, 2, 3];
let result = data.get(10)
    .ok_or(RokError::NotFound("Element not found".into()))
    .context("Array access failed");
```

### Validation Errors

```rust
use rok_utils::RokError;

fn validate_email(email: &str) -> Result<(), RokError> {
    if email.contains('@') {
        Ok(())
    } else {
        Err(RokError::ValidationFailure {
            field: "email".to_string(),
            reason: "Must contain @".to_string(),
        })
    }
}

let result = validate_email("invalid");
assert!(matches!(result, Err(RokError::ValidationFailure { .. })));
```

### Handling Different Error Types

```rust
use rok_utils::RokError;

fn handle_error(err: &RokError) -> String {
    match err {
        RokError::NotFound(msg) => format!("404: {}", msg),
        RokError::ValidationFailure { field, reason } => {
            format!("Validation error on {}: {}", field, reason)
        }
        RokError::Unauthorized(msg) => format!("401: {}", msg),
        _ => format!("Error: {}", err.code()),
    }
}
```

---

## Functional Patterns

### Pipe

```rust
use rok_utils::fp::pipe;

let result = pipe(5, vec![
    |x| x + 1,
    |x| x * 2,
    |x| x - 3,
]);
assert_eq!(result, 9); // (5 + 1) * 2 - 3 = 9
```

### Compose

```rust
use rok_utils::fp::compose;

let add_one = |x: i32| x + 1;
let double = |x: i32| x * 2;
let add_then_double = compose(double, add_one);

assert_eq!(add_then_double(5), 12); // (5 + 1) * 2
```

### Tap (Side Effects)

```rust
use rok_utils::fp::tap;

let mut log = Vec::new();
let result = tap(42, |v| log.push(*v));
assert_eq!(result, 42);
assert_eq!(log, vec![42]);
```

### Retry

```rust
use rok_utils::fp::retry;

let mut attempts = 0;
let result = retry(3, || {
    attempts += 1;
    if attempts < 2 {
        Err("failed")
    } else {
        Ok("success")
    }
});
assert_eq!(result.unwrap(), "success");
assert_eq!(attempts, 2);
```

### Memoization

```rust
use rok_utils::fp::memoize;

let call_count = std::cell::Cell::new(0);
let expensive = memoize(|x: i32| {
    call_count.set(call_count.get() + 1);
    x * x
});

assert_eq!(expensive(5), 25);
assert_eq!(expensive(5), 25); // Uses cached result
assert_eq!(call_count.get(), 1);
```

### Lazy Initialization

```rust
use rok_utils::fp::Lazy;

let config = Lazy::new(|| {
    println!("Initializing config...");
    "config_value".to_string()
});

println!("Before access");
let value = config.get();
println!("After access: {}", value);
let value2 = config.get(); // No re-initialization
```

---

## Data Utilities

### Number Formatting (feature: default)

```rust
use rok_utils::data::numbers::{format_number, format_currency, format_percentage};

assert_eq!(format_number(1234567.89, 2, ','), "1,234,567.89");
assert_eq!(format_currency(1234.50, "USD"), "$1,234.50");
assert_eq!(format_percentage(0.1234, 1), "12.3%");
```

### Rounding

```rust
use rok_utils::data::numbers::{round, ceil, floor};

assert_eq!(round(3.14159, 2), 3.14);
assert_eq!(ceil(3.001, 0), 4.0);
assert_eq!(floor(3.999, 0), 3.0);
```

### Date/Time (feature: "dates")

```rust
use rok_utils::{now, today, format_date, add_days};

let today = today();
let tomorrow = add_days(&today, 1);

let now = now();
let formatted = format_date(&now, "%Y-%m-%d %H:%M");
```

### UUID/ULID Generation (feature: "ids")

```rust
use rok_utils::{uuid_v4, uuid_v7, ulid, is_uuid, is_ulid};

let uuid = uuid_v4();
let uuid7 = uuid_v7();
let id = ulid();

assert!(is_uuid(&uuid));
assert!(is_ulid(&id));
```

### Hashing (feature: "crypto")

```rust
use rok_utils::{hash_sha256, verify_sha256, generate_token, secure_compare};

let hash = hash_sha256("password");
assert!(verify_sha256("password", &hash));

let token = generate_token(32);
assert_eq!(token.len(), 32); // 32 bytes as hex

assert!(secure_compare("secret", "secret"));
assert!(!secure_compare("secret", "Secret"));
```

### Random Strings (feature: "random")

```rust
use rok_utils::{random, password};

let rand_str = random(16); // 16 character random string
let pass = password(16, true); // with symbols
```

---

## File System Helpers

### Directory Operations

```rust
use rok_utils::fs::{ensure_dir, is_dir, is_file, find_files};

ensure_dir("./data/output").expect("Failed to create directory");

if is_dir("./data") {
    let files = find_files("./data", "*.txt").unwrap();
}
```

### File Operations

```rust
use rok_utils::fs::{read_to_string, write_atomic, copy_dir_all};

let content = read_to_string("config.toml").unwrap();

write_atomic("output.txt", "Hello, World!").unwrap();
```

### Directory Copying

```rust
use rok_utils::fs::copy_dir_all;

copy_dir_all("source", "destination").expect("Copy failed");
```

---

## Type Guards (feature: "json")

```rust
use rok_utils::types::{is_string, is_number, is_array, is_object};
use serde_json::json;

let value = json!({
    "name": "Alice",
    "age": 30,
    "scores": [95, 87, 92]
});

assert!(is_string(&value["name"]));
assert!(is_number(&value["age"]));
assert!(is_array(&value["scores"]));
assert!(is_object(&value));
```

### Deep Path Access

```rust
use rok_utils::types::get_path;
use serde_json::json;

let data = json!({
    "user": {
        "address": {
            "city": "New York"
        }
    }
});

assert_eq!(get_path(&data, "user.address.city"), Some(&json!("New York")));
assert_eq!(get_path(&data, "user.missing"), None);
```

### Deep Path Setting

```rust
use rok_utils::types::set_path;
use serde_json::json;

let mut data = json!({"a": 1});
data = set_path(data, "b", json!(2));

assert_eq!(data.get("b"), Some(&json!(2)));
```

### Deep Equality

```rust
use rok_utils::types::deep_equal;
use serde_json::json;

assert!(deep_equal(&json!({"a": 1}), &json!({"a": 1})));
assert!(!deep_equal(&json!({"a": 1}), &json!({"a": 2})));
```

---

## Complete Examples

### Web API Input Validation

```rust
use rok_utils::{RokError, RokResultExt, Str, truncate};

fn validate_username(username: &str) -> Result<String, RokError> {
    let normalized = Str::of(username)
        .trim()
        .lower()
        .when_empty(|_| panic!("Username required"))
        .value();
    
    if normalized.len() < 3 {
        return Err(RokError::ValidationFailure {
            field: "username".to_string(),
            reason: "Must be at least 3 characters".to_string(),
        });
    }
    
    if normalized.len() > 20 {
        return Err(RokError::ValidationFailure {
            field: "username".to_string(),
            reason: "Must be at most 20 characters".to_string(),
        });
    }
    
    Ok(normalized)
}
```

### Slug Generation for URLs

```rust
use rok_utils::{Str, slug, to_snake_case};

fn generate_url_slug(title: &str) -> String {
    Str::of(title)
        .trim()
        .lower()
        .replace("'", "")
        .squish()
        .value()
}

assert_eq!(generate_url_slug("  Hello World  !"), "hello world");
```

### API Response Formatting

```rust
use rok_utils::{Str, truncate};

fn format_error_message(error: &str) -> String {
    Str::of(error)
        .trim()
        .truncate(100)
        .finish("...")
        .wrap("[Error] ", "")
        .value()
}

assert_eq!(format_error_message("  Something went wrong  "), "[Error] Something went wrong...");
```

---

## Recipes

Common patterns and ready-to-use solutions.

### URL Slug Generation

Generate URL-friendly slugs from titles:

```rust
use rok_utils::str::Str;

fn generate_slug(title: &str) -> String {
    Str::of(title)
        .trim()
        .lower()
        .replace("'", "")
        .replace("&", " and ")
        .squish()
        .pipe(|s| slug(&s, '-'))
        .value()
}

assert_eq!(generate_slug("  Hello World!  "), "hello-world");
assert_eq!(generate_slug("O'Reilly's Guide"), "oreillys-guide");
```

### Username Normalization

Normalize usernames for consistent storage:

```rust
use rok_utils::str::Str;

fn normalize_username(username: &str) -> String {
    Str::of(username)
        .trim()
        .lower()
        .replace(" ", "_")
        .replace("@", "")
        .when_empty(|s| s.append("anonymous"))
        .value()
}

assert_eq!(normalize_username("  JohnDoe  "), "johndoe");
assert_eq!(normalize_username("@admin"), "admin");
assert_eq!(normalize_username("   "), "anonymous");
```

### Email Masking

Mask email addresses for privacy:

```rust
use rok_utils::str::Str;

fn mask_email(email: &str) -> String {
    let parts: Vec<&str> = email.split('@').collect();
    if parts.len() != 2 {
        return email.to_string();
    }
    
    let local = parts[0];
    let domain = parts[1];
    
    if local.len() <= 2 {
        Str::of(email)
            .replace(local, "*".repeat(local.len()).as_str())
            .value()
    } else {
        Str::of(email)
            .replace(local, &format!("{}***", &local[..1]))
            .value()
    }
}

assert_eq!(mask_email("john@example.com"), "j***@example.com");
assert_eq!(mask_email("ab@example.com"), "**@example.com");
```

### Credit Card Formatting

Format credit card numbers with spaces:

```rust
use rok_utils::str::Str;

fn format_card_number(card: &str) -> String {
    let digits: String = card.chars().filter(|c| c.is_ascii_digit()).collect();
    
    Str::of(&digits)
        .pipe(|s| {
            s.chars()
                .collect::<Vec<_>>()
                .chunks(4)
                .map(|chunk| chunk.iter().collect::<String>())
                .collect::<Vec<_>>()
                .join(" ")
        })
        .value()
}

assert_eq!(format_card_number("1234567890123456"), "1234 5678 9012 3456");
```

### Title Case with Exceptions

Apply title case while preserving acronyms and small words:

```rust
use rok_utils::str::Str;

fn smart_title(title: &str) -> String {
    let small_words = ["a", "an", "the", "and", "but", "or", "for", "nor", "on", "at", "to", "by"];
    
    Str::of(title)
        .title()
        .pipe(|s: String| {
            let words: Vec<String> = s.split_whitespace()
                .map(|word| {
                    let lower = word.to_lowercase();
                    if small_words.contains(&lower.as_str()) && word != s.split_whitespace().next().unwrap() {
                        lower
                    } else if word.chars().all(|c| c.is_uppercase()) {
                        word.to_string()
                    } else {
                        word.to_string()
                    }
                })
                .collect();
            words.join(" ")
        })
        .value()
}

assert_eq!(smart_title("the quick brown fox"), "The Quick Brown Fox");
```

### Dynamic Error Messages

Build user-friendly error messages:

```rust
use rok_utils::{RokError, Str};

fn format_error(error: &RokError, context: &str) -> String {
    let code = error.code();
    let message = match error {
        RokError::NotFound(msg) => format!("{} not found", msg),
        RokError::ValidationFailure { field, reason } => format!("Invalid {}: {}", field, reason),
        RokError::Unauthorized(msg) => msg.clone(),
        _ => "An unexpected error occurred".to_string(),
    };
    
    Str::of(&message)
        .wrap("[", "]")
        .prepend(&format!("{}: ", context))
        .value()
}

let err = RokError::NotFound("User".to_string());
assert!(format_error(&err, "Lookup").contains("User not found"));
```

### Batch Processing with Retry

Process items with retry logic:

```rust
use rok_utils::fp::{retry, pipe};

fn process_with_retry<T, U>(
    items: Vec<T>,
    processor: impl Fn(T) -> Result<U, &'static str>,
    max_retries: usize,
) -> Vec<Result<U, &'static str>> {
    items.into_iter()
        .map(|item| {
            retry(max_retries, || processor(item.clone()))
        })
        .collect()
}
```

### Config File Loading

Load and validate configuration:

```rust
use rok_utils::{RokError, RokResultExt, Str};

#[derive(Debug)]
struct Config {
    host: String,
    port: u16,
    database: String,
}

fn load_config(path: &str) -> Result<Config, RokError> {
    let content = std::fs::read_to_string(path)
        .context("Failed to read config file")?;
    
    let json: serde_json::Value = serde_json::from_str(&content)
        .context("Failed to parse config JSON")?;
    
    let host = json["host"].as_str()
        .ok_or_else(|| RokError::ValidationFailure {
            field: "host".to_string(),
            reason: "Missing or invalid".to_string(),
        })?;
    
    let port = json["port"].as_u64()
        .ok_or_else(|| RokError::ValidationFailure {
            field: "port".to_string(),
            reason: "Missing or invalid".to_string(),
        })? as u16;
    
    let database = json["database"].as_str()
        .ok_or_else(|| RokError::ValidationFailure {
            field: "database".to_string(),
            reason: "Missing or invalid".to_string(),
        })?;
    
    Ok(Config {
        host: host.to_string(),
        port,
        database: database.to_string(),
    })
}
```

### API Response Building

Build consistent API responses:

```rust
use rok_utils::str::Str;

#[derive(Debug, serde::Serialize)]
struct ApiResponse<T> {
    success: bool,
    data: Option<T>,
    error: Option<String>,
}

impl<T> ApiResponse<T> {
    fn ok(data: T) -> Self {
        Self {
            success: true,
            data: Some(data),
            error: None,
        }
    }
    
    fn err(message: &str) -> Self {
        Self {
            success: false,
            data: None,
            error: Some(Str::of(message)
                .trim()
                .lower()
                .to_string()),
        }
    }
}
```

### Form Input Sanitization

Sanitize user input for safe storage:

```rust
use rok_utils::str::Str;

fn sanitize_input(input: &str) -> String {
    Str::of(input)
        .trim()
        .replace("<", "&lt;")
        .replace(">", "&gt;")
        .replace("\"", "&quot;")
        .replace("'", "&#39;")
        .replace("&", "&amp;")
        .squish()
        .value()
}

assert_eq!(sanitize_input("  <script>alert('xss')</script>  "), "&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;");
```

### Path Manipulation

Safe file path operations:

```rust
use rok_utils::{path::normalize, path::with_extension, path::stem_ext};

fn safe_file_rename(old_path: &str, new_name: &str) -> Result<String, String> {
    let (stem, ext) = stem_ext(old_path)
        .ok_or("Invalid path")?;
    
    let new_ext = ext.unwrap_or("txt");
    let parent = Str::of(old_path)
        .pipe(|s: String| {
            std::path::Path::new(&s)
                .parent()
                .map(|p| p.to_string_lossy().to_string())
                .unwrap_or_default()
        });
    
    let new_path = std::path::Path::new(&parent)
        .join(new_name)
        .with_extension(new_ext)
        .to_string_lossy()
        .to_string();
    
    Ok(normalize(&new_path))
}
```
