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 +4 -4
- data/README.md +1 -1
- data/lib/rrule.rb +1 -0
- data/lib/rrule/frequencies/frequency.rb +36 -2
- data/lib/rrule/frequencies/simple_weekly.rb +9 -0
- data/lib/rrule/rule.rb +4 -23
- data/rrule.gemspec +2 -2
- data/scripts/benchmark.rb +17 -0
- data/scripts/history.txt +5 -0
- data/spec/frequencies/daily_spec.rb +35 -28
- data/spec/frequencies/monthly_spec.rb +37 -31
- data/spec/frequencies/simple_weekly_spec.rb +30 -0
- data/spec/frequencies/weekly_spec.rb +58 -23
- data/spec/frequencies/yearly_spec.rb +31 -29
- data/spec/spec_helper.rb +2 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c26a3dfb1d12c01d066b7c664e6ea0da8fb5ead0
|
4
|
+
data.tar.gz: 1975eaa5dacd0363518d155f994a9966b837f682
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a9f362bd929a06f539e69df842cebb0052f3f841b624d36e01edb9dca64e4c5f472da54b3d671df6089a991b6b4bd1b0bbe39502409274d5636ab68a81e6ed22
|
7
|
+
data.tar.gz: 70400ae4f025bcee80979056cfec688a16e5be6fd948a07d905fa9f5e48ec7d8f62df31d84f8d0181e001aa6ee27e89fb3c39250b6df85195eb91739876cc14a
|
data/README.md
CHANGED
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
|
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
|
-
|
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.
|
4
|
-
s.date = '
|
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"
|
data/scripts/history.txt
ADDED
@@ -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:
|
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
|
-
|
13
|
-
subject { described_class.new(context).possible_days }
|
16
|
+
before { context.rebuild(date.year, date.month) }
|
14
17
|
|
15
|
-
|
16
|
-
|
18
|
+
describe '#next_occurrences' do
|
19
|
+
subject(:frequency) { described_class.new(context, filters, generator, timeset) }
|
17
20
|
|
18
|
-
|
19
|
-
|
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
|
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 '
|
28
|
-
let(:
|
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
|
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) {
|
43
|
+
let(:date) { Time.zone.local(1997, 2, 28) }
|
45
44
|
|
46
|
-
it
|
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) {
|
53
|
+
let(:date) { Time.zone.local(1997, 12, 31) }
|
51
54
|
|
52
|
-
it
|
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:
|
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
|
16
|
+
before { context.rebuild(date.year, date.month) }
|
13
17
|
|
14
|
-
describe '#
|
15
|
-
subject { described_class.new(context)
|
18
|
+
describe '#next_occurrences' do
|
19
|
+
subject(:frequency) { described_class.new(context, filters, generator, timeset) }
|
16
20
|
|
17
|
-
context '
|
18
|
-
let(:date) {
|
21
|
+
context 'with an interval of one' do
|
22
|
+
let(:date) { Time.zone.local(1997, 1, 1) }
|
19
23
|
|
20
|
-
it
|
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 '
|
24
|
-
let(:
|
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
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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) {
|
43
|
+
let(:date) { Time.zone.local(1997, 2, 28) }
|
47
44
|
|
48
|
-
it
|
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) {
|
53
|
-
|
54
|
-
it
|
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:
|
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
|
16
|
+
before { context.rebuild(date.year, date.month) }
|
13
17
|
|
14
|
-
describe '#
|
15
|
-
subject { described_class.new(context)
|
18
|
+
describe '#next_occurrences' do
|
19
|
+
subject(:frequency) { described_class.new(context, filters, generator, timeset) }
|
16
20
|
|
17
|
-
context '
|
18
|
-
let(:date) {
|
21
|
+
context 'with an interval of one' do
|
22
|
+
let(:date) { Time.zone.local(1997, 1, 1) }
|
19
23
|
|
20
|
-
it
|
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 '
|
24
|
-
let(:
|
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
|
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
|
30
|
-
let(:date) {
|
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
|
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
|
-
|
37
|
-
|
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
|
40
|
-
let(:date) {
|
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
|
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) {
|
73
|
+
let(:date) { Time.zone.local(1997, 2, 28) }
|
47
74
|
|
48
|
-
it
|
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) {
|
83
|
+
let(:date) { Time.zone.local(1997, 12, 31) }
|
53
84
|
|
54
|
-
it
|
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(:
|
4
|
+
let(:interval) { 1 }
|
5
5
|
let(:context) do
|
6
6
|
RRule::Context.new(
|
7
|
-
{ interval:
|
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(
|
16
|
+
before(:each) { context.rebuild(date.year, date.month) }
|
14
17
|
|
15
|
-
describe '#
|
16
|
-
subject { described_class.new(context)
|
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) {
|
22
|
+
let(:date) { Time.zone.local(1997, 1, 1) }
|
36
23
|
|
37
|
-
it
|
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) {
|
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
|
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 '
|
47
|
-
let(:
|
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
|
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
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.
|
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:
|
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
|