htmx_components/server/
opt_attrs.rs

1use std::collections::HashMap;
2
3pub fn opt_attr<S: AsRef<str>, T: AsRef<str>>(key: S, val: T) -> String {
4    if val.as_ref().is_empty() {
5        String::from("")
6    } else {
7        format!("{}=\"{}\"", key.as_ref(), val.as_ref())
8    }
9}
10
11pub fn opt_attrs<S: AsRef<str>, T: AsRef<str>>(map: HashMap<S, T>) -> String {
12    if map.is_empty() {
13        String::from("")
14    } else {
15        let mut attrs = map
16            .iter()
17            .map(|(key, val)| opt_attr(key, val))
18            .collect::<Vec<String>>();
19
20        // Output attributes in alpha order.
21        attrs.sort();
22        attrs.join(" ").trim().to_string()
23    }
24}
25
26#[cfg(test)]
27mod tests {
28    // Note this useful idiom: importing names from outer (for mod tests) scope.
29    use super::*;
30
31    #[test]
32    fn test_opt_attr_with_empty_string() {
33        assert_eq!(opt_attr("foo", ""), String::from(""));
34    }
35
36    #[test]
37    fn test_opt_attr_with_non_empty_string() {
38        assert_eq!(
39            opt_attr("foo", String::from("baz")),
40            String::from("foo=\"baz\"")
41        );
42    }
43
44    #[test]
45    fn test_opt_attr_with_string_with_spaces() {
46        assert_eq!(
47            opt_attr("foo", String::from("foo bar baz")),
48            String::from("foo=\"foo bar baz\"")
49        );
50    }
51
52    #[test]
53    fn test_opt_attrs_with_empty_map() {
54        assert_eq!(opt_attrs(HashMap::<&str, &str>::new()), String::from(""));
55    }
56
57    #[test]
58    fn test_opt_attrs_with_empty_map_empty_array() {
59        assert_eq!(opt_attrs(HashMap::<&str, &str>::from([])), String::from(""));
60    }
61
62    #[test]
63    fn test_opt_attrs_with_single_attr_that_is_empty() {
64        assert_eq!(opt_attrs(HashMap::from([("foo", "")])), String::from(""));
65    }
66
67    #[test]
68    fn test_opt_attrs_with_multiple_attrs_that_are_empty() {
69        assert_eq!(
70            opt_attrs(HashMap::from([
71                ("foo", String::from("")),
72                ("baz", String::from("")),
73            ])),
74            String::from("")
75        );
76    }
77
78    #[test]
79    fn test_opt_attrs_with_single_attribute_tuple() {
80        assert_eq!(
81            opt_attrs(HashMap::from([("foo", String::from("baz"))])),
82            String::from("foo=\"baz\"")
83        );
84    }
85
86    #[test]
87    fn test_opt_attrs_with_multiple_attribute_tuple() {
88        let attrs = opt_attrs(HashMap::from([
89            ("foo", String::from("baz")),
90            ("bar", String::from("fuzz fuzz-baz")),
91        ]));
92
93        assert_eq!(attrs, String::from("bar=\"fuzz fuzz-baz\" foo=\"baz\""),);
94    }
95}