/*! * Provides traits and helpers for generating and manipulating written lanuage constructs */ /// A type that can be compiled into a sentence. pub trait ToSentence { /// Sentencifies self. The result should be suitable to be placed within a sentence. fn to_sentence(&self) -> String; /// Sentencifies self, upper-casing the first letter and adding a period to the end. Using this is discouraged due to its lack of flexibility (i.e. needing alternate punctuation or a lowercase first letter). fn to_sentence_finalize(&self) -> String { let s = self.to_sentence(); let mut c = s.chars(); match s.len() { 0 => format!(""), 1 => format!("{}.", s.to_uppercase()), _ => format!("{}{}.", c.nth(0).unwrap().to_uppercase(), c.as_str()), } } } impl<'a, T> ToSentence for T where T: AsRef<[&'a str]> { fn to_sentence(&self) -> String { let s = self.as_ref(); let len = s.len(); let mut str = String::new(); for (i, seg) in s.iter().map(|s| s.as_ref()).enumerate() { if i == 0 { str.push_str(seg); } else if i == len-1 { if len == 2 { str.push_str(&format!(" and {}", seg)); } else { str.push_str(&format!(", and {}", seg)); } } else { str.push_str(&format!(", {}", seg)); } } str } } // impl ToSentence for T where T: AsRef<[String]> { // fn to_sentence(&self) -> String { // let s = self.as_ref(); // let len = s.len(); // let mut str = String::new(); // for (i, seg) in s.iter().map(|s| s.as_ref()).enumerate() { // if i == 0 { // str.push_str(seg); // } else if i == len { // if len == 2 { // str.push_str(&format!(" and {}", seg)); // } else { // str.push_str(&format!(", and {}", seg)); // } // } else { // str.push_str(&format!(", {}", seg)); // } // } // str // } // } #[cfg(test)] mod test { use super::ToSentence; const STRING_SLICE_A: &'static [&'static str] = &[ "a", ]; const STRING_SLICE_B: &'static [&'static str] = &[ "a", "b", ]; const STRING_SLICE_C: &'static [&'static str] = &[ "a", "b", "c", "d", "e", "f", "g", ]; #[test] fn str_slice_to_sentence() { assert_eq!(STRING_SLICE_A.to_sentence(), "a"); assert_eq!(STRING_SLICE_B.to_sentence(), "a and b"); assert_eq!(STRING_SLICE_C.to_sentence(), "a, b, c, d, e, f, and g"); } #[test] fn str_slice_to_sentence_finalize() { assert_eq!(STRING_SLICE_A.to_sentence_finalize(), "A."); assert_eq!(STRING_SLICE_B.to_sentence_finalize(), "A and b."); assert_eq!(STRING_SLICE_C.to_sentence_finalize(), "A, b, c, d, e, f, and g."); } #[test] fn string_vec_to_sentence() { let vec: Vec = vec!{ "a".to_owned(), }; assert_eq!(vec.iter().map(|e| e.as_ref()).collect::>().to_sentence(), "a"); let vec: Vec = vec!{ "a".to_owned(), "b".to_owned(), }; assert_eq!(vec.iter().map(|e| e.as_ref()).collect::>().to_sentence(), "a and b"); let vec: Vec = vec!{ "a".to_owned(), "b".to_owned(), "c".to_owned(), "d".to_owned(), "e".to_owned(), "f".to_owned(), "g".to_owned(), }; assert_eq!(vec.iter().map(|e| e.as_ref()).collect::>().to_sentence(), "a, b, c, d, e, f, and g"); } #[test] fn string_vec_to_sentence_finalize() { let vec: Vec = vec!{ "a".to_owned(), }; assert_eq!(vec.iter().map(|e| e.as_ref()).collect::>().to_sentence_finalize(), "A."); let vec: Vec = vec!{ "a".to_owned(), "b".to_owned(), }; assert_eq!(vec.iter().map(|e| e.as_ref()).collect::>().to_sentence_finalize(), "A and b."); let vec: Vec = vec!{ "a".to_owned(), "b".to_owned(), "c".to_owned(), "d".to_owned(), "e".to_owned(), "f".to_owned(), "g".to_owned(), }; assert_eq!(vec.iter().map(|e| e.as_ref()).collect::>().to_sentence_finalize(), "A, b, c, d, e, f, and g."); } }