From 034710fe9784836a3dde5060d13fd99e31e322fc Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 16 Apr 2018 20:04:57 +0200 Subject: Rewrite icalendar API for nice builder pattern style building of objects (#22) --- src/util.rs | 48 ------------------------- src/vcard.rs | 113 +++++++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 95 insertions(+), 66 deletions(-) diff --git a/src/util.rs b/src/util.rs index f414ed7..6802e69 100644 --- a/src/util.rs +++ b/src/util.rs @@ -45,54 +45,6 @@ macro_rules! create_data_type { } } -macro_rules! make_builder_fn { - ( - fn $fnname:ident building $property_name:tt with_params, - $mapfn:expr => $( $arg_name:ident : $arg_type:ty ),* - ) => { - pub fn $fnname(mut self, params: $crate::param::Parameters, $( $arg_name : $arg_type ),*) -> Self { - let raw_value = vec![ $( $arg_name ),* ] - .into_iter() - .map($mapfn) - .collect::>() - .join(";"); - - let prop = Property { - name: String::from($property_name), - params: params, - raw_value: raw_value, - prop_group: None - }; - - self.0.props.entry(String::from($property_name)).or_insert(vec![]).push(prop); - self - } - }; - - ( - fn $fnname:ident building $property_name:tt, - $mapfn:expr => $( $arg_name:ident : $arg_type:ty ),* - ) => { - pub fn $fnname(mut self, $( $arg_name : $arg_type ),*) -> Self { - let raw_value = vec![ $( $arg_name ),* ] - .into_iter() - .map($mapfn) - .collect::>() - .join(";"); - - - let prop = Property { - name: String::from($property_name), - params: BTreeMap::new(), - raw_value: raw_value, - prop_group: None - }; - self.0.props.entry(String::from($property_name)).or_insert(vec![]).push(prop); - self - } - } -} - #[cfg(feature = "timeconversions")] pub const DATE_TIME_FMT : &'static str = "%Y%m%dT%H%M%SZ"; diff --git a/src/vcard.rs b/src/vcard.rs index 4191adc..a989d19 100644 --- a/src/vcard.rs +++ b/src/vcard.rs @@ -33,6 +33,11 @@ impl Vcard { }) } + /// Helper for `VcardBuilder::new()` + pub fn builder() -> VcardBuilder { + VcardBuilder::new() + } + /// Wrap a Component into a Vcard object, or don't do it if the Component is not a Vcard. pub fn from_component(c: Component)-> RResult { if c.name == "VCARD" { @@ -73,6 +78,92 @@ impl Vcard { make_getter_function_for_values!(url , "URL" , Url); make_getter_function_for_optional!(version , "VERSION" , Version); + fn set_properties(&mut self, props: BTreeMap>) { + self.0.props = props; + } + +} + +impl Default for Vcard { + fn default() -> Self { + Vcard(Component::new(String::from("VCARD"))) + } +} + +impl Deref for Vcard { + type Target = Component; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +/// A builder for building a Vcard object. +pub struct VcardBuilder { + properties: BTreeMap> +} + +macro_rules! make_builder_fn { + ( + fn $fnname:ident building $property_name:tt with_params, + $mapfn:expr => $( $arg_name:ident : $arg_type:ty ),* + ) => { + pub fn $fnname(mut self, params: $crate::param::Parameters, $( $arg_name : $arg_type ),*) -> Self { + let raw_value = vec![ $( $arg_name ),* ] + .into_iter() + .map($mapfn) + .collect::>() + .join(";"); + + let prop = Property { + name: String::from($property_name), + params: params, + raw_value: raw_value, + prop_group: None + }; + + self.properties.entry(String::from($property_name)).or_insert(vec![]).push(prop); + self + } + }; + + ( + fn $fnname:ident building $property_name:tt, + $mapfn:expr => $( $arg_name:ident : $arg_type:ty ),* + ) => { + pub fn $fnname(mut self, $( $arg_name : $arg_type ),*) -> Self { + let raw_value = vec![ $( $arg_name ),* ] + .into_iter() + .map($mapfn) + .collect::>() + .join(";"); + + + let prop = Property { + name: String::from($property_name), + params: BTreeMap::new(), + raw_value: raw_value, + prop_group: None + }; + self.properties.entry(String::from($property_name)).or_insert(vec![]).push(prop); + self + } + } +} + +impl VcardBuilder { + pub fn new() -> Self { + VcardBuilder { + properties: BTreeMap::new(), + } + } + + pub fn build(self) -> Result { + let mut v = Vcard::default(); + v.set_properties(self.properties); + Ok(v) + } + make_builder_fn!(fn with_adr building "ADR" with_params, |o| o.unwrap_or(String::from("")) => pobox : Option, @@ -123,20 +214,6 @@ impl Vcard { } -impl Default for Vcard { - fn default() -> Self { - Vcard(Component::new(String::from("VCARD"))) - } -} - -impl Deref for Vcard { - type Target = Component; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - create_data_type!(Adr); create_data_type!(Anniversary); create_data_type!(BDay); @@ -213,8 +290,6 @@ impl Name { } -pub struct VcardBuilder(Component); - #[cfg(test)] mod test { use super::Vcard; @@ -249,7 +324,7 @@ mod test { fn test_vcard_builder() { use component::write_component; - let build = Vcard::default() + let build = Vcard::builder() .with_name(parameters!(), None, Some("Mustermann".into()), @@ -270,7 +345,9 @@ mod test { Some("51147".into()), Some("Deutschland".into())) .with_email("erika@mustermann.de".into()) - .with_rev("20140301T221110Z".into()); + .with_rev("20140301T221110Z".into()) + .build() + .unwrap(); let build_string = write_component(&build); -- cgit v1.2.3