use std::fmt;
use std::iter::FromIterator;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Attributes {
attributes: Vec<(String, String)>,
}
impl fmt::Display for Attributes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let attribute_tags: Vec<String> = self
.attributes
.iter()
.map(|(key, value)| format!(r#" {}="{}""#, key, value))
.collect();
write!(f, "{}", attribute_tags.join(""))
}
}
impl<I: IntoIterator<Item = (S, S)>, S: ToString> From<I> for Attributes {
fn from(iter: I) -> Self {
let attributes: Vec<(String, String)> = iter
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect();
Self { attributes }
}
}
impl<S: ToString> FromIterator<(S, S)> for Attributes {
fn from_iter<T: IntoIterator<Item = (S, S)>>(iter: T) -> Self {
iter.into()
}
}
impl Default for Attributes {
fn default() -> Self {
Self::empty()
}
}
impl Attributes {
pub fn empty() -> Self {
Attributes {
attributes: Vec::new(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
use test_case::test_case;
#[test]
fn from_hashmap() {
let mut map = HashMap::new();
map.insert("id", "my-element");
map.insert("class", "my-css-class");
let mut sut = Attributes::from(map);
sut.attributes.sort();
assert_eq!(sut.attributes.len(), 2);
assert_eq!(
sut.attributes,
vec![
(String::from("class"), String::from("my-css-class")),
(String::from("id"), String::from("my-element")),
]
);
}
#[test_case(Vec::new(), "" ; "test_0")]
#[test_case(vec![("id", "my-id")], r#" id="my-id""# ; "test_1")]
#[test_case(vec![("id", "my-id"), ("class", "my-class")], r#" id="my-id" class="my-class""# ; "test_2")]
fn display(map: Vec<(&str, &str)>, expected: &str) {
let sut = Attributes::from(map);
assert_eq!(sut.to_string(), expected);
}
}