rrule 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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