ical_importer 0.0.1
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.
- data/.rspec +2 -0
- data/.rvmrc +5 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +34 -0
- data/README.md +74 -0
- data/Rakefile +13 -0
- data/ical_importer.gemspec +25 -0
- data/lib/ical_importer/builder.rb +22 -0
- data/lib/ical_importer/collector.rb +25 -0
- data/lib/ical_importer/date_exclusion.rb +11 -0
- data/lib/ical_importer/local_event.rb +59 -0
- data/lib/ical_importer/parser.rb +75 -0
- data/lib/ical_importer/recurrence_event_builder.rb +37 -0
- data/lib/ical_importer/remote_event.rb +54 -0
- data/lib/ical_importer/single_event_builder.rb +128 -0
- data/lib/ical_importer/version.rb +3 -0
- data/lib/ical_importer.rb +11 -0
- data/spec/ical_importer/builder_spec.rb +45 -0
- data/spec/ical_importer/collector_spec.rb +21 -0
- data/spec/ical_importer/date_exclusion_spec.rb +30 -0
- data/spec/ical_importer/local_event_spec.rb +126 -0
- data/spec/ical_importer/parser_spec.rb +126 -0
- data/spec/ical_importer/recurrence_event_builder_spec.rb +57 -0
- data/spec/ical_importer/remote_event_spec.rb +69 -0
- data/spec/ical_importer/single_event_builder_spec.rb +18 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/mn_twins.ics +1412 -0
- data/spec/support/test.ics +40 -0
- metadata +187 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module IcalImporter
|
3
|
+
describe DateExclusion do
|
4
|
+
subject { DateExclusion.new(attributes) }
|
5
|
+
describe "#initialize" do
|
6
|
+
describe "set the one valid attribute" do
|
7
|
+
let(:attributes) { { :date_exclusion => "yerp" } }
|
8
|
+
it "sets the date exlcusion" do
|
9
|
+
subject.date_exclusion.should == "yerp"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "try to set valid/invalid attributes" do
|
14
|
+
let(:attributes) { { :date_exclusion => "yerp", :not_me => "nope" } }
|
15
|
+
it "sets the date exlcusion" do
|
16
|
+
subject.date_exclusion.should == "yerp"
|
17
|
+
expect { subject.not_me }.to raise_error(NoMethodError)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "set the one valid attribute" do
|
22
|
+
let(:attributes) { { :not_me => "yerp", :or_me => "nope" } }
|
23
|
+
it "sets the date exlcusion" do
|
24
|
+
expect { subject.not_me }.to raise_error(NoMethodError)
|
25
|
+
expect { subject.or_me }.to raise_error(NoMethodError)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module IcalImporter
|
3
|
+
describe LocalEvent do
|
4
|
+
subject { LocalEvent.new(attributes) }
|
5
|
+
describe "#init" do
|
6
|
+
let(:attributes) { {} }
|
7
|
+
it { should respond_to :uid }
|
8
|
+
it { should respond_to :title }
|
9
|
+
it { should respond_to :description }
|
10
|
+
it { should respond_to :location }
|
11
|
+
it { should respond_to :start_date_time }
|
12
|
+
it { should respond_to :end_date_time }
|
13
|
+
it { should respond_to :utc }
|
14
|
+
it { should respond_to :date_exclusions }
|
15
|
+
it { should respond_to :recur_end_date }
|
16
|
+
it { should respond_to :recur_month_repeat_by }
|
17
|
+
it { should respond_to :recur_interval }
|
18
|
+
it { should respond_to :recur_interval_value }
|
19
|
+
it { should respond_to :recur_end_date }
|
20
|
+
it { should respond_to :recurrence_id }
|
21
|
+
it { should respond_to :all_day_event }
|
22
|
+
it { should respond_to :recurrence }
|
23
|
+
it { should respond_to :recur_week_sunday }
|
24
|
+
it { should respond_to :recur_week_monday }
|
25
|
+
it { should respond_to :recur_week_tuesday }
|
26
|
+
it { should respond_to :recur_week_wednesday }
|
27
|
+
it { should respond_to :recur_week_thursday }
|
28
|
+
it { should respond_to :recur_week_friday }
|
29
|
+
it { should respond_to :recur_week_saturday }
|
30
|
+
it { should respond_to :uid= }
|
31
|
+
it { should respond_to :title= }
|
32
|
+
it { should respond_to :description= }
|
33
|
+
it { should respond_to :location= }
|
34
|
+
it { should respond_to :start_date_time= }
|
35
|
+
it { should respond_to :end_date_time= }
|
36
|
+
it { should respond_to :utc= }
|
37
|
+
it { should respond_to :date_exclusions= }
|
38
|
+
it { should respond_to :recur_end_date= }
|
39
|
+
it { should respond_to :recur_month_repeat_by= }
|
40
|
+
it { should respond_to :recur_interval= }
|
41
|
+
it { should respond_to :recur_interval_value= }
|
42
|
+
it { should respond_to :recur_end_date= }
|
43
|
+
it { should respond_to :recurrence_id= }
|
44
|
+
it { should respond_to :all_day_event= }
|
45
|
+
it { should respond_to :recurrence= }
|
46
|
+
it { should respond_to :recur_week_sunday= }
|
47
|
+
it { should respond_to :recur_week_monday= }
|
48
|
+
it { should respond_to :recur_week_tuesday= }
|
49
|
+
it { should respond_to :recur_week_wednesday= }
|
50
|
+
it { should respond_to :recur_week_thursday= }
|
51
|
+
it { should respond_to :recur_week_friday= }
|
52
|
+
it { should respond_to :recur_week_saturday= }
|
53
|
+
|
54
|
+
describe "#get_attributes" do
|
55
|
+
let(:attributes) { { :uid => 1, :title => 'winner', :utc => true } }
|
56
|
+
it "selects some attributes" do
|
57
|
+
subject.get_attributes(['utc', :uid]).should == { :uid => 1, :utc => true }
|
58
|
+
end
|
59
|
+
|
60
|
+
it "gets and empty hash" do
|
61
|
+
subject.get_attributes(['doesnt exist']).should == { }
|
62
|
+
end
|
63
|
+
|
64
|
+
it "sends an empty array" do
|
65
|
+
subject.get_attributes([]).should == { }
|
66
|
+
end
|
67
|
+
|
68
|
+
it "doesn't send an array" do
|
69
|
+
expect { subject.get_attributes({}) }.to raise_error(ArgumentError, "Must be an Array")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#to_hash" do
|
74
|
+
let(:attributes) { { :uid => 1, :title => "winner" } }
|
75
|
+
it "should return all of the attributes" do
|
76
|
+
subject.to_hash.should == {
|
77
|
+
:uid => 1,
|
78
|
+
:title => "winner",
|
79
|
+
:description => nil,
|
80
|
+
:location => nil,
|
81
|
+
:start_date_time => nil,
|
82
|
+
:end_date_time => nil,
|
83
|
+
:utc => nil,
|
84
|
+
:date_exclusions => [], # Set in initializer
|
85
|
+
:recur_end_date => nil,
|
86
|
+
:recur_month_repeat_by => nil,
|
87
|
+
:recur_interval => nil,
|
88
|
+
:recur_interval_value => nil,
|
89
|
+
:recur_end_date => nil,
|
90
|
+
:recurrence_id => nil,
|
91
|
+
:all_day_event => nil,
|
92
|
+
:recurrence => nil,
|
93
|
+
:recur_week_sunday => nil,
|
94
|
+
:recur_week_monday => nil,
|
95
|
+
:recur_week_tuesday => nil,
|
96
|
+
:recur_week_wednesday => nil,
|
97
|
+
:recur_week_thursday => nil,
|
98
|
+
:recur_week_friday => nil,
|
99
|
+
:recur_week_saturday => nil
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "#attributes=" do
|
105
|
+
let(:attributes) { { :uid => 1, :title => "winner" } }
|
106
|
+
it "sets a few attributes" do
|
107
|
+
subject.attributes = { :uid => 2, :description => "we got 'em" }
|
108
|
+
subject.uid.should == 2
|
109
|
+
subject.attributes[:uid].should == 2
|
110
|
+
subject.title.should == "winner"
|
111
|
+
subject.attributes[:title].should == "winner"
|
112
|
+
subject.description.should == "we got 'em"
|
113
|
+
subject.attributes[:description].should == "we got 'em"
|
114
|
+
end
|
115
|
+
|
116
|
+
it "sets the acceptable attributes, not the unacceptable" do
|
117
|
+
subject.attributes = { :dont => "use", :me => "ha", :uid => 3 }
|
118
|
+
subject.uid.should == 3
|
119
|
+
subject.attributes[:uid].should == 3
|
120
|
+
subject.attributes[:dont].should == nil
|
121
|
+
subject.attributes[:me].should == nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'timeout'
|
3
|
+
module IcalImporter
|
4
|
+
describe Parser do
|
5
|
+
subject { Parser.new(url) }
|
6
|
+
let(:url) { "http://some_url" }
|
7
|
+
let(:bare_stuff) { stub :pos= => true }
|
8
|
+
before do
|
9
|
+
::Timeout.stub!(:timeout).and_yield
|
10
|
+
RemoteEvent.any_instance.stub :all_day_event? => true
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#initialize' do
|
14
|
+
it "parses with rical" do
|
15
|
+
Parser.any_instance.stub(:open_ical).and_return bare_stuff
|
16
|
+
RiCal.should_receive(:parse).with bare_stuff
|
17
|
+
Parser.new(url)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#should_parse?" do
|
22
|
+
it "should parse" do
|
23
|
+
subject.stub :bare_feed => bare_stuff
|
24
|
+
subject.should_parse?.should == true
|
25
|
+
end
|
26
|
+
|
27
|
+
context "empty base_feed" do
|
28
|
+
it "is false" do
|
29
|
+
subject.stub :base_feed => nil
|
30
|
+
subject.should_parse?.should == false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#worth_parsing?" do
|
36
|
+
it "should be parsed" do
|
37
|
+
feed = stub :present? => true, :first => true
|
38
|
+
subject.stub :feed => feed, :should_parse? => true
|
39
|
+
subject.worth_parsing?.should == true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#all_events" do
|
44
|
+
let(:url) { sample_ics_path }
|
45
|
+
it "has all 3 events" do
|
46
|
+
subject.parse
|
47
|
+
subject.all_events.count.should == 3
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#single_events" do
|
52
|
+
let(:url) { sample_ics_path }
|
53
|
+
it "has the 3 singluar events" do
|
54
|
+
subject.parse
|
55
|
+
subject.single_events.count.should == 3
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Need to find a good example feed with recurrence_id set
|
60
|
+
describe "#recurrence_events" do
|
61
|
+
let(:url) { sample_ics_path }
|
62
|
+
it "has 0 recurrence_events" do
|
63
|
+
subject.parse
|
64
|
+
subject.recurrence_events.count.should == 0
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#parse" do
|
69
|
+
let(:url) { sample_ics_path }
|
70
|
+
it "returns 3 events" do
|
71
|
+
subject.parse.count.should == 3
|
72
|
+
end
|
73
|
+
|
74
|
+
it "can use a block to manipulate events" do
|
75
|
+
count = 0
|
76
|
+
subject.parse do |e|
|
77
|
+
e.should be_an_instance_of LocalEvent
|
78
|
+
count += 1
|
79
|
+
end
|
80
|
+
count.should == 3
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#open_ical" do
|
85
|
+
it 'cleans up and tries to open an HTTP URL' do
|
86
|
+
subject.stub :open => bare_stuff
|
87
|
+
subject.send(:open_ical).should == bare_stuff
|
88
|
+
end
|
89
|
+
|
90
|
+
it "fails with an invalid protocol" do
|
91
|
+
expect { subject.send(:open_ical, 'wrong_proto') }.to raise_error(ArgumentError, "Must be http or https")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#prepped_uri" do
|
96
|
+
it "spits back the http URL" do
|
97
|
+
subject.send(:prepped_uri, 'http').should == url
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "https" do
|
101
|
+
let(:url) { "https://some_url" }
|
102
|
+
it "spits back the https URL" do
|
103
|
+
subject.send(:prepped_uri, 'https').should == url
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "webcal" do
|
108
|
+
let(:base_url) { "://some_url" }
|
109
|
+
let(:http_url) { "http#{base_url}" }
|
110
|
+
let(:url) { "webcal#{base_url}" }
|
111
|
+
it "spits back the http URL" do
|
112
|
+
subject.send(:prepped_uri, 'http').should == http_url
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "Webcal" do
|
117
|
+
let(:base_url) { "://some_url" }
|
118
|
+
let(:http_url) { "http#{base_url}" }
|
119
|
+
let(:url) { "Webcal#{base_url}" }
|
120
|
+
it "spits back the http URL" do
|
121
|
+
subject.send(:prepped_uri, 'http').should == http_url
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module IcalImporter
|
3
|
+
describe RecurrenceEventBuilder do
|
4
|
+
describe "#initialize" do
|
5
|
+
it "should set up basic accessors" do
|
6
|
+
subject.events_to_build.should == []
|
7
|
+
subject.built_events.should == []
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#<<" do
|
12
|
+
it "adds event" do
|
13
|
+
new_event = stub(:is_a? => true)
|
14
|
+
subject << new_event
|
15
|
+
subject.events_to_build.should == [new_event]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "fails with incorrect event type" do
|
19
|
+
new_event = stub(:is_a? => false)
|
20
|
+
expect { subject.<<(new_event) }.to raise_error(ArgumentError, "Must be a RiCal Event")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#build" do
|
25
|
+
it "wraps builds the events and fills in the attribute" do
|
26
|
+
event_list = [stub, stub]
|
27
|
+
RemoteEvent.stub(:new).and_return(event_list[0], event_list[1])
|
28
|
+
subject.stub :events_to_build => event_list
|
29
|
+
subject.should_receive(:build_new_local_event).with(event_list[0]).ordered.and_return("boom1")
|
30
|
+
subject.should_receive(:build_new_local_event).with(event_list[1]).ordered.and_return("boom2")
|
31
|
+
subject.build
|
32
|
+
subject.built_events.should == %w[boom1 boom2]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#build_new_local_event" do
|
37
|
+
let(:remote_event) { stub :summary => "birthdayy",
|
38
|
+
:uid => 1,
|
39
|
+
:description => "do stuff",
|
40
|
+
:location => "here",
|
41
|
+
:start_date_time => "today",
|
42
|
+
:end_date_time => "tomorrow",
|
43
|
+
:recurrence_id => 1
|
44
|
+
}
|
45
|
+
it "creates a new event" do
|
46
|
+
RemoteEvent.stub(:new => remote_event)
|
47
|
+
local_event = subject.send(:build_new_local_event, remote_event)
|
48
|
+
local_event.title.should == "birthdayy"
|
49
|
+
local_event.description.should == "do stuff"
|
50
|
+
local_event.location.should == "here"
|
51
|
+
local_event.start_date_time.should == "today"
|
52
|
+
local_event.end_date_time.should == "tomorrow"
|
53
|
+
local_event.recurrence.should == true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module IcalImporter
|
3
|
+
describe RemoteEvent do
|
4
|
+
subject { RemoteEvent.new(event) }
|
5
|
+
let(:event) { stub :dtstart => stub(:tzid => nil) }
|
6
|
+
it { should respond_to :description }
|
7
|
+
it { should respond_to :recurs? }
|
8
|
+
it { should respond_to :rrule_property }
|
9
|
+
it { should respond_to :exdate }
|
10
|
+
describe "#initialize" do
|
11
|
+
describe "dtstart tzid nil" do
|
12
|
+
it "sets utc and event" do
|
13
|
+
subject.event.should == event
|
14
|
+
subject.utc?.should == true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "dtstart tzid == :floating" do
|
19
|
+
let(:event) { stub :dtstart => stub(:tzid => :floating) }
|
20
|
+
it "sets utc and event" do
|
21
|
+
subject.event.should == event
|
22
|
+
subject.utc?.should == false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#start_date_time" do
|
28
|
+
describe "with string date" do
|
29
|
+
let(:event) { stub :dtstart => "20120715" }
|
30
|
+
it "gets the date time" do
|
31
|
+
subject.start_date_time.should == event.dtstart.to_datetime
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "with an actual DateTime" do
|
36
|
+
let(:event) { stub :dtstart => "20120715".to_datetime }
|
37
|
+
it "uses the datetime because it is already that" do
|
38
|
+
subject.start_date_time.should == event.dtstart
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "without a floating tzid" do
|
43
|
+
let(:event) { stub :dtstart => stub(
|
44
|
+
:is_a? => true,
|
45
|
+
:tzid => nil,
|
46
|
+
:time => "20120715".to_datetime,
|
47
|
+
:utc => "20120715".to_datetime.utc) }
|
48
|
+
it "uses the utc time of the datetime" do
|
49
|
+
subject.start_date_time.should == event.dtstart.time.utc
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#event_attributes" do
|
55
|
+
let(:event) { RiCal.parse(sample_ics).first.events.first }
|
56
|
+
it "fills in some attributes" do
|
57
|
+
subject.event_attributes.should == {
|
58
|
+
:uid => "1629F7A5-5A69-43CB-899E-4CE9BD5F069F",
|
59
|
+
:title => "Recurring Event",
|
60
|
+
:utc => true,
|
61
|
+
:description => nil,
|
62
|
+
:location => "",
|
63
|
+
:start_date_time => "Wed, 14 Sep 2016 00:00:00 +0000".to_datetime,
|
64
|
+
:end_date_time => "Thu, 15 Sep 2016 00:00:00 +0000".to_datetime,
|
65
|
+
:all_day_event => true}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module IcalImporter
|
3
|
+
describe SingleEventBuilder do
|
4
|
+
subject { SingleEventBuilder.new(event) }
|
5
|
+
let(:event) { RiCal.parse(sample_ics('mn_twins')).first.events.first }
|
6
|
+
describe "#build" do
|
7
|
+
it "builds an event" do
|
8
|
+
new_event = subject.build
|
9
|
+
new_event.should be_a LocalEvent
|
10
|
+
new_event.title.should == "Spring Training: Tampa Bay 3 - Minnesota 7"
|
11
|
+
new_event.utc?.should == true
|
12
|
+
new_event.description.should == "Spring Training: Tampa Bay 3 - Minnesota 7\n\nClick below for game previews, wraps and boxscores plus video, tickets, stats, gameday and more!\nhttp://mlb.mlb.com/mlb/gameday/index.jsp?gid=2012_03_03_tbamlb_minmlb_1\n\nWatch or Listen with MLB.TV: http://mlb.mlb.com/schedule/index.jsp?c_id=min&m=03&y=2012\n\nLocal Radio: 1500 ESPN"
|
13
|
+
new_event.location.should == "Lee County Sports Complex, Hammond County Stadium, Lee County"
|
14
|
+
new_event.all_day_event.should == false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
require 'ical_importer'
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
10
|
+
config.run_all_when_everything_filtered = true
|
11
|
+
config.filter_run :focus
|
12
|
+
|
13
|
+
# Run specs in random order to surface order dependencies. If you find an
|
14
|
+
# order dependency and want to debug it, you can fix the order by providing
|
15
|
+
# the seed, which is printed after each run.
|
16
|
+
# --seed 1234
|
17
|
+
config.order = 'random'
|
18
|
+
end
|
19
|
+
|
20
|
+
def sample_ics(file_name=nil)
|
21
|
+
File.open sample_ics_path(file_name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def sample_ics_path(file_name=nil)
|
25
|
+
File.join(File.dirname(__FILE__), 'support', "#{file_name || 'test'}.ics")
|
26
|
+
end
|