From ace1973b3a291a4c09485373f8574ecde3ee229b Mon Sep 17 00:00:00 2001
From: Guillaume Pasquet <dev@etenil.net>
Date: Sat, 19 Mar 2022 09:56:51 +0000
Subject: Fix #13 - Implement default values for placeholders

---
 src/executor.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 46 insertions(+), 4 deletions(-)

(limited to 'src/executor.rs')

diff --git a/src/executor.rs b/src/executor.rs
index 54ca491..763b0e6 100644
--- a/src/executor.rs
+++ b/src/executor.rs
@@ -29,19 +29,29 @@ impl Context {
         }
     }
 
+    #[cfg(test)]
     fn key_str(&self, key: &String) -> String {
+        // Use for reference / utility?
         format!("{{{}}}", key)
     }
 
     pub fn substitute(&self, string: &String) -> String {
         let mut buffer = string.clone();
-        let re = Regex::new(r"\{([A-Za-z0-9_]+)\}").unwrap();
+        let re = Regex::new(r"\{(?P<key>[A-Za-z0-9_]+)(?::-(?P<value>.*))?\}").unwrap();
 
         for var in re.captures_iter(string) {
-            let key = String::from(&var[1]);
+            let key = String::from(&var["key"]);
+            let value = String::from(
+                var.name("value")
+                    .map(|m| m.as_str())
+                    .or(Some(&String::from(""))).unwrap()
+            );
+
             buffer = buffer.replace(
-                self.key_str(&key).as_str(),
-                self.vars.get(&key).or(Some(&String::from(""))).unwrap(),
+                // Since this iterates over matches, having match 0 is guaranteed. So the
+                // `unwrap()` operation here is safe.
+                var.get(0).unwrap().as_str(),
+                self.vars.get(&key).or(Some(&value)).unwrap()
             );
         }
 
@@ -197,6 +207,38 @@ mod tests_context {
             String::from("blah blah  blah")
         );
     }
+
+    #[test]
+    fn test_context_substitute_default() {
+        let vars: Vec<(String, String)> = vec![];
+        let ctx = Context::new(vars.into_iter());
+        assert_eq!(
+            ctx.substitute(&String::from("blah blah {chewie:-wookie} blah")),
+            String::from("blah blah wookie blah")
+        );
+    }
+
+    #[test]
+    fn test_context_substitute_value_with_default() {
+        let vars: Vec<(String, String)> = vec![
+            (String::from("chewie"), String::from("han")),
+        ];
+        let ctx = Context::new(vars.into_iter());
+        assert_eq!(
+            ctx.substitute(&String::from("blah blah {chewie:-wookie} blah")),
+            String::from("blah blah han blah")
+        );
+    }
+
+    #[test]
+    fn test_context_substitute_empty_default() {
+        let vars: Vec<(String, String)> = vec![];
+        let ctx = Context::new(vars.into_iter());
+        assert_eq!(
+            ctx.substitute(&String::from("blah blah {chewie:-} blah")),
+            String::from("blah blah  blah")
+        );
+    }
 }
 
 #[cfg(test)]
-- 
cgit v1.2.3