app-path 0.1.1

Create file paths relative to your executable for truly portable applications
Documentation
# AppPath

**Create paths relative to your executable for truly portable applications.**

[![Crates.io](https://img.shields.io/crates/v/app-path.svg)](https://crates.io/crates/app-path)
[![Documentation](https://docs.rs/app-path/badge.svg)](https://docs.rs/app-path)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](LICENSE-MIT)
[![CI](https://github.com/DK26/app-path-rs/workflows/CI/badge.svg)](https://github.com/DK26/app-path-rs/actions)

## ๐ŸŽฏ The Problem

When building applications that need to access files (configs, templates, data), you typically have two choices:

1. **System directories** (`~/.config/`, `%APPDATA%`, etc.) - Great for installed apps, but...
   - Requires installation
   - Spreads files across the system
   - Hard to backup/move
   - Needs admin rights on some systems

2. **Hardcoded paths** - Simple but brittle and non-portable

## โœจ The Solution

**AppPath creates paths relative to your executable location**, enabling truly portable applications where everything stays together.

```rust
use app_path::AppPath;

// These paths are automatically relative to your executable
let config = AppPath::try_new("config.toml")?;
let templates = AppPath::try_new("templates")?;
let data = AppPath::try_new("data/users.db")?;

// Check if files exist, create directories, etc.
if !config.exists() {
    config.create_dir_all()?;
    std::fs::write(config.path(), "default config")?;
}
```

## ๐Ÿš€ Why Choose AppPath?

### vs. Standard Library (`std::env::current_dir()`)
```rust
// โŒ Brittle - depends on where user runs the program
let config = std::env::current_dir()?.join("config.toml");

// โœ… Reliable - always relative to your executable
let config = AppPath::try_new("config.toml")?;
```

### vs. System Directories (`directories` crate)
```rust
// โŒ Scattered across the system
use directories::ProjectDirs;
let proj_dirs = ProjectDirs::from("com", "MyOrg", "MyApp").unwrap();
let config = proj_dirs.config_dir().join("config.toml"); // ~/.config/MyApp/config.toml

// โœ… Everything together with your app
let config = AppPath::try_new("config.toml")?; // ./config.toml (next to exe)
```

### vs. Manual Path Joining
```rust
// โŒ Verbose and error-prone
let exe_path = std::env::current_exe()?;
let exe_dir = exe_path.parent().ok_or("No parent")?;
let config = exe_dir.join("config.toml");

// โœ… Clean and simple
let config = AppPath::try_new("config.toml")?;
```

## ๐Ÿ“ Perfect For

- **Portable applications** that travel on USB drives
- **Development tools** that should work anywhere
- **Corporate environments** where you can't install software
- **Containerized applications** with predictable layouts
- **Embedded systems** with simple file structures
- **Quick prototypes** that need simple file access

## ๐Ÿ› ๏ธ Features

- โœ… **Zero dependencies** - Lightweight and fast
- โœ… **Cross-platform** - Works on Windows, Linux, macOS
- โœ… **Simple API** - Just `AppPath::try_new()` and you're done
- โœ… **Full `Path` compatibility** - Implements `AsRef<Path>`, `Display`, etc.
- โœ… **Ergonomic conversions** - `TryFrom<&str>`, `TryFrom<String>` support
- โœ… **Testing support** - Override base directory with `with_base()`
- โœ… **Directory creation** - Built-in `create_dir_all()`
- โœ… **Well tested** - Comprehensive test suite

## ๐Ÿ“– Quick Start

Add to your `Cargo.toml`:
```toml
[dependencies]
app-path = "0.1"
```

```rust
use app_path::AppPath;
use std::fs;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create paths relative to your executable
    let config = AppPath::try_new("config.toml")?;
    let templates = AppPath::try_new("templates")?;
    let logs = AppPath::try_new("logs/app.log")?;
    
    // Use them like normal paths
    if config.exists() {
        let content = fs::read_to_string(config.path())?;
        println!("Config: {}", content);
    }
    
    // Create directories automatically
    logs.create_dir_all()?;
    fs::write(logs.path(), "Application started\n")?;
    
    println!("Config: {}", config);      // Displays full path
    println!("Templates: {}", templates);
    
    Ok(())
}
```

### Alternative Creation Methods

For ergonomic conversions from strings, use `TryFrom`:

```rust
use app_path::AppPath;
use std::convert::TryFrom;

// Primary constructor - clear that it can fail
let config = AppPath::try_new("config.toml")?;

// From string literals using TryFrom
let data = AppPath::try_from("data.db")?;

// From String values
let filename = "cache.json".to_string();
let cache = AppPath::try_from(filename)?;

// From String references  
let path_string = "logs/app.log".to_string();
let logs = AppPath::try_from(&path_string)?;

// All methods give you the same functionality
assert_eq!(config.input(), std::path::Path::new("config.toml"));
```

## ๐Ÿ—๏ธ Application Structure

Your portable application structure becomes:
```
myapp.exe          # Your executable
โ”œโ”€โ”€ config.toml    # AppPath::try_new("config.toml")
โ”œโ”€โ”€ templates/     # AppPath::try_new("templates")
โ”‚   โ”œโ”€โ”€ email.html
โ”‚   โ””โ”€โ”€ report.html
โ”œโ”€โ”€ data/          # AppPath::try_new("data")
โ”‚   โ””โ”€โ”€ cache.db
โ””โ”€โ”€ logs/          # AppPath::try_new("logs")
    โ””โ”€โ”€ app.log
```

## ๐Ÿงช Testing Support

Override the base directory for testing:

```rust
#[cfg(test)]
mod tests {
    use app_path::AppPath;
    use std::env;

    #[test]
    fn test_config_loading() {
        let temp = env::temp_dir().join("app_path_test");
        let config = AppPath::try_new("config.toml")
            .unwrap()
            .with_base(&temp);
        
        // Test with isolated temporary directory
        assert!(!config.exists());
    }
}
```

## ๐Ÿ”„ Common Usage Patterns

### Replace hardcoded paths:
```rust
// Instead of brittle hardcoded paths
let config = PathBuf::from("config.toml");  // Depends on working directory

// Use AppPath for reliable, portable paths
let config = AppPath::try_new("config.toml")?;  // Always relative to executable
```

### Replace manual path construction:
```rust
// Instead of verbose manual construction
let exe = std::env::current_exe()?;
let exe_dir = exe.parent().unwrap();
let config = exe_dir.join("config.toml");

// Use AppPath for clean, simple code
let config = AppPath::try_new("config.toml")?;
```

## ๐Ÿ“„ License

Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT license](LICENSE-MIT) at your option.

---

**AppPath: Keep it simple, keep it together.** ๐ŸŽฏ