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
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
|
+
[](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
|