about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGriffin Smith <root@gws.fyi>2019-07-29T02·31-0400
committerGriffin Smith <root@gws.fyi>2019-07-29T02·31-0400
commit34b20b7786a8f6753bb449425772958e0285c385 (patch)
treee8781db1c3bed3f8897f40fb201c40b6f1d28bac
parentba7bec9a3e36eaf2af65677b02884172241d1b24 (diff)
Add functions for making sentences from lists
This seems like something I keep having to write
-rw-r--r--proptest-regressions/description.txt7
-rw-r--r--src/description.rs93
-rw-r--r--src/main.rs1
3 files changed, 101 insertions, 0 deletions
diff --git a/proptest-regressions/description.txt b/proptest-regressions/description.txt
new file mode 100644
index 000000000000..3c4942315b45
--- /dev/null
+++ b/proptest-regressions/description.txt
@@ -0,0 +1,7 @@
+# Seeds for failure cases proptest has generated in the past. It is
+# automatically read and these particular cases re-run before any
+# novel cases are generated.
+#
+# It is recommended to check this file in to source control so that
+# everyone who runs the test benefits from these saved cases.
+cc 92b51b5444b913aaa6cb89d7e7175ab6a6af5b5231ba047d123bb55d43d7d272 # shrinks to descriptions = []
diff --git a/src/description.rs b/src/description.rs
new file mode 100644
index 000000000000..4c553c746d91
--- /dev/null
+++ b/src/description.rs
@@ -0,0 +1,93 @@
+use crate::entities::Describe;
+
+pub fn list_to_sentence(lst: &Vec<String>) -> String {
+    let mut buf = String::with_capacity(
+        lst.iter()
+            .map(|e| e.len() + 2usize /* ", " */)
+            .sum::<usize>()
+            + if lst.len() >= 3 {
+                3usize /* "and" */
+            } else {
+                0usize
+            },
+    );
+
+    match lst.len() {
+        0 => {}
+        1 => buf.push_str(&lst[0]),
+        2 => {
+            buf.push_str(&lst[0]);
+            buf.push_str(" and ");
+            buf.push_str(&lst[1]);
+        }
+        _ => {
+            for desc in &lst[..lst.len() - 1] {
+                buf.push_str(desc);
+                buf.push_str(", ");
+            }
+            buf.push_str("and ");
+            buf.push_str(&lst[lst.len() - 1]);
+        }
+    }
+
+    buf
+}
+
+pub fn describe_list<A: Describe>(lst: &Vec<A>) -> String {
+    list_to_sentence(
+        &lst.iter().map(|e| e.description()).collect::<Vec<String>>(),
+    )
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use proptest::prelude::*;
+    use proptest_derive::Arbitrary;
+
+    #[derive(Debug, Arbitrary)]
+    struct Description(String);
+
+    impl Describe for Description {
+        fn description(&self) -> String {
+            self.0.clone()
+        }
+    }
+
+    proptest! {
+        #[test]
+        fn test_describe_list_includes_all_descriptions(
+            descriptions: Vec<Description>
+        ) {
+            let res = describe_list(&descriptions);
+            for Description(desc) in descriptions {
+                assert!(res.contains(&desc));
+            }
+        }
+    }
+
+    #[test]
+    fn test_describe_list() {
+        assert_eq!(
+            describe_list(&vec![Description("one".to_string())]),
+            "one".to_string()
+        );
+
+        assert_eq!(
+            describe_list(&vec![
+                Description("one".to_string()),
+                Description("two".to_string())
+            ]),
+            "one and two".to_string()
+        );
+
+        assert_eq!(
+            describe_list(&vec![
+                Description("one".to_string()),
+                Description("two".to_string()),
+                Description("three".to_string())
+            ]),
+            "one, two, and three".to_string()
+        );
+    }
+}
diff --git a/src/main.rs b/src/main.rs
index b322a969a1be..676d2173e857 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -34,6 +34,7 @@ mod util;
 mod types;
 #[macro_use]
 mod entities;
+mod description;
 mod display;
 mod game;
 mod level_gen;