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