1#[must_use]
5pub fn listed<S: AsRef<str>>(items: &[S]) -> String {
6 match items {
7 [] => String::new(),
8 [one] => one.as_ref().to_owned(),
9 [rest @ .., last] => format!(
10 "{} and {}",
11 rest.iter()
12 .map(AsRef::as_ref)
13 .collect::<Vec<_>>()
14 .join(", "),
15 last.as_ref()
16 ),
17 }
18}
19
20#[must_use]
22pub fn titled(slug: &str) -> String {
23 let words = slug.replace(['-', '_'], " ");
24 let mut c = words.chars();
25 c.next()
26 .map(|f| f.to_uppercase().chain(c).collect())
27 .unwrap_or_default()
28}
29
30#[cfg(test)]
31mod tests {
32 use super::{listed, titled};
33
34 #[test]
35 fn a_slug_reads_as_a_title() {
36 assert_eq!(titled("empty-title"), "Empty title");
37 assert_eq!(titled(""), "");
38 }
39
40 #[test]
41 fn lists_read_as_a_sentence() {
42 assert_eq!(listed::<&str>(&[]), "");
43 assert_eq!(listed(&["a"]), "a");
44 assert_eq!(listed(&["a", "b"]), "a and b");
45 assert_eq!(listed(&["a", "b", "c"]), "a, b and c");
46 }
47}