Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions benches/process.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
use criterion::{Criterion, criterion_group, criterion_main};
use std::hint::black_box;
use string_pipeline::process;
use string_pipeline::Template;

fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("process_simple", |b| {
b.iter(|| {
process(
black_box("/home/user/.cargo/bin"),
// output: "bin"
black_box("{split:/:-1}"),
)
.unwrap()
Template::parse(black_box("{split:/:-1}"))
.unwrap()
.format(black_box("/home/user/.cargo/bin"))
.unwrap()
})
});

c.bench_function("process_complex", |b| {
b.iter(|| {
process(
black_box(" 18, 4.92, Unknown"),
// output: "NUM: 18 - NUM: 4.92"
black_box("{split:,:0..2|trim|prepend:num\\: |join: - |upper}"),
)
Template::parse(black_box(
"{split:,:0..2|trim|prepend:num\\: |join: - |upper}",
))
.unwrap()
.format(black_box("18, 4.92, Unknown"))
.unwrap()
})
});
Expand Down
68 changes: 64 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,70 @@
//! # string_pipeline
//!
//! A flexible, template-driven string transformation pipeline for Rust.
//!
//! This library provides a way to define a sequence of string operations using a concise template syntax,
//! allowing for dynamic string manipulation based on user-defined templates.
//!
//! # Quick start
//! ```rust
//! use string_pipeline::Template;
//!
//! // Define a template with operations
//! let template = Template::parse("{split:,:0..2|join: and }").unwrap();
//!
//! // Format a string using the template
//! let result = template.format("a,b,c,d").unwrap();
//!
//! assert_eq!(result, "a and b");
//! ```
//!
//! A more in-depth view of the template syntax can be found in the [Template::parse](Template::parse) method documentation.
//!
//! # More examples
//! Get the second item in a comma-separated list:
//! ```rust
//! use string_pipeline::Template;
//!
//! let template = Template::parse("{split:,:1}").unwrap();
//!
//! let result = template.format("a,b,c").unwrap();
//!
//! assert_eq!(result, "b");
//! ```
//!
//! Replace all spaces with underscores and uppercase:
//! ```rust
//! use string_pipeline::Template;
//!
//! let template = Template::parse("{replace:s/ /_/g|upper}").unwrap();
//!
//! let result = template.format("foo bar baz").unwrap();
//!
//! assert_eq!(result, "FOO_BAR_BAZ");
//! ```
//!
//! Trim, split and append a suffix to each resulting item:
//! ```rust
//! use string_pipeline::Template;
//!
//! let template = Template::parse("{split:,:..|trim|append:!}").unwrap();
//!
//! let result = template.format(" a, b,c , d , e ").unwrap();
//!
//! assert_eq!(result, "a!,b!,c!,d!,e!");
//! ```
//!
//! Strip ANSI escape codes:
//! ```rust
//! use string_pipeline::Template;
//!
//! let template = Template::parse("{strip_ansi}").unwrap();
//!
//! let result = template.format("\x1b[31mHello\x1b[0m").unwrap();
//!
//! assert_eq!(result, "Hello");
//! ```

mod pipeline;

pub use pipeline::apply_ops;
pub use pipeline::parse_template;
pub use pipeline::process;
pub use pipeline::{RangeSpec, StringOp, Value};
pub use pipeline::Template;
11 changes: 8 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clap::Parser;
use std::io::{self, Read};
use string_pipeline::process;
use string_pipeline::Template;

#[derive(Parser)]
struct Cli {
Expand Down Expand Up @@ -33,10 +33,15 @@ fn main() {
},
};

match process(&input, &cli.template) {
let template = Template::parse(&cli.template).unwrap_or_else(|e| {
eprintln!("Error parsing template: {}", e);
std::process::exit(1);
});

match template.format(&input) {
Ok(result) => println!("{}", result),
Err(e) => {
eprintln!("Error: {}", e);
eprintln!("Error formatting input: {}", e);
std::process::exit(1);
}
}
Expand Down
39 changes: 16 additions & 23 deletions src/pipeline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use regex::Regex;
mod parser;
use strip_ansi_escapes::strip;

pub use crate::pipeline::template::Template;
mod template;

#[derive(Debug, Clone)]
pub enum Value {
enum Value {
Str(String),
List(Vec<String>),
}
Expand Down Expand Up @@ -55,10 +58,6 @@ pub enum RangeSpec {
Range(Option<isize>, Option<isize>, bool), // (start, end, inclusive)
}

pub fn parse_template(template: &str) -> Result<(Vec<StringOp>, bool), String> {
parser::parse_template(template)
}

fn resolve_index(idx: isize, len: usize) -> usize {
if len == 0 {
return 0;
Expand Down Expand Up @@ -380,21 +379,20 @@ pub fn apply_ops(input: &str, ops: &[StringOp], debug: bool) -> Result<String, S
})
}

pub fn process(input: &str, template: &str) -> Result<String, String> {
let (ops, debug) = parse_template(template)?;
apply_ops(input, &ops, debug)
}

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

fn process(input: &str, template: &str) -> Result<String, String> {
let tmpl = Template::parse(template)?;
tmpl.format(input)
}

// Single Operation Tests - Organized by Operation Type
mod single_operations {
use super::*;

mod positive_tests {
use super::*;
use super::super::process;

// Split operation tests
#[test]
Expand Down Expand Up @@ -979,7 +977,7 @@ mod tests {
}

mod negative_tests {
use super::*;
use super::super::process;

// Split operation negative tests
#[test]
Expand Down Expand Up @@ -1111,11 +1109,8 @@ mod tests {

// Two-Step Pipeline Tests
mod two_step_pipelines {
use super::*;

mod positive_tests {
use super::*;

use super::super::process;
// Split + Join combinations
#[test]
fn test_split_join_different_separators() {
Expand Down Expand Up @@ -1379,7 +1374,7 @@ mod tests {
}

mod negative_tests {
use super::*;
use super::super::process;

// Invalid pipeline combinations
#[test]
Expand Down Expand Up @@ -1430,10 +1425,8 @@ mod tests {

// Multi-Step Pipeline Tests
mod multi_step_pipelines {
use super::*;

mod positive_tests {
use super::*;
use super::super::process;

// Split + Transform + Join patterns
#[test]
Expand Down Expand Up @@ -2135,7 +2128,7 @@ mod tests {
}

mod negative_tests {
use super::*;
use super::super::process;

// Invalid three-step combinations
#[test]
Expand Down
Loading