rrule 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2f4e67330d4bebaf8408d3125386565754c269ef
4
- data.tar.gz: e1bfbeadff4cd2cf622360d38357d954bd9f5984
3
+ metadata.gz: c26a3dfb1d12c01d066b7c664e6ea0da8fb5ead0
4
+ data.tar.gz: 1975eaa5dacd0363518d155f994a9966b837f682
5
5
  SHA512:
6
- metadata.gz: 55b57448971a919141f491bc141d017eb2bd98421ed0f7cf6bf79d51859fb5cf5e6647d1c28b9738e4465258108fa436be006466b25428823a49b6220808216f
7
- data.tar.gz: 72792b23c6a0e483a37d16501d1a79a2efc2303e1e0113bf03dc83bcd6775933f0a946bbf7c3f52be211d17a5e87560977874f57b90223af567a2f2a302a8bc0
6
+ metadata.gz: a9f362bd929a06f539e69df842cebb0052f3f841b624d36e01edb9dca64e4c5f472da54b3d671df6089a991b6b4bd1b0bbe39502409274d5636ab68a81e6ed22
7
+ data.tar.gz: 70400ae4f025bcee80979056cfec688a16e5be6fd948a07d905fa9f5e48ec7d8f62df31d84f8d0181e001aa6ee27e89fb3c39250b6df85195eb91739876cc14a
data/README.md CHANGED
@@ -64,7 +64,7 @@ rrule.all
64
64
 
65
65
  ## License
66
66
 
67
- Copyright 2015 Square Inc.
67
+ Copyright 2018 Square Inc.
68
68
 
69
69
  Licensed under the Apache License, Version 2.0 (the "License");
70
70
  you may not use this file except in compliance with the License.
data/lib/rrule.rb CHANGED
@@ -8,6 +8,7 @@ module RRule
8
8
  autoload :Frequency, 'rrule/frequencies/frequency'
9
9
  autoload :Daily, 'rrule/frequencies/daily'
10
10
  autoload :Weekly, 'rrule/frequencies/weekly'
11
+ autoload :SimpleWeekly, 'rrule/frequencies/simple_weekly'
11
12
  autoload :Monthly, 'rrule/frequencies/monthly'
12
13
  autoload :Yearly, 'rrule/frequencies/yearly'
13
14
 
@@ -1,10 +1,13 @@
1
1
  module RRule
2
2
  class Frequency
3
- attr_reader :current_date
3
+ attr_reader :current_date, :filters, :generator, :timeset
4
4
 
5
- def initialize(context)
5
+ def initialize(context, filters, generator, timeset)
6
6
  @context = context
7
7
  @current_date = context.dtstart
8
+ @filters = filters
9
+ @generator = generator
10
+ @timeset = timeset
8
11
  end
9
12
 
10
13
  def advance
@@ -15,10 +18,41 @@ module RRule
15
18
  end
16
19
  end
17
20
 
21
+ def next_occurrences
22
+ possible_days_of_year = possible_days
23
+
24
+ if filters.present?
25
+ possible_days_of_year.each_with_index do |day_index, i|
26
+ possible_days_of_year[i] = nil if filters.any? { |filter| filter.reject?(day_index) }
27
+ end
28
+ end
29
+
30
+ generator.combine_dates_and_times(possible_days_of_year, timeset).tap do
31
+ advance
32
+ end
33
+ end
34
+
18
35
  def possible_days
19
36
  fail NotImplementedError
20
37
  end
21
38
 
39
+ def self.for_options(options)
40
+ case options[:freq]
41
+ when 'DAILY'
42
+ Daily
43
+ when 'WEEKLY'
44
+ if options[:simple_weekly] && !options[:bymonth]
45
+ SimpleWeekly # simplified and faster version if we don't need to deal with filtering
46
+ else
47
+ Weekly
48
+ end
49
+ when 'MONTHLY'
50
+ Monthly
51
+ when 'YEARLY'
52
+ Yearly
53
+ end
54
+ end
55
+
22
56
  private
23
57
 
24
58
  attr_reader :context
@@ -0,0 +1,9 @@
1
+ module RRule
2
+ class SimpleWeekly < Frequency
3
+ def next_occurrences
4
+ this_occurrence = current_date
5
+ @current_date += context.options[:interval].weeks
6
+ [this_occurrence]
7
+ end
8
+ end
9
+ end
data/lib/rrule/rule.rb CHANGED
@@ -31,18 +31,6 @@ module RRule
31
31
  count = options[:count]
32
32
 
33
33
  filters = []
34
-
35
- frequency = case options[:freq]
36
- when 'DAILY'
37
- Daily.new(context)
38
- when 'WEEKLY'
39
- Weekly.new(context)
40
- when 'MONTHLY'
41
- Monthly.new(context)
42
- when 'YEARLY'
43
- Yearly.new(context)
44
- end
45
-
46
34
  if options[:bymonth]
47
35
  filters.push(ByMonth.new(options[:bymonth], context))
48
36
  end
@@ -69,24 +57,17 @@ module RRule
69
57
  generator = AllOccurrences.new(context)
70
58
  end
71
59
 
60
+ frequency = Frequency.for_options(options).new(context, filters, generator, timeset)
61
+
72
62
  loop do
73
63
  return if frequency.current_date.year > MAX_YEAR
74
64
 
75
- possible_days_of_year = frequency.possible_days
76
-
77
- possible_days_of_year.each_with_index do |day_index, i|
78
- possible_days_of_year[i] = nil if filters.any? { |filter| filter.reject?(day_index) }
79
- end
80
-
81
- results_with_time = generator.combine_dates_and_times(possible_days_of_year, timeset)
82
- results_with_time.each do |this_result|
65
+ frequency.next_occurrences.each do |this_result|
83
66
  next if this_result < dtstart
84
67
  return if options[:until] && this_result > options[:until]
85
68
  return if count && (count -= 1) < 0
86
69
  yield this_result unless exdate.include?(this_result)
87
70
  end
88
-
89
- frequency.advance
90
71
  end
91
72
  end
92
73
 
@@ -99,7 +80,6 @@ module RRule
99
80
  attr_reader :options
100
81
 
101
82
  def floor_to_seconds(date)
102
- return date
103
83
  # This removes all sub-second and floors it to the second level.
104
84
  # Sub-second level calculations breaks a lot of assumptions in this
105
85
  # library and rounding it may also cause unexpected inequalities.
@@ -165,6 +145,7 @@ module RRule
165
145
  when 'MONTHLY'
166
146
  options[:bymonthday] = [dtstart.day]
167
147
  when 'WEEKLY'
148
+ options[:simple_weekly] = true
168
149
  options[:byweekday] = [Weekday.new(dtstart.wday)]
169
150
  end
170
151
  end
data/rrule.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rrule'
3
- s.version = '0.2.1'
4
- s.date = '2016-06-06'
3
+ s.version = '0.3.0'
4
+ s.date = '2018-04-23'
5
5
  s.summary = 'RRule expansion'
6
6
  s.description = 'A gem for expanding dates according to the RRule specification'
7
7
  s.authors = ['Ryan Mitchell']
@@ -0,0 +1,17 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '../lib/'))
2
+ require 'rrule'
3
+ include Benchmark
4
+
5
+ rules_to_benchmark = ['FREQ=WEEKLY', 'FREQ=WEEKLY;BYDAY=WE']
6
+ rrule_version = '0.3.0'
7
+
8
+ puts "Benchmarking rules in version #{rrule_version}: 1000 expansions over one month\n"
9
+ Benchmark.benchmark(CAPTION, rules_to_benchmark.map(&:size).max, FORMAT) do |bm|
10
+ rules_to_benchmark.each do |rule|
11
+ rrule = RRule.parse(rule, dtstart: Time.parse('Wed Jan 30 09:00:00 PST 2013'), tzid: 'America/Chicago')
12
+ bm.report(rule) do
13
+ 1000.times { rrule.between(Time.parse('Sun Jul 31 22:00:00 PDT 2016'), Time.parse('Wed Aug 31 21:59:59 PDT 2016')) }
14
+ end
15
+ end
16
+ end
17
+ puts "\n"
@@ -0,0 +1,5 @@
1
+ Benchmarking rules in version 0.3.0
2
+ user system total real
3
+ FREQ=WEEKLY 7.190000 0.040000 7.230000 ( 7.242336)
4
+ FREQ=WEEKLY;BYDAY=WE 12.770000 0.070000 12.840000 ( 12.857210)
5
+
@@ -1,55 +1,62 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe RRule::Daily do
4
+ let(:interval) { 1 }
4
5
  let(:context) do
5
6
  RRule::Context.new(
6
- { interval: 1 },
7
+ { interval: interval },
7
8
  date,
8
9
  'America/Los_Angeles'
9
10
  )
10
11
  end
12
+ let(:filters) { [] }
13
+ let(:generator) { RRule::AllOccurrences.new(context) }
14
+ let(:timeset) { [{ hour: date.hour, minute: date.min, second: date.sec }] }
11
15
 
12
- describe '#possible_days' do
13
- subject { described_class.new(context).possible_days }
16
+ before { context.rebuild(date.year, date.month) }
14
17
 
15
- context 'on the first day of the year' do
16
- let(:date) { Date.new(1997, 1, 1)}
18
+ describe '#next_occurrences' do
19
+ subject(:frequency) { described_class.new(context, filters, generator, timeset) }
17
20
 
18
- it { is_expected.to eql [0] }
19
- end
20
-
21
- context 'on a day in the first month' do
22
- let(:date) { Date.new(1997, 1, 25)}
21
+ context 'with an interval of one' do
22
+ let(:date) { Time.zone.local(1997, 1, 1) }
23
23
 
24
- it { is_expected.to eql [24] }
24
+ it 'returns sequential days' do
25
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1)]
26
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 2)]
27
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 3)]
28
+ end
25
29
  end
26
30
 
27
- context 'on a day in the next month' do
28
- let(:date) { Date.new(1997, 2, 25)}
29
-
30
- it { is_expected.to eql [55] }
31
- end
32
- end
33
-
34
- describe '#advance' do
35
- subject { described_class.new(context).advance }
36
-
37
- context 'on the first day of the year' do
38
- let(:date) { Date.new(1997, 1, 1)}
31
+ context 'with an interval of two' do
32
+ let(:interval) { 2 }
33
+ let(:date) { Time.zone.local(1997, 1, 1) }
39
34
 
40
- it { is_expected.to eql date + 1.day }
35
+ it 'returns every other day' do
36
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1)]
37
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 3)]
38
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 5)]
39
+ end
41
40
  end
42
41
 
43
42
  context 'on the last day of February' do
44
- let(:date) { Date.new(1997, 2, 28)}
43
+ let(:date) { Time.zone.local(1997, 2, 28) }
45
44
 
46
- it { is_expected.to eql date + 1.day }
45
+ it 'goes into the next month' do
46
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 2, 28)]
47
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 3, 1)]
48
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 3, 2)]
49
+ end
47
50
  end
48
51
 
49
52
  context 'on the last day of the year' do
50
- let(:date) { Date.new(1997, 12, 31)}
53
+ let(:date) { Time.zone.local(1997, 12, 31) }
51
54
 
52
- it { is_expected.to eql date + 1.day }
55
+ it 'goes into the next year' do
56
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 12, 31)]
57
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1998, 1, 1)]
58
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1998, 1, 2)]
59
+ end
53
60
  end
54
61
  end
55
62
  end
@@ -1,57 +1,63 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe RRule::Monthly do
4
+ let(:interval) { 1 }
4
5
  let(:context) do
5
6
  RRule::Context.new(
6
- { interval: 1 },
7
+ { interval: interval },
7
8
  date,
8
9
  'America/Los_Angeles'
9
10
  )
10
11
  end
12
+ let(:filters) { [RRule::ByMonthDay.new([date.day], context)] }
13
+ let(:generator) { RRule::AllOccurrences.new(context) }
14
+ let(:timeset) { [{ hour: date.hour, minute: date.min, second: date.sec }] }
11
15
 
12
- before(:each) { context.rebuild(1997, 1) }
16
+ before { context.rebuild(date.year, date.month) }
13
17
 
14
- describe '#possible_days' do
15
- subject { described_class.new(context).possible_days }
18
+ describe '#next_occurrences' do
19
+ subject(:frequency) { described_class.new(context, filters, generator, timeset) }
16
20
 
17
- context 'on the first day of the year' do
18
- let(:date) { Date.new(1997, 1, 1)}
21
+ context 'with an interval of one' do
22
+ let(:date) { Time.zone.local(1997, 1, 1) }
19
23
 
20
- it { is_expected.to eql (0..30).to_a }
24
+ it 'returns sequential months' do
25
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1)]
26
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 2, 1)]
27
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 3, 1)]
28
+ end
21
29
  end
22
30
 
23
- context 'on a day in the first month' do
24
- let(:date) { Date.new(1997, 1, 25)}
31
+ context 'with an interval of two' do
32
+ let(:interval) { 2 }
33
+ let(:date) { Time.zone.local(1997, 1, 1) }
25
34
 
26
- it { is_expected.to eql (0..30).to_a }
27
- end
28
-
29
- context 'on a day in the next month' do
30
- let(:date) { Date.new(1997, 2, 25)}
31
-
32
- it { is_expected.to eql (31..58).to_a }
33
- end
34
- end
35
-
36
- describe '#advance' do
37
- subject { described_class.new(context).advance }
38
-
39
- context 'on the first day of the year' do
40
- let(:date) { Date.new(1997, 1, 1)}
41
-
42
- it { is_expected.to eql date + 1.month }
35
+ it 'returns every other month' do
36
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1)]
37
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 3, 1)]
38
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 5, 1)]
39
+ end
43
40
  end
44
41
 
45
42
  context 'on the last day of February' do
46
- let(:date) { Date.new(1997, 2, 28)}
43
+ let(:date) { Time.zone.local(1997, 2, 28) }
47
44
 
48
- it { is_expected.to eql date + 1.month }
45
+ it 'returns the next three months' do
46
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 2, 28)]
47
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 3, 28)]
48
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 4, 28)]
49
+ end
49
50
  end
50
51
 
51
52
  context 'on the last day of the year' do
52
- let(:date) { Date.new(1997, 12, 31)}
53
-
54
- it { is_expected.to eql date + 1.month }
53
+ let(:date) { Time.zone.local(1997, 12, 31) }
54
+
55
+ it 'returns empty arrays for periods with no matching occurrences' do
56
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 12, 31)]
57
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1998, 1, 31)]
58
+ expect(frequency.next_occurrences).to eql []
59
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1998, 3, 31)]
60
+ end
55
61
  end
56
62
  end
57
63
  end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe RRule::SimpleWeekly do
4
+ let(:context) { RRule::Context.new({ interval: interval }, date, nil) }
5
+ let(:frequency) { described_class.new(context, nil, nil, nil) }
6
+
7
+ describe '#next_occurrences' do
8
+ let(:date) { Date.new(1997, 1, 1) }
9
+
10
+ context 'with an interval of 1' do
11
+ let(:interval) { 1 }
12
+
13
+ it 'returns occurrences every week' do
14
+ expect(frequency.next_occurrences).to eql [Date.new(1997, 1, 1)]
15
+ expect(frequency.next_occurrences).to eql [Date.new(1997, 1, 8)]
16
+ expect(frequency.next_occurrences).to eql [Date.new(1997, 1, 15)]
17
+ end
18
+ end
19
+
20
+ context 'with an interval of 2' do
21
+ let(:interval) { 2 }
22
+
23
+ it 'returns occurrences every other week' do
24
+ expect(frequency.next_occurrences).to eql [Date.new(1997, 1, 1)]
25
+ expect(frequency.next_occurrences).to eql [Date.new(1997, 1, 15)]
26
+ expect(frequency.next_occurrences).to eql [Date.new(1997, 1, 29)]
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,57 +1,92 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe RRule::Weekly do
4
+ let(:interval) { 1 }
4
5
  let(:context) do
5
6
  RRule::Context.new(
6
- { interval: 1, wkst: 1 },
7
+ { interval: interval, wkst: 1 },
7
8
  date,
8
9
  'America/Los_Angeles'
9
10
  )
10
11
  end
12
+ let(:filters) { [RRule::ByWeekDay.new([RRule::Weekday.new(date.wday)], context)] }
13
+ let(:generator) { RRule::AllOccurrences.new(context) }
14
+ let(:timeset) { [{ hour: date.hour, minute: date.min, second: date.sec }] }
11
15
 
12
- before(:each) { context.rebuild(1997, 1) }
16
+ before { context.rebuild(date.year, date.month) }
13
17
 
14
- describe '#possible_days' do
15
- subject { described_class.new(context).possible_days }
18
+ describe '#next_occurrences' do
19
+ subject(:frequency) { described_class.new(context, filters, generator, timeset) }
16
20
 
17
- context 'on the first day of the year with five days left in the week' do
18
- let(:date) { Date.new(1997, 1, 1)}
21
+ context 'with an interval of one' do
22
+ let(:date) { Time.zone.local(1997, 1, 1) }
19
23
 
20
- it { is_expected.to eql (0..4).to_a }
24
+ it 'returns sequential weeks' do
25
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1)]
26
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 8)]
27
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 15)]
28
+ end
21
29
  end
22
30
 
23
- context 'on a day in the first month with two days left in the week' do
24
- let(:date) { Date.new(1997, 1, 25)}
31
+ context 'with an interval of two' do
32
+ let(:interval) { 2 }
33
+ let(:date) { Time.zone.local(1997, 1, 1) }
25
34
 
26
- it { is_expected.to eql (24..25).to_a }
35
+ it 'returns every other week' do
36
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1)]
37
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 15)]
38
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 29)]
39
+ end
27
40
  end
28
41
 
29
- context 'on a day in the next month with six days left in the week' do
30
- let(:date) { Date.new(1997, 2, 25)}
42
+ context 'on the first day of the year with five days left in the week' do
43
+ let(:date) { Time.zone.local(1997, 1, 1) }
31
44
 
32
- it { is_expected.to eql (55..60).to_a }
45
+ it 'returns the next three weeks' do
46
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1)]
47
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 8)]
48
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 15)]
49
+ end
33
50
  end
34
- end
35
51
 
36
- describe '#advance' do
37
- subject { described_class.new(context).advance }
52
+ context 'on a day in the first month with two days left in the week' do
53
+ let(:date) { Time.zone.local(1997, 1, 25) }
54
+
55
+ it 'returns the next three weeks' do
56
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 25)]
57
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 2, 1)]
58
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 2, 8)]
59
+ end
60
+ end
38
61
 
39
- context 'on the first day of the year' do
40
- let(:date) { Date.new(1997, 1, 1)}
62
+ context 'on a day in the next month with six days left in the week' do
63
+ let(:date) { Time.zone.local(1997, 2, 25) }
41
64
 
42
- it { is_expected.to eql date.next_week }
65
+ it 'returns the next three weeks' do
66
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 2, 25)]
67
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 3, 4)]
68
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 3, 11)]
69
+ end
43
70
  end
44
71
 
45
72
  context 'on the last day of February' do
46
- let(:date) { Date.new(1997, 2, 28)}
73
+ let(:date) { Time.zone.local(1997, 2, 28) }
47
74
 
48
- it { is_expected.to eql date.next_week }
75
+ it 'returns the next three weeks' do
76
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 2, 28)]
77
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 3, 7)]
78
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 3, 14)]
79
+ end
49
80
  end
50
81
 
51
82
  context 'on the last day of the year' do
52
- let(:date) { Date.new(1997, 12, 31)}
83
+ let(:date) { Time.zone.local(1997, 12, 31) }
53
84
 
54
- it { is_expected.to eql date.next_week }
85
+ it 'returns the next three weeks' do
86
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 12, 31)]
87
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1998, 1, 7)]
88
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1998, 1, 14)]
89
+ end
55
90
  end
56
91
  end
57
92
  end
@@ -1,52 +1,54 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe RRule::Yearly do
4
- let(:date) { Date.new(1997, 1, 1) }
4
+ let(:interval) { 1 }
5
5
  let(:context) do
6
6
  RRule::Context.new(
7
- { interval: 1, wkst: 1 },
7
+ { interval: interval, wkst: 1 },
8
8
  date,
9
9
  'America/Los_Angeles'
10
10
  )
11
11
  end
12
+ let(:filters) { [RRule::ByMonth.new([date.month], context), RRule::ByMonthDay.new([date.day], context)] }
13
+ let(:generator) { RRule::AllOccurrences.new(context) }
14
+ let(:timeset) { [{ hour: date.hour, minute: date.min, second: date.sec }] }
12
15
 
13
- before(:each) { context.rebuild(1997, 1) }
16
+ before(:each) { context.rebuild(date.year, date.month) }
14
17
 
15
- describe '#possible_days' do
16
- subject { described_class.new(context).possible_days }
17
-
18
- context 'in a non leap year' do
19
- before(:each) { context.rebuild(1997, 1) }
20
-
21
- it { is_expected.to eql (0..364).to_a }
22
- end
23
-
24
- context 'in a leap year' do
25
- before(:each) { context.rebuild(2000, 1) }
26
-
27
- it { is_expected.to eql (0..365).to_a }
28
- end
29
- end
30
-
31
- describe '#advance' do
32
- subject { described_class.new(context).advance }
18
+ describe '#next_occurrences' do
19
+ subject(:frequency) { described_class.new(context, filters, generator, timeset) }
33
20
 
34
21
  context 'on the first day of the year' do
35
- let(:date) { Date.new(1997, 1, 1)}
22
+ let(:date) { Time.zone.local(1997, 1, 1) }
36
23
 
37
- it { is_expected.to eql date + 1.year }
24
+ it 'returns the next three years' do
25
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1)]
26
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1998, 1, 1)]
27
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1999, 1, 1)]
28
+ end
38
29
  end
39
30
 
40
- context 'on the last day of February' do
41
- let(:date) { Date.new(1997, 2, 28)}
31
+ context 'on the last day of February in a leap year' do
32
+ let(:date) { Time.zone.local(2000, 2, 29) }
42
33
 
43
- it { is_expected.to eql date + 1.year }
34
+ it 'skips non-leap years' do
35
+ expect(frequency.next_occurrences).to eql [Time.zone.local(2000, 2, 29)]
36
+ expect(frequency.next_occurrences).to eql []
37
+ expect(frequency.next_occurrences).to eql []
38
+ expect(frequency.next_occurrences).to eql []
39
+ expect(frequency.next_occurrences).to eql [Time.zone.local(2004, 2, 29)]
40
+ end
44
41
  end
45
42
 
46
- context 'on the last day of the year' do
47
- let(:date) { Date.new(1997, 12, 31)}
43
+ context 'with an interval of two' do
44
+ let(:interval) { 2 }
45
+ let(:date) { Time.zone.local(1997, 1, 1) }
48
46
 
49
- it { is_expected.to eql date + 1.year }
47
+ it 'returns every other year' do
48
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1)]
49
+ expect(frequency.next_occurrences).to eql [Time.zone.local(1999, 1, 1)]
50
+ expect(frequency.next_occurrences).to eql [Time.zone.local(2001, 1, 1)]
51
+ end
50
52
  end
51
53
  end
52
54
  end
data/spec/spec_helper.rb CHANGED
@@ -19,3 +19,5 @@ RSpec.configure do |config|
19
19
  mocks.verify_partial_doubles = true
20
20
  end
21
21
  end
22
+
23
+ Time.zone = 'America/Los_Angeles'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rrule
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Mitchell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-06 00:00:00.000000000 Z
11
+ date: 2018-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -62,6 +62,7 @@ files:
62
62
  - lib/rrule/frequencies/daily.rb
63
63
  - lib/rrule/frequencies/frequency.rb
64
64
  - lib/rrule/frequencies/monthly.rb
65
+ - lib/rrule/frequencies/simple_weekly.rb
65
66
  - lib/rrule/frequencies/weekly.rb
66
67
  - lib/rrule/frequencies/yearly.rb
67
68
  - lib/rrule/generators/all_occurrences.rb
@@ -69,6 +70,8 @@ files:
69
70
  - lib/rrule/rule.rb
70
71
  - lib/rrule/weekday.rb
71
72
  - rrule.gemspec
73
+ - scripts/benchmark.rb
74
+ - scripts/history.txt
72
75
  - spec/context_spec.rb
73
76
  - spec/filters/by_month_day_spec.rb
74
77
  - spec/filters/by_month_spec.rb
@@ -77,6 +80,7 @@ files:
77
80
  - spec/filters/by_year_day_spec.rb
78
81
  - spec/frequencies/daily_spec.rb
79
82
  - spec/frequencies/monthly_spec.rb
83
+ - spec/frequencies/simple_weekly_spec.rb
80
84
  - spec/frequencies/weekly_spec.rb
81
85
  - spec/frequencies/yearly_spec.rb
82
86
  - spec/generators/all_occurrences_spec.rb
@@ -116,6 +120,7 @@ test_files:
116
120
  - spec/filters/by_year_day_spec.rb
117
121
  - spec/frequencies/daily_spec.rb
118
122
  - spec/frequencies/monthly_spec.rb
123
+ - spec/frequencies/simple_weekly_spec.rb
119
124
  - spec/frequencies/weekly_spec.rb
120
125
  - spec/frequencies/yearly_spec.rb
121
126
  - spec/generators/all_occurrences_spec.rb