date-utilities 0.0.4

Lightweight utilities for working with dates
Documentation
use std::borrow::Cow;

pub struct Template<'t> {
    pub items: Vec<&'t str>,
}

const EMPTY_SLOT: &str = "";

impl<'t> Template<'t> {
    pub fn new(on: &'t str, interpolate_character: char) -> Self {
        let mut items = Vec::new();
        let mut start = 0;
        for (idx, _matched) in on.match_indices(interpolate_character) {
            let escaped = on[..idx].ends_with(interpolate_character);
            if escaped {
                items.push(&on[start..=idx]);
                items.push(EMPTY_SLOT);
                start = idx + 1;
            } else {
                items.push(&on[start..idx]);
                let rest = &on[idx..][1..];
                let name_end = rest
                    .find(|c: char| !(c.is_alphanumeric() || matches!(c, '_')))
                    .unwrap_or(rest.len());

                items.push(&rest[..name_end]);
                start = idx + 1 + name_end;
            }
        }
        items.push(&on[start..]);
        Self { items }
    }

    pub fn interpolate<'a>(&'a self, mut cb: impl FnMut(&'t str) -> Cow<'a, str>) -> String {
        let mut buf = String::new();
        for (idx, item) in self.items.iter().enumerate() {
            if idx % 2 == 0 {
                buf.push_str(item);
            } else if item != &EMPTY_SLOT {
                buf.push_str(&cb(item));
            }
        }
        buf
    }
}

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

    #[test]
    fn basic() {
        let template = Template::new("Hello $name!", '$');
        let values = std::collections::HashMap::from([("name", "Ben")]);
        assert_eq!(
            &template.interpolate(|key| values[key].into()),
            "Hello Ben!"
        );
    }

    #[test]
    fn escape() {
        let template = Template::new("Hello $name! Here is $$20!", '$');
        let values = std::collections::HashMap::from([("name", "Ben")]);
        assert_eq!(
            &template.interpolate(|key| values[key].into()),
            "Hello Ben! Here is $20!"
        );
    }
}