ical_importer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/.rspec
ADDED
data/.rvmrc
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ical_importer (0.0.1)
|
5
|
+
activesupport (~> 3.0.15)
|
6
|
+
i18n
|
7
|
+
ri_cal
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activesupport (3.0.16)
|
13
|
+
awesome_print (1.0.2)
|
14
|
+
diff-lcs (1.1.3)
|
15
|
+
i18n (0.6.0)
|
16
|
+
rake (0.9.2.2)
|
17
|
+
ri_cal (0.8.8)
|
18
|
+
rspec (2.11.0)
|
19
|
+
rspec-core (~> 2.11.0)
|
20
|
+
rspec-expectations (~> 2.11.0)
|
21
|
+
rspec-mocks (~> 2.11.0)
|
22
|
+
rspec-core (2.11.1)
|
23
|
+
rspec-expectations (2.11.2)
|
24
|
+
diff-lcs (~> 1.1.3)
|
25
|
+
rspec-mocks (2.11.1)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
awesome_print
|
32
|
+
ical_importer!
|
33
|
+
rake
|
34
|
+
rspec
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Ical Importer
|
2
|
+
|
3
|
+
Easily import your iCal feeds.
|
4
|
+
|
5
|
+
[![TravisCI](https://secure.travis-ci.org/tstmedia/ical_importer.png "TravisCI")](http://travis-ci.org/tstmedia/ical_importer "Travis-CI IcalImporter")
|
6
|
+
|
7
|
+
<!---
|
8
|
+
[RubyGems](NOT YET "NOT YET")
|
9
|
+
--->
|
10
|
+
|
11
|
+
# Notes
|
12
|
+
|
13
|
+
* Recurrence events are not the same as recurring events
|
14
|
+
|
15
|
+
# Usage
|
16
|
+
|
17
|
+
Add
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem 'ical_importer', :git => 'http://github.com/tstmedia/ical_importer.git'
|
21
|
+
```
|
22
|
+
|
23
|
+
to your Gemfile
|
24
|
+
|
25
|
+
Then you can do:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
IcalImporter::Parser.new(a_url).parse # To get just an array of events
|
29
|
+
|
30
|
+
IcalImporter::Parser.new(a_url).parse do |event|
|
31
|
+
event.uid
|
32
|
+
event.title
|
33
|
+
event.description
|
34
|
+
event.location
|
35
|
+
event.start_date_time
|
36
|
+
event.end_date_time
|
37
|
+
event.utc
|
38
|
+
event.date_exclusions
|
39
|
+
event.recur_end_date
|
40
|
+
event.recur_month_repeat_by
|
41
|
+
event.recur_interval
|
42
|
+
event.recur_interval_value
|
43
|
+
event.recurrence_id
|
44
|
+
event.all_day_event
|
45
|
+
event.recurrence
|
46
|
+
event.utc?
|
47
|
+
event.all_day_event?
|
48
|
+
event.recurrence?
|
49
|
+
event.recur_week_sunday
|
50
|
+
event.recur_week_monday
|
51
|
+
event.recur_week_tuesday
|
52
|
+
event.recur_week_wednesday
|
53
|
+
event.recur_week_thursday
|
54
|
+
event.recur_week_friday
|
55
|
+
event.recur_week_saturday
|
56
|
+
end
|
57
|
+
|
58
|
+
parser = IcalImporter::Parser.new(a_url)
|
59
|
+
parser.parse do |e|
|
60
|
+
# block stuffs
|
61
|
+
end
|
62
|
+
|
63
|
+
# Each of these also accepts blocks and returns a list
|
64
|
+
parser.all_events
|
65
|
+
parser.recurrence_events
|
66
|
+
parser.single_events
|
67
|
+
```
|
68
|
+
|
69
|
+
# TODO
|
70
|
+
|
71
|
+
* Current implementation based on an extraction from another app
|
72
|
+
- some of the recurring/recurrence/single logic is fragmented
|
73
|
+
- Re-implement to be more similarly classifiable across these different scenarios
|
74
|
+
* Document Methods
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require "rspec/core/rake_task"
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
namespace :spec do
|
8
|
+
RSpec::Core::RakeTask.new(:docs) do |t|
|
9
|
+
t.rspec_opts = ["--format doc"]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => :spec
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/ical_importer/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Jon Phenow"]
|
6
|
+
gem.email = ["jon.phenow@tstmedia.com"]
|
7
|
+
gem.description = %q{Easily import iCal Events from a URL and handle their output}
|
8
|
+
gem.summary = %q{}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
gem.name = "ical_importer"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = IcalImporter::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'activesupport', "~> 3.0.15"
|
19
|
+
gem.add_dependency 'ri_cal'
|
20
|
+
gem.add_dependency 'i18n'
|
21
|
+
|
22
|
+
gem.add_development_dependency 'rake'
|
23
|
+
gem.add_development_dependency 'rspec'
|
24
|
+
gem.add_development_dependency 'awesome_print'
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module IcalImporter
|
2
|
+
class Builder
|
3
|
+
attr_reader :event, :recurrence_builder
|
4
|
+
def initialize(event, recurrence_builder)
|
5
|
+
@event = event
|
6
|
+
@recurrence_builder = recurrence_builder
|
7
|
+
end
|
8
|
+
|
9
|
+
def handle_as_recurrence?
|
10
|
+
event.recurrence_id.present?
|
11
|
+
end
|
12
|
+
|
13
|
+
def build
|
14
|
+
if handle_as_recurrence?
|
15
|
+
recurrence_builder << event
|
16
|
+
nil # Don't want this messing up our collect in Collector
|
17
|
+
else
|
18
|
+
SingleEventBuilder.new(event).build
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module IcalImporter
|
2
|
+
class Collector
|
3
|
+
attr_reader :single_events, :events, :recurrence_events
|
4
|
+
|
5
|
+
def initialize(events)
|
6
|
+
@events = events
|
7
|
+
@single_events = []
|
8
|
+
@recurrence_events = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def collect
|
12
|
+
self.tap do
|
13
|
+
recurrence_builder = RecurrenceEventBuilder.new
|
14
|
+
single_events.tap do |c|
|
15
|
+
events.each do |remote_event|
|
16
|
+
c << Builder.new(remote_event, recurrence_builder).build
|
17
|
+
end
|
18
|
+
@recurrence_events = recurrence_builder.build.built_events.flatten.compact
|
19
|
+
c.flatten!
|
20
|
+
c.compact!
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module IcalImporter
|
2
|
+
class LocalEvent
|
3
|
+
class << self
|
4
|
+
attr_accessor :class_attributes
|
5
|
+
end
|
6
|
+
|
7
|
+
@class_attributes = [
|
8
|
+
:uid,
|
9
|
+
:title,
|
10
|
+
:description,
|
11
|
+
:location,
|
12
|
+
:start_date_time,
|
13
|
+
:end_date_time,
|
14
|
+
:utc,
|
15
|
+
:date_exclusions,
|
16
|
+
:recur_end_date,
|
17
|
+
:recur_month_repeat_by,
|
18
|
+
:recur_interval,
|
19
|
+
:recur_interval_value,
|
20
|
+
:recur_end_date,
|
21
|
+
:recurrence_id,
|
22
|
+
:all_day_event,
|
23
|
+
:recurrence
|
24
|
+
]
|
25
|
+
|
26
|
+
attr_accessor *class_attributes
|
27
|
+
alias utc? utc
|
28
|
+
alias all_day_event? all_day_event
|
29
|
+
alias recurrence? recurrence
|
30
|
+
|
31
|
+
DAYS = %w[sunday monday tuesday wednesday thursday friday saturday]
|
32
|
+
DAYS.each do |day|
|
33
|
+
class_attributes << "recur_week_#{day}".to_sym
|
34
|
+
attr_accessor "recur_week_#{day}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(attributes)
|
38
|
+
self.attributes = attributes
|
39
|
+
@date_exclusions ||= []
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_attributes(list)
|
43
|
+
raise ArgumentError, "Must be an Array" unless list.is_a? Array
|
44
|
+
list.collect! { |e| e.to_s }
|
45
|
+
attributes.select { |k,_| list.include? k.to_s }
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_hash
|
49
|
+
Hash[*self.class.class_attributes.collect { |attribute| [attribute.to_sym, send(attribute)] }.flatten(1)]
|
50
|
+
end
|
51
|
+
alias :attributes :to_hash
|
52
|
+
|
53
|
+
def attributes=(attributes)
|
54
|
+
attributes.each do |name, value|
|
55
|
+
instance_variable_set "@#{name}", value if self.class.class_attributes.include? name.to_sym
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module IcalImporter
|
2
|
+
class Parser
|
3
|
+
attr_reader :feed, :bare_feed, :url
|
4
|
+
|
5
|
+
def initialize(url)
|
6
|
+
@url = url
|
7
|
+
@bare_feed = open_ical
|
8
|
+
if should_parse?
|
9
|
+
@bare_feed.pos = 0
|
10
|
+
@feed = RiCal.parse @bare_feed
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def should_parse?
|
15
|
+
bare_feed.present?
|
16
|
+
end
|
17
|
+
|
18
|
+
def worth_parsing?
|
19
|
+
should_parse? && feed.present? && feed.first
|
20
|
+
end
|
21
|
+
|
22
|
+
def all_events(&block)
|
23
|
+
tap_and_each (@imported_single_events || []) + (@imported_recurrence_events || []), &block
|
24
|
+
end
|
25
|
+
|
26
|
+
def single_events(&block)
|
27
|
+
tap_and_each (@imported_single_events || []), &block
|
28
|
+
end
|
29
|
+
|
30
|
+
def recurrence_events(&block)
|
31
|
+
tap_and_each (@imported_recurrence_events || []), &block
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse(&block)
|
35
|
+
if worth_parsing?
|
36
|
+
collected = Collector.new(feed.first.events).collect
|
37
|
+
@imported_single_events = collected.single_events
|
38
|
+
@imported_recurrence_events = collected.recurrence_events
|
39
|
+
tap_and_each (@imported_single_events + @imported_recurrence_events), &block
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def tap_and_each(list)
|
46
|
+
list.tap do |r|
|
47
|
+
r.each do |event|
|
48
|
+
yield event if block_given?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def open_ical(protocol = 'http')
|
54
|
+
raise ArgumentError, "Must be http or https" unless %w[http https].include? protocol
|
55
|
+
begin
|
56
|
+
Timeout::timeout(5) do
|
57
|
+
open prepped_uri(protocol)
|
58
|
+
end
|
59
|
+
rescue
|
60
|
+
return open_ical 'https' if protocol == 'http'
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def prepped_uri(protocol)
|
66
|
+
uri = url.strip.gsub(/^[Ww]ebcal:/, "#{protocol}:")
|
67
|
+
uri = begin
|
68
|
+
URI.unescape(uri)
|
69
|
+
rescue URI::InvalidURIError
|
70
|
+
end
|
71
|
+
URI.escape(uri)
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module IcalImporter
|
2
|
+
class RecurrenceEventBuilder
|
3
|
+
attr_reader :events_to_build, :built_events
|
4
|
+
def initialize
|
5
|
+
@events_to_build = []
|
6
|
+
@built_events = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def <<(event)
|
10
|
+
raise ArgumentError, "Must be a RiCal Event" unless event.is_a? RiCal::Component::Event
|
11
|
+
@events_to_build << event
|
12
|
+
end
|
13
|
+
|
14
|
+
def build
|
15
|
+
self.tap do
|
16
|
+
events_to_build.each do |remote_event|
|
17
|
+
@built_events << build_new_local_event(remote_event)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def build_new_local_event(remote_event)
|
25
|
+
LocalEvent.new({
|
26
|
+
:uid => remote_event.uid,
|
27
|
+
:title => remote_event.summary,
|
28
|
+
:description => remote_event.description,
|
29
|
+
:location => remote_event.location || '',
|
30
|
+
:start_date_time => remote_event.start_date_time,
|
31
|
+
:end_date_time => remote_event.end_date_time,
|
32
|
+
:date_exclusions => [DateExclusion.new(:exclude_date => remote_event.recurrence_id)],
|
33
|
+
:recurrence => true
|
34
|
+
})
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module IcalImporter
|
2
|
+
class RemoteEvent
|
3
|
+
attr_accessor :event, :utc
|
4
|
+
alias :utc? :utc
|
5
|
+
delegate :description, :recurs?, :rrule_property, :exdate, :to => :event
|
6
|
+
|
7
|
+
def initialize(event)
|
8
|
+
@event = event
|
9
|
+
begin
|
10
|
+
@utc = @event.dtstart.try(:tzid) != :floating
|
11
|
+
rescue
|
12
|
+
@utc = true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def start_date_time
|
17
|
+
get_date_time_for :dtstart
|
18
|
+
end
|
19
|
+
|
20
|
+
def end_date_time
|
21
|
+
get_date_time_for :dtend
|
22
|
+
end
|
23
|
+
|
24
|
+
def all_day_event?
|
25
|
+
(Time.parse(end_date_time.to_s) - Time.parse(start_date_time.to_s)) >= 1.day
|
26
|
+
end
|
27
|
+
|
28
|
+
def event_attributes
|
29
|
+
{
|
30
|
+
:uid => event.uid,
|
31
|
+
:title => event.summary,
|
32
|
+
:utc => utc?,
|
33
|
+
:description => event.description,
|
34
|
+
:location => event.location || '',
|
35
|
+
:start_date_time => start_date_time,
|
36
|
+
:end_date_time => end_date_time,
|
37
|
+
:all_day_event => all_day_event?
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def get_date_time_for(event_method)
|
44
|
+
event_method = event_method.to_sym
|
45
|
+
raise ArgumentError, "Should be dtend or dtstart" unless [:dtstart, :dtend].include? event_method
|
46
|
+
event_time = event.send event_method
|
47
|
+
if event_time.is_a? DateTime
|
48
|
+
(event_time.tzid == :floating) ? event_time : event_time.utc
|
49
|
+
else
|
50
|
+
event_time.to_datetime
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module IcalImporter
|
2
|
+
class SingleEventBuilder
|
3
|
+
attr_reader :event, :local_event
|
4
|
+
|
5
|
+
def initialize(event)
|
6
|
+
@event = RemoteEvent.new event
|
7
|
+
@local_event = LocalEvent.new @event.event_attributes
|
8
|
+
end
|
9
|
+
|
10
|
+
# Get single-occurrence events built and get a lits of recurrence
|
11
|
+
# events, these must be build last
|
12
|
+
def build
|
13
|
+
# handle recuring events
|
14
|
+
@local_event.tap do |le|
|
15
|
+
if @event.recurs?
|
16
|
+
rrule = @event.rrule_property.first # only support recurrence on one schedule
|
17
|
+
# set out new event's basic rucurring properties
|
18
|
+
le.attributes = recurrence_attributes rrule
|
19
|
+
|
20
|
+
set_date_exclusion
|
21
|
+
frequency_set rrule
|
22
|
+
else # make sure we remove this if it changed
|
23
|
+
le.attributes = non_recurrence_attributes
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def non_recurrence_attributes
|
31
|
+
attributes = {
|
32
|
+
:recur_interval => "none",
|
33
|
+
:recur_interval_value => nil,
|
34
|
+
:recur_end_date => nil
|
35
|
+
}
|
36
|
+
if !@local_event.all_day_event && @event.start_date_time.day != @event.end_date_time.day # single event that spans multiple days
|
37
|
+
attributes.merge({
|
38
|
+
:recur_interval => "day",
|
39
|
+
:recur_interval_value => 1,
|
40
|
+
:recur_end_date => @event.end_date_time.end_of_day - 1.day,
|
41
|
+
:all_day_event => true
|
42
|
+
})
|
43
|
+
end
|
44
|
+
attributes
|
45
|
+
end
|
46
|
+
|
47
|
+
def recurrence_attributes(rrule)
|
48
|
+
{
|
49
|
+
:recur_interval => recur_map[rrule.freq],
|
50
|
+
:recur_interval_value => rrule.interval,
|
51
|
+
:recur_end_date => rrule.until.try(:to_datetime)
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def set_date_exclusion
|
56
|
+
# set any date exclusions
|
57
|
+
@local_event.date_exclusions = @event.exdate.flatten.map{|d| DateExclusion.new(:exclude_date => d)}
|
58
|
+
end
|
59
|
+
|
60
|
+
def frequency_set(rrule)
|
61
|
+
# if .bounded? is an integer that's googles "recur X times"
|
62
|
+
# if that's the case we try to figure out the date it should be by
|
63
|
+
# multiplying thise "X" times by the frequency that the event recurrs
|
64
|
+
if rrule.bounded?.is_a? Fixnum # convert X times to a date
|
65
|
+
case rrule.freq
|
66
|
+
when "DAILY"
|
67
|
+
@local_event.recur_end_date = frequency_template.days
|
68
|
+
when "WEEKLY"
|
69
|
+
if rrule.to_ical.include?("BYDAY=")
|
70
|
+
remote_days = rrule.to_ical.split("BYDAY=").last.split(";WKST=").first.split(',')
|
71
|
+
day_map.each do |abbr, day|
|
72
|
+
@local_event.send "recur_week_#{day}=", remote_days.include?(abbr)
|
73
|
+
end
|
74
|
+
else
|
75
|
+
remote_days = [@local_event.start_date_time.wday]
|
76
|
+
wday_map.each do |abbr, day|
|
77
|
+
@local_event.send "recur_week_#{day}=", remote_days.include?(abbr)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
# recurrence X times is probably broken - we can select multiple times in a week
|
81
|
+
@local_event.recur_end_date = (frequency_template / remote_days.length).weeks
|
82
|
+
when "MONTHLY"
|
83
|
+
@local_event.recur_month_repeat_by = (rrule.to_ical =~ /BYDAY/) ? "day_of_week" : "day_of_month"
|
84
|
+
@local_event.recur_end_date = frequency_template.months
|
85
|
+
when "YEARLY"
|
86
|
+
@local_event.recur_end_date = frequency_template.years
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def frequency_template
|
92
|
+
@local_event.start_date_time + (rrule.bounded? * rrule.interval - 1)
|
93
|
+
end
|
94
|
+
|
95
|
+
def recur_map
|
96
|
+
{
|
97
|
+
"DAILY" => "day",
|
98
|
+
"WEEKLY" => "week",
|
99
|
+
"MONTHLY" => "month",
|
100
|
+
"YEARLY" => "year"
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def day_map
|
105
|
+
{
|
106
|
+
"SU" => "sunday",
|
107
|
+
"MO" => "monday",
|
108
|
+
"TU" => "tuesday",
|
109
|
+
"WE" => "wednesday",
|
110
|
+
"TH" => "thursday",
|
111
|
+
"FR" => "friday",
|
112
|
+
"SA" => "saturday"
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
def wday_map
|
117
|
+
{
|
118
|
+
0 => "sunday",
|
119
|
+
1 => "monday",
|
120
|
+
2 => "tuesday",
|
121
|
+
3 => "wednesday",
|
122
|
+
4 => "thursday",
|
123
|
+
5 => "friday",
|
124
|
+
6 => "saturday"
|
125
|
+
}
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'ri_cal'
|
3
|
+
|
4
|
+
require 'ical_importer/date_exclusion'
|
5
|
+
require 'ical_importer/builder'
|
6
|
+
require 'ical_importer/collector'
|
7
|
+
require 'ical_importer/remote_event'
|
8
|
+
require 'ical_importer/local_event'
|
9
|
+
require 'ical_importer/parser'
|
10
|
+
require 'ical_importer/recurrence_event_builder'
|
11
|
+
require 'ical_importer/single_event_builder'
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module IcalImporter
|
3
|
+
describe Builder do
|
4
|
+
subject { Builder.new(event, recurrence_builder) }
|
5
|
+
let(:recurrence_builder) { RecurrenceEventBuilder.new }
|
6
|
+
|
7
|
+
describe "#handle_as_recurrence?" do
|
8
|
+
describe "recurrence_id'd event" do
|
9
|
+
let(:event) { stub :recurrence_id => 1 }
|
10
|
+
it "handles as recurrence" do
|
11
|
+
subject.handle_as_recurrence?.should == true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "non-recurrence_id'd event" do
|
16
|
+
let(:event) { stub :recurrence_id => nil }
|
17
|
+
it "handles as recurrence" do
|
18
|
+
subject.handle_as_recurrence?.should == false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#build" do
|
24
|
+
let(:event) { stub }
|
25
|
+
describe "recurrence" do
|
26
|
+
let(:event) { stub :recurrence_id => 1 }
|
27
|
+
it "adds events to be computed with recurrence_builder" do
|
28
|
+
recurrence_builder.should_receive(:<<).with(event)
|
29
|
+
subject.build.should == nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "non-recurrence" do
|
34
|
+
let(:event) { stub :recurrence_id => nil }
|
35
|
+
it "builds single event" do
|
36
|
+
single_event_builder = stub
|
37
|
+
returned = stub
|
38
|
+
SingleEventBuilder.should_receive(:new).with(event).and_return single_event_builder
|
39
|
+
single_event_builder.should_receive(:build).and_return(returned)
|
40
|
+
subject.build.should == returned
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module IcalImporter
|
3
|
+
describe Collector do
|
4
|
+
let(:events) { [] }
|
5
|
+
subject { Collector.new events }
|
6
|
+
it { should respond_to :collect }
|
7
|
+
|
8
|
+
describe "#collect" do
|
9
|
+
let(:events) { [stub, stub] }
|
10
|
+
let(:r_builder) { stub(:build => stub(:built_events => [])) }
|
11
|
+
it "tries to build, then cleanup the returns" do
|
12
|
+
built = stub
|
13
|
+
RecurrenceEventBuilder.should_receive(:new).and_return r_builder
|
14
|
+
Builder.should_receive(:new).with(events[0], r_builder).ordered.and_return(built)
|
15
|
+
Builder.should_receive(:new).with(events[1], r_builder).ordered.and_return(built)
|
16
|
+
built.should_receive(:build).twice.and_return "boom"
|
17
|
+
subject.collect
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|