Skip to main content

utils/
substitution.rs

1use std::collections::HashMap;
2use std::hash::BuildHasher;
3
4use regex::{Captures, Regex};
5
6/// Substitute parameters in a prompt template
7/// Supports named parameters using the format `$parameter_name`
8pub fn substitute_parameters<S: BuildHasher>(
9    template: &str,
10    arguments: &Option<HashMap<String, String, S>>,
11) -> String {
12    let Ok(regex) = Regex::new(r"\$(\w+)") else {
13        return template.to_string();
14    };
15
16    arguments
17        .as_ref()
18        .map(|args| {
19            regex
20                .replace_all(template, |caps: &Captures| {
21                    let text = caps[0].to_string();
22                    let param_name = &caps[1];
23                    args.get(param_name).cloned().unwrap_or(text)
24                })
25                .to_string()
26        })
27        .unwrap_or(template.to_string())
28}
29
30#[cfg(test)]
31mod tests {
32    use super::*;
33
34    #[test]
35    fn test_substitute_named_parameters() {
36        let template = "Review this $language code in $framework";
37        let args = HashMap::from([
38            ("language".to_string(), "Rust".to_string()),
39            ("framework".to_string(), "Actix".to_string()),
40        ]);
41
42        let result = substitute_parameters(template, &Some(args));
43        assert_eq!(result, "Review this Rust code in Actix");
44    }
45
46    #[test]
47    fn test_no_arguments() {
48        let template = "Hello $name, welcome to $project. Today is $day";
49        let none: Option<HashMap<String, String>> = None;
50        let result = substitute_parameters(template, &none);
51        assert_eq!(result, "Hello $name, welcome to $project. Today is $day");
52    }
53
54    #[test]
55    fn test_missing_parameter() {
56        let template = "Language: $language, Framework: $framework, Database: $database";
57        let args = HashMap::from([
58            ("language".to_string(), "Rust".to_string()),
59            ("framework".to_string(), "Actix".to_string()),
60        ]);
61
62        let result = substitute_parameters(template, &Some(args));
63        assert_eq!(
64            result,
65            "Language: Rust, Framework: Actix, Database: $database"
66        );
67    }
68
69    #[test]
70    fn test_empty_arguments() {
71        let template = "Process $input with $config";
72        let args = HashMap::new();
73        let result = substitute_parameters(template, &Some(args));
74        assert_eq!(result, "Process $input with $config");
75    }
76
77    #[test]
78    fn test_no_parameters_in_template() {
79        let template = "Just a plain string without parameters";
80        let args = HashMap::from([("unused".to_string(), "value".to_string())]);
81        let result = substitute_parameters(template, &Some(args));
82        assert_eq!(result, "Just a plain string without parameters");
83    }
84}