From ed603b788b23535b086f2a7491627e018e8dce5d Mon Sep 17 00:00:00 2001 From: Fredrik Meringdal Date: Sun, 1 Nov 2020 21:22:20 +0100 Subject: docs and removed some stuff from options --- README.md | 6 +++--- src/lib.rs | 36 ++++++++++++++++++------------------ src/options.rs | 13 +++---------- src/parse_options.rs | 15 ++++++++------- src/rrule.rs | 32 ++++++++++++++++++++++++++------ src/rruleset.rs | 43 +++++++++++++++++++++++++++---------------- src/rruleset_iter.rs | 6 +++--- src/rrulestr.rs | 9 +++------ tests/rrule.rs | 2 -- 9 files changed, 91 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index b753437..f394759 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,9 @@ use rrule::build_rrule; let mut rrule = build_rrule("DTSTART:20120201T093000Z\nRRULE:FREQ=DAILY;COUNT=3").unwrap(); -// Get all occurrences of the rrule -let occurences = rrule.all(); -assert_eq!(occurences.len(), 3); +// Get all recurrences of the rrule +let recurrences = rrule.all(); +assert_eq!(recurrences.len(), 3); ``` # Documentation and more examples diff --git a/src/lib.rs b/src/lib.rs index 00eaaad..6685810 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,14 +52,14 @@ //! //! // Construct `RRule` from options //! let mut rrule = RRule::new(options); -//! let occurences = rrule.all(); +//! let recurrences = rrule.all(); //! for i in 0..5 { -//! assert_eq!(occurences[i].year(), 2020); -//! assert_eq!(occurences[i].month(), 1); -//! assert_eq!(occurences[i].day(), 1 + i as u32); -//! assert_eq!(occurences[i].hour(), 9); +//! assert_eq!(recurrences[i].year(), 2020); +//! assert_eq!(recurrences[i].month(), 1); +//! assert_eq!(recurrences[i].day(), 1 + i as u32); +//! assert_eq!(recurrences[i].hour(), 9); //! } -//! assert_eq!(occurences.len(), 5); +//! assert_eq!(recurrences.len(), 5); //! //! //! @@ -68,7 +68,7 @@ //! // Construct RRuleSet from one rrule and exrule //! // The rrule will occur weekly on Tuesday and Wednesday and the exrule //! // will occur weekly on Wednesday, and therefore the end result will contain -//! // weekly occurences just on Wednesday. +//! // weekly recurrences just on Wednesday. //! //! //! // Build options for rrule that occurs weekly on Tuesday and Wednesday @@ -101,13 +101,13 @@ //! rrule_set.rrule(rrule); //! rrule_set.exrule(exrule); //! -//! let occurences = rrule_set.all(); +//! let recurrences = rrule_set.all(); //! -//! for occurence in &occurences { +//! for occurence in &recurrences { //! assert_eq!(occurence.weekday(), Weekday::Tue); //! } //! -//! assert_eq!(occurences.len(), 2); +//! assert_eq!(recurrences.len(), 2); //! ``` //! //! @@ -126,14 +126,14 @@ //! use rrule::{RRule, RRuleSet, Options, Frequenzy, Weekday}; //! //! // SOME NOTES: -//! // Occurences produced by an rrule will be in the same timezone +//! // recurrences produced by an rrule will be in the same timezone //! // as the start datetime provided (dtstart). The `until` datetime MUST //! // always be specified with the UTC timezone if it is specified. //! //! // Example: -//! // The following examples uses the RRuleSet type with an RRule that yields occurences +//! // The following examples uses the RRuleSet type with an RRule that yields recurrences //! // in the Europe/Berlin timezone, and one EXDATE that is specified -//! // in UTC and collides (and therefore filters away) with one of those occurences. +//! // in UTC and collides (and therefore filters away) with one of those recurrences. //! //! //! // Build options for rrule that occurs daily at 9 oclock for 4 times @@ -155,9 +155,9 @@ //! rrule_set.rrule(rrule); //! rrule_set.exdate(exdate); //! -//! let occurences = rrule_set.all(); -//! // RRule contained 4 occurences but 1 was filtered away by the exdate -//! assert_eq!(occurences.len(), 3); +//! let recurrences = rrule_set.all(); +//! // RRule contained 4 recurrences but 1 was filtered away by the exdate +//! assert_eq!(recurrences.len(), 3); //! //! // If you want to get back the DateTimes in another timezone you can just iterate over the result //! // and convert them to another timezone by using the with_timzone method provided by the DateTime type. @@ -166,12 +166,12 @@ //! // Example of converting to mocow timezone //! use chrono_tz::Europe::Moscow; //! -//! let occurences_in_moscow_tz: Vec> = occurences.iter() +//! let recurrences_in_moscow_tz: Vec> = recurrences.iter() //! .map(|d| d.with_timezone(&Moscow)).collect(); //! //! //! // Example of converting to local timezone (Local comes from chrono::prelude::*) -//! let occurences_in_local_tz: Vec> = occurences.iter() +//! let recurrences_in_local_tz: Vec> = recurrences.iter() //! .map(|d| d.with_timezone(&Local)).collect(); //! //! diff --git a/src/options.rs b/src/options.rs index 884ecb6..31f884b 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,7 +1,7 @@ use crate::datetime::{get_weekday_val, DTime}; use crate::parse_options::parse_options; use chrono::prelude::*; -use chrono_tz::Tz; +use chrono_tz::{Tz, UTC}; use std::error::Error; use std::fmt::{Display, Formatter}; @@ -39,7 +39,6 @@ pub struct ParsedOptions { pub byeaster: Option, } -// TODO: PartialOptions shouldnt have all of these fields #[derive(Debug, Clone)] pub struct Options { pub freq: Option, @@ -52,14 +51,12 @@ pub struct Options { pub bysetpos: Option>, pub bymonth: Option>, pub bymonthday: Option>, - pub bynmonthday: Option>, pub byyearday: Option>, pub byweekno: Option>, pub byweekday: Option>, pub byhour: Option>, pub byminute: Option>, pub bysecond: Option>, - pub bynweekday: Option>>, pub byeaster: Option, } @@ -76,14 +73,12 @@ impl Options { bysetpos: None, bymonth: None, bymonthday: None, - bynmonthday: None, byyearday: None, byweekno: None, byweekday: None, byhour: None, byminute: None, bysecond: None, - bynweekday: None, byeaster: None, } } @@ -108,14 +103,12 @@ impl Options { bysetpos: Self::is_some_or_none(&opt1.bysetpos, &opt2.bysetpos).clone(), bymonth: Self::is_some_or_none(&opt1.bymonth, &opt2.bymonth).clone(), bymonthday: Self::is_some_or_none(&opt1.bymonthday, &opt2.bymonthday).clone(), - bynmonthday: Self::is_some_or_none(&opt1.bynmonthday, &opt2.bynmonthday).clone(), byyearday: Self::is_some_or_none(&opt1.byyearday, &opt2.byyearday).clone(), byweekno: Self::is_some_or_none(&opt1.byweekno, &opt2.byweekno).clone(), byweekday: Self::is_some_or_none(&opt1.byweekday, &opt2.byweekday).clone(), byhour: Self::is_some_or_none(&opt1.byhour, &opt2.byhour).clone(), byminute: Self::is_some_or_none(&opt1.byminute, &opt2.byminute).clone(), bysecond: Self::is_some_or_none(&opt1.bysecond, &opt2.bysecond).clone(), - bynweekday: Self::is_some_or_none(&opt1.bynweekday, &opt2.bynweekday).clone(), byeaster: Self::is_some_or_none(&opt1.byeaster, &opt2.byeaster).clone(), } } @@ -135,8 +128,8 @@ impl Options { self } - pub fn until(mut self, until: DTime) -> Self { - self.until = Some(until); + pub fn until(mut self, until: DateTime) -> Self { + self.until = Some(until.with_timezone(&UTC)); self } diff --git a/src/parse_options.rs b/src/parse_options.rs index 727da86..0387e51 100644 --- a/src/parse_options.rs +++ b/src/parse_options.rs @@ -15,6 +15,9 @@ pub fn parse_options(options: &Options) -> Result> = vec![]; + let mut bynmonthday: Vec = vec![]; + let mut partial_options = Options::concat(&default_partial_options, options); if partial_options.byeaster.is_some() { @@ -72,10 +75,9 @@ pub fn parse_options(options: &Options) -> Result partial_options.bynmonthday = None, + None => bynmonthday = vec![], Some(opts_bymonthday) => { let mut bymonthday = vec![]; - let mut bynmonthday = vec![]; for v in opts_bymonthday { if *v > 0 { @@ -86,13 +88,12 @@ pub fn parse_options(options: &Options) -> Result Result Vec> { let iter_args = IterArgs { inc: true, @@ -26,8 +27,11 @@ impl RRule { let res = iter(&mut iter_res, &mut self.options); res } - - pub fn before(&mut self, dt: DateTime, inc: bool) -> Vec> { + + /// Returns the last recurrence before the given datetime instance. + /// The inc keyword defines what happens if dt is an recurrence. + /// With inc == true, if dt itself is an recurrence, it will be returned. + pub fn before(&mut self, dt: DateTime, inc: bool) -> Option> { let iter_args = IterArgs { inc, before: None, @@ -36,10 +40,18 @@ impl RRule { }; let mut iter_res = RRuleIterRes::new(QueryMethodTypes::Before, iter_args); - iter(&mut iter_res, &mut self.options) + let recurrences = iter(&mut iter_res, &mut self.options); + if recurrences.is_empty() { + None + } else { + Some(recurrences[0]) + } } - pub fn after(&mut self, dt: DateTime, inc: bool) -> Vec> { + /// Returns the last recurrence after the given datetime instance. + /// The inc keyword defines what happens if dt is an recurrence. + /// With inc == true, if dt itself is an recurrence, it will be returned. + pub fn after(&mut self, dt: DateTime, inc: bool) -> Option> { let iter_args = IterArgs { inc, before: None, @@ -47,10 +59,18 @@ impl RRule { dt: Some(dt), }; let mut iter_res = RRuleIterRes::new(QueryMethodTypes::After, iter_args); - - iter(&mut iter_res, &mut self.options) + let recurrences = iter(&mut iter_res, &mut self.options); + if recurrences.is_empty() { + None + } else { + Some(recurrences[0]) + } } + /// Returns all the recurrences of the rrule between after and before. + /// The inc keyword defines what happens if after and/or before are + /// themselves recurrences. With inc == true, they will be included in the + /// list, if they are found in the recurrence set. pub fn between( &mut self, after: DateTime, diff --git a/src/rruleset.rs b/src/rruleset.rs index 4a3caa5..4bea086 100644 --- a/src/rruleset.rs +++ b/src/rruleset.rs @@ -40,30 +40,41 @@ impl RRuleSet { self.exdate.push(exdate); } + /// Returns all the recurrences of the rruleset pub fn all(&mut self) -> Vec> { let mut iter = RRuleSetIter::all(self); iter.iter() } /// Returns the last recurrence before the given datetime instance. - /// The inc keyword defines what happens if dt is an occurrence. - /// With inc == true, if dt itself is an occurrence, it will be returned. - pub fn before(&mut self, date: DateTime, inc: bool) -> Vec> { + /// The inc keyword defines what happens if dt is an recurrence. + /// With inc == true, if dt itself is an recurrence, it will be returned. + pub fn before(&mut self, date: DateTime, inc: bool) -> Option> { let mut iter = RRuleSetIter::before(self, date, inc); - iter.iter() + let recurrences = iter.iter(); + if recurrences.is_empty() { + None + } else { + Some(recurrences[0]) + } } /// Returns the last recurrence after the given datetime instance. - /// The inc keyword defines what happens if dt is an occurrence. - /// With inc == true, if dt itself is an occurrence, it will be returned. - pub fn after(&mut self, date: DateTime, inc: bool) -> Vec> { + /// The inc keyword defines what happens if dt is an recurrence. + /// With inc == true, if dt itself is an recurrence, it will be returned. + pub fn after(&mut self, date: DateTime, inc: bool) -> Option> { let mut iter = RRuleSetIter::after(self, date, inc); - iter.iter() + let recurrences = iter.iter(); + if recurrences.is_empty() { + None + } else { + Some(recurrences[0]) + } } - /// Returns all the occurrences of the rrule between after and before. + /// Returns all the recurrences of the rrule between after and before. /// The inc keyword defines what happens if after and/or before are - /// themselves occurrences. With inc == True, they will be included in the + /// themselves recurrences. With inc == true, they will be included in the /// list, if they are found in the recurrence set. pub fn between( &mut self, @@ -396,9 +407,9 @@ mod test_iter_set { let rrule = RRule::new(options); set.exrule(rrule); - test_recurring( - set.before(ymd_hms_2(2015, 9, 2, 9, 0, 0), false), - vec![ymd_hms_2(2014, 9, 2, 9, 0, 0)], + assert_eq!( + set.before(ymd_hms_2(2015, 9, 2, 9, 0, 0), false).unwrap(), + ymd_hms_2(2014, 9, 2, 9, 0, 0), ); } @@ -454,9 +465,9 @@ mod test_iter_set { let rrule = RRule::new(options); set.exrule(rrule); - test_recurring( - set.after(ymd_hms_2(2000, 9, 2, 9, 0, 0), false), - vec![ymd_hms_2(2007, 9, 2, 9, 0, 0)], + assert_eq!( + set.after(ymd_hms_2(2000, 9, 2, 9, 0, 0), false).unwrap(), + ymd_hms_2(2007, 9, 2, 9, 0, 0), ); } diff --git a/src/rruleset_iter.rs b/src/rruleset_iter.rs index 0b3fe35..9cc2c3e 100644 --- a/src/rruleset_iter.rs +++ b/src/rruleset_iter.rs @@ -8,7 +8,7 @@ use std::collections::HashMap; /// Result iterator for the RRuleSet type. It mostly just wraps /// `RRuleIterRes` and also before accepting any date makes sure that /// it does not collide with any exdates provided by either the exdates property -/// or produced by the exrule rules. +/// or any occurence produced by any of the the exrules. pub struct RRuleSetIter<'a> { exdate_hash: HashMap, iter_res: RRuleIterRes, @@ -95,7 +95,7 @@ impl<'a> RRuleSetIter<'a> { } } - /// Here it is required to recompute exrules to see if some of the occurences will collide with the provided date. + /// Here it is required to recompute exrules to see if some of the recurrences will collide with the provided date. fn accept_when_unknown_bounds(&mut self, date: DateTime) -> bool { let dt = date.timestamp(); if !self.exdate_hash.contains_key(&dt) { @@ -112,7 +112,7 @@ impl<'a> RRuleSetIter<'a> { true } - /// No need to recompute exrules as it has already beeen computed in the start of the iter method + /// No need to recompute exrules as it has already been computed in the start of the iter method /// because the bounds where known. fn accept_when_known_bounds(&mut self, date: DateTime) -> bool { let dt = date.timestamp(); diff --git a/src/rrulestr.rs b/src/rrulestr.rs index 20670f8..62a2e29 100644 --- a/src/rrulestr.rs +++ b/src/rrulestr.rs @@ -9,23 +9,20 @@ use once_cell::sync::Lazy; use regex::Regex; use std::str::FromStr; +/// Some regex used for parsing the rrule string. static DATESTR_RE: Lazy = Lazy::new(|| Regex::new(r"(?m)^(\d{4})(\d{2})(\d{2})(T(\d{2})(\d{2})(\d{2})Z?)?$").unwrap()); static DTSTART_RE: Lazy = Lazy::new(|| Regex::new(r"(?m)DTSTART(?:;TZID=([^:=]+?))?(?::|=)([^;\s]+)").unwrap()); - static RRULE_RE: Lazy = Lazy::new(|| Regex::new(r"(?m)^(?:RRULE|EXRULE):").unwrap()); - static PARSE_LINE_RE_1: Lazy = Lazy::new(|| Regex::new(r"(?m)^\s+|\s+$").unwrap()); static PARSE_LINE_RE_2: Lazy = Lazy::new(|| Regex::new(r"(?m)^([A-Z]+?)[:;]").unwrap()); - static RDATE_RE: Lazy = Lazy::new(|| Regex::new(r"(?m)RDATE(?:;TZID=([^:=]+))?").unwrap()); static EXDATE_RE: Lazy = Lazy::new(|| Regex::new(r"(?m)EXDATE(?:;TZID=([^:=]+))?").unwrap()); - - static DATETIME_RE: Lazy = Lazy::new(|| Regex::new(r"(?m)(VALUE=DATE(-TIME)?)|(TZID=)").unwrap()); + fn parse_datestring_bit( bits: ®ex::Captures, i: usize, @@ -171,7 +168,7 @@ fn parse_rrule(line: &str) -> Result { options.interval = Some(interval); } "BYSETPOS" => { - let bysetpos = stringval_to_intvec(value, |pos| true, format!("Invalid bysetpos value"))?; + let bysetpos = stringval_to_intvec(value, |_pos| true, format!("Invalid bysetpos value"))?; options.bysetpos = Some(bysetpos); } "BYMONTH" => { diff --git a/tests/rrule.rs b/tests/rrule.rs index d62ebe3..bfb6f7c 100644 --- a/tests/rrule.rs +++ b/tests/rrule.rs @@ -5333,7 +5333,6 @@ mod test { #[test] fn minutely_by_yeardayneg() { - let start = std::time::SystemTime::now(); let options = ParsedOptions { freq: Frequenzy::Minutely, count: Some(4), @@ -6197,7 +6196,6 @@ mod test { #[test] fn secondly_by_yeardayneg() { - let start = std::time::SystemTime::now(); let options = ParsedOptions { freq: Frequenzy::Secondly, count: Some(4), -- cgit v1.2.3