ics_parser 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.
- checksums.yaml +7 -0
- data/.gitignore +35 -0
- data/Gemfile +3 -0
- data/README.md +31 -0
- data/ics_parser.gemspec +23 -0
- data/lib/event_parser.rb +121 -0
- data/lib/ics_parser.rb +19 -0
- data/spec/event_parser_spec.rb +100 -0
- data/spec/ics_parser_spec.rb +5 -0
- data/spec/sample.ics +71 -0
- data/spec/spec_helper.rb +4 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6cd9cb4de61ebafff4c36462820aac8f46fa839f
|
4
|
+
data.tar.gz: 5b8ae88900375e3cd0102ac70ab840dc6afa7edd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 04285a82a6adbabfb8b3ac1154a016a7e02e28be06cb5df1f1f102dac557f9f372b27894ad8b410fa96ead56fee9d6a9850b48e218a89de4f1a4ca4e9fe89056
|
7
|
+
data.tar.gz: 7e0d3503fa4228dad2df895c1f1f69c87bbf4bd898c5ab12715cfe42d958b58a3191d5a77a2a7a1fb1b352019703ff4516a606aaa572f2525c00ed82861814d3
|
data/.gitignore
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/vendor/bundle
|
26
|
+
/lib/bundler/man/
|
27
|
+
|
28
|
+
# for a library or gem, you might want to ignore these files since the code is
|
29
|
+
# intended to run in multiple environments; otherwise, check them in:
|
30
|
+
# Gemfile.lock
|
31
|
+
# .ruby-version
|
32
|
+
# .ruby-gemset
|
33
|
+
|
34
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
35
|
+
.rvmrc
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
IcsParser
|
2
|
+
=========
|
3
|
+
|
4
|
+
Reads an ICalendar file and returns the events in an array.
|
5
|
+
|
6
|
+
Also supports recurring events with excluded dates (using EXDATE).
|
7
|
+
|
8
|
+
It is not complete and I have only tested it on my feed (exported from Apple iCloud)
|
9
|
+
so do not rely on it.
|
10
|
+
|
11
|
+
# Example
|
12
|
+
|
13
|
+
```
|
14
|
+
require 'ics_parser'
|
15
|
+
|
16
|
+
parser = IcsParser.from_file('path/to/file')
|
17
|
+
# or parser = IcsParser.from_string(calendar)
|
18
|
+
events = parser.events
|
19
|
+
|
20
|
+
events.each do |event|
|
21
|
+
puts event.summary # string
|
22
|
+
puts event.starts_at # Time
|
23
|
+
puts event.ends_at # Time
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
# Installation
|
28
|
+
|
29
|
+
```
|
30
|
+
gem install ics_parser
|
31
|
+
```
|
data/ics_parser.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "ics_parser"
|
7
|
+
spec.version = '0.0.1'
|
8
|
+
spec.authors = ["Matúš Tomlein"]
|
9
|
+
spec.email = ["matus@tomlein.org"]
|
10
|
+
spec.summary = %q{Reads iCalendar feeds and returns events in an array.}
|
11
|
+
spec.description = %q{}
|
12
|
+
spec.homepage = "https://github.com/matus-tomlein/ics_parser"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
23
|
+
end
|
data/lib/event_parser.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
class EventParser
|
5
|
+
def initialize(calendar_content)
|
6
|
+
@calendar_content = calendar_content
|
7
|
+
end
|
8
|
+
|
9
|
+
def events
|
10
|
+
events = []
|
11
|
+
|
12
|
+
get_events_in_calendar.each do |event|
|
13
|
+
summary = parse_summary event
|
14
|
+
starts_at = parse_starts_at event
|
15
|
+
ends_at = parse_ends_at event
|
16
|
+
|
17
|
+
if recurring_event? event
|
18
|
+
recurring_dates = parse_recurring_dates(event)
|
19
|
+
|
20
|
+
recurring_dates.each do |recurring_starts_at, recurring_ends_at|
|
21
|
+
events << new_event(summary,
|
22
|
+
recurring_starts_at,
|
23
|
+
recurring_ends_at)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
events << new_event(summary,
|
27
|
+
starts_at,
|
28
|
+
ends_at)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
events
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def new_event(summary, starts_at, ends_at)
|
38
|
+
OpenStruct.new(summary: summary,
|
39
|
+
starts_at: starts_at,
|
40
|
+
ends_at: ends_at)
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_events_in_calendar
|
44
|
+
beginnings = @calendar_content.split('BEGIN:VEVENT')
|
45
|
+
events = []
|
46
|
+
|
47
|
+
beginnings.each do |event_beginning|
|
48
|
+
next unless event_beginning.include? 'END:VEVENT'
|
49
|
+
|
50
|
+
events << event_beginning.split('END:VEVENT').first
|
51
|
+
end
|
52
|
+
|
53
|
+
events
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse_summary(event)
|
57
|
+
/SUMMARY:(.*)/.match(event)[1]
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_starts_at(event)
|
61
|
+
Time.parse(/DTSTART[\w\/=;]*:(\d+T\d+)/.match(event)[1])
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse_ends_at(event)
|
65
|
+
Time.parse(/DTEND[\w\/=;]*:(\d+T\d+)/.match(event)[1])
|
66
|
+
end
|
67
|
+
|
68
|
+
def recurring_event?(event)
|
69
|
+
event.include? 'RRULE:FREQ=WEEKLY;'
|
70
|
+
end
|
71
|
+
|
72
|
+
def parse_recurring_dates(event)
|
73
|
+
recurring_dates = {}
|
74
|
+
starts_at = parse_starts_at event
|
75
|
+
ends_at = parse_ends_at event
|
76
|
+
summary = parse_summary event
|
77
|
+
|
78
|
+
if event.include? 'RRULE:FREQ=WEEKLY;COUNT='
|
79
|
+
count = /RRULE:FREQ=WEEKLY;COUNT=(\d+)/.match(event)[1].to_i
|
80
|
+
|
81
|
+
count.times do |i|
|
82
|
+
recurring_starts_at = add_days_to_time(starts_at, i * 7)
|
83
|
+
recurring_ends_at = add_days_to_time(ends_at, i * 7)
|
84
|
+
|
85
|
+
unless is_date_excluded?(recurring_starts_at, event)
|
86
|
+
recurring_dates[recurring_starts_at] = recurring_ends_at
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
elsif event.include? 'RRULE:FREQ=WEEKLY;UNTIL='
|
91
|
+
until_time = Time.parse(/RRULE:FREQ=WEEKLY;UNTIL=(\d+T\d+)/.match(event)[1])
|
92
|
+
|
93
|
+
last_starts_at = starts_at
|
94
|
+
last_ends_at = ends_at
|
95
|
+
|
96
|
+
while last_starts_at <= until_time
|
97
|
+
unless is_date_excluded?(last_starts_at, event)
|
98
|
+
recurring_dates[last_starts_at] = last_ends_at
|
99
|
+
end
|
100
|
+
|
101
|
+
last_starts_at = add_days_to_time(last_starts_at, 7)
|
102
|
+
last_ends_at = add_days_to_time(last_ends_at, 7)
|
103
|
+
end
|
104
|
+
|
105
|
+
else
|
106
|
+
raise "Unsupported recurring event type: #{summary}"
|
107
|
+
end
|
108
|
+
|
109
|
+
recurring_dates
|
110
|
+
end
|
111
|
+
|
112
|
+
def is_date_excluded?(date, event)
|
113
|
+
date_str = date.strftime '%Y%m%dT%I%M%S'
|
114
|
+
not_excluded = /EXDATE[\w\/=;]*:#{date_str}/.match(event).nil?
|
115
|
+
!not_excluded
|
116
|
+
end
|
117
|
+
|
118
|
+
def add_days_to_time(time, days)
|
119
|
+
time + (days * 24 * 60 * 60)
|
120
|
+
end
|
121
|
+
end
|
data/lib/ics_parser.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'event_parser'
|
2
|
+
|
3
|
+
class IcsParser
|
4
|
+
def self.from_file(file)
|
5
|
+
from_string(File.read(file))
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.from_string(text)
|
9
|
+
return IcsParser.new(text)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(calendar_content)
|
13
|
+
@calendar_content = calendar_content
|
14
|
+
end
|
15
|
+
|
16
|
+
def events
|
17
|
+
EventParser.new(@calendar_content).events
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe EventParser do
|
4
|
+
let(:sample_data) { File.read 'spec/sample.ics' }
|
5
|
+
let(:parser) { EventParser.new(sample_data) }
|
6
|
+
|
7
|
+
context 'one time event' do
|
8
|
+
let(:event) do
|
9
|
+
parser.events.find {|event| event.summary == 'one time event' }
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'has the right start time' do
|
13
|
+
expect(event.starts_at).to eq Time.new(2015, 2, 24, 12, 30)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'has the right end time' do
|
17
|
+
expect(event.ends_at).to eq Time.new(2015, 2, 24, 13, 15)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'recurring weekly event' do
|
22
|
+
let(:events) do
|
23
|
+
parser.events.find_all {|event| event.summary == 'recurring weekly event' }
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'found 7 events' do
|
27
|
+
expect(events.size).to eq 7
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'have the right start times' do
|
31
|
+
expected_times = [
|
32
|
+
Time.new(2015, 4, 15, 14, 0),
|
33
|
+
Time.new(2015, 4, 22, 14, 0),
|
34
|
+
Time.new(2015, 4, 29, 14, 0),
|
35
|
+
Time.new(2015, 5, 6, 14, 0),
|
36
|
+
Time.new(2015, 5, 13, 14, 0),
|
37
|
+
Time.new(2015, 5, 20, 14, 0),
|
38
|
+
Time.new(2015, 5, 27, 14, 0)
|
39
|
+
]
|
40
|
+
times = events.map {|event| event.starts_at }
|
41
|
+
expect(times).to eq expected_times
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'have the right end times' do
|
45
|
+
expected_times = [
|
46
|
+
Time.new(2015, 4, 15, 16, 0),
|
47
|
+
Time.new(2015, 4, 22, 16, 0),
|
48
|
+
Time.new(2015, 4, 29, 16, 0),
|
49
|
+
Time.new(2015, 5, 6, 16, 0),
|
50
|
+
Time.new(2015, 5, 13, 16, 0),
|
51
|
+
Time.new(2015, 5, 20, 16, 0),
|
52
|
+
Time.new(2015, 5, 27, 16, 0)
|
53
|
+
]
|
54
|
+
times = events.map {|event| event.ends_at }
|
55
|
+
expect(times).to eq expected_times
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'recurring event with exdates' do
|
60
|
+
let(:events) do
|
61
|
+
parser.events.find_all {|event| event.summary == 'recurring event with exdates' }
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'found some events' do
|
65
|
+
expect(events.size).to be > 1
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'contains the correct dates' do
|
69
|
+
times = events.map {|event| event.starts_at }
|
70
|
+
|
71
|
+
expect(times).to include Time.new(2014, 11, 19, 9, 0)
|
72
|
+
expect(times).to include Time.new(2014, 11, 26, 9, 0)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'didn\'t find the excluded events' do
|
76
|
+
times = events.map {|event| event.starts_at }
|
77
|
+
|
78
|
+
excluded_times = [
|
79
|
+
Time.new(2015, 4, 8, 9, 0),
|
80
|
+
Time.new(2015, 6, 10, 9, 0),
|
81
|
+
Time.new(2015, 4, 15, 9, 0),
|
82
|
+
Time.new(2015, 5, 20, 9, 0),
|
83
|
+
Time.new(2015, 3, 25, 9, 0),
|
84
|
+
Time.new(2015, 6, 3, 9, 0),
|
85
|
+
Time.new(2014, 12, 3, 9, 0),
|
86
|
+
Time.new(2015, 3, 11, 9, 0),
|
87
|
+
Time.new(2015, 7, 8, 9, 0),
|
88
|
+
Time.new(2014, 12, 24, 9, 0),
|
89
|
+
Time.new(2014, 12, 31, 9, 0),
|
90
|
+
Time.new(2015, 7, 1, 9, 0),
|
91
|
+
Time.new(2015, 6, 24, 9, 0),
|
92
|
+
Time.new(2015, 4, 1, 9, 0),
|
93
|
+
]
|
94
|
+
|
95
|
+
excluded_times.each do |excluded_time|
|
96
|
+
expect(times).not_to include excluded_time
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/spec/sample.ics
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
BEGIN:VCALENDAR
|
2
|
+
CALSCALE:GREGORIAN
|
3
|
+
VERSION:2.0
|
4
|
+
METHOD:PUBLISH
|
5
|
+
X-WR-CALNAME:Supervision
|
6
|
+
X-WR-TIMEZONE:Europe/Copenhagen
|
7
|
+
X-APPLE-CALENDAR-COLOR:#FFCC00
|
8
|
+
BEGIN:VTIMEZONE
|
9
|
+
TZID:Europe/Copenhagen
|
10
|
+
BEGIN:DAYLIGHT
|
11
|
+
TZOFFSETFROM:+0100
|
12
|
+
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
|
13
|
+
DTSTART:19810329T020000
|
14
|
+
TZNAME:CEST
|
15
|
+
TZOFFSETTO:+0200
|
16
|
+
END:DAYLIGHT
|
17
|
+
BEGIN:STANDARD
|
18
|
+
TZOFFSETFROM:+0200
|
19
|
+
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
|
20
|
+
DTSTART:19961027T030000
|
21
|
+
TZNAME:CET
|
22
|
+
TZOFFSETTO:+0100
|
23
|
+
END:STANDARD
|
24
|
+
END:VTIMEZONE
|
25
|
+
BEGIN:VEVENT
|
26
|
+
CREATED:20150614T194602Z
|
27
|
+
UID:3DE997B6-EB52-4893-A922-6A1BCB35340F
|
28
|
+
RRULE:FREQ=WEEKLY;COUNT=7
|
29
|
+
DTEND;TZID=Europe/Copenhagen:20150415T160000
|
30
|
+
TRANSP:OPAQUE
|
31
|
+
SUMMARY:recurring weekly event
|
32
|
+
DTSTART;TZID=Europe/Copenhagen:20150415T140000
|
33
|
+
DTSTAMP:20150614T194602Z
|
34
|
+
SEQUENCE:0
|
35
|
+
END:VEVENT
|
36
|
+
BEGIN:VEVENT
|
37
|
+
CREATED:20150614T194154Z
|
38
|
+
UID:7B924445-C7BC-4F0A-BCFD-EFBF4394EAFA
|
39
|
+
DTEND;TZID=Europe/Copenhagen:20150224T131500
|
40
|
+
TRANSP:OPAQUE
|
41
|
+
SUMMARY:one time event
|
42
|
+
DTSTART;TZID=Europe/Copenhagen:20150224T123000
|
43
|
+
DTSTAMP:20150614T194154Z
|
44
|
+
SEQUENCE:0
|
45
|
+
END:VEVENT
|
46
|
+
BEGIN:VEVENT
|
47
|
+
CREATED:20150614T193544Z
|
48
|
+
UID:6371A3DF-17C9-47B7-9277-F7D2596CCD36
|
49
|
+
RRULE:FREQ=WEEKLY;UNTIL=20150714T235959Z
|
50
|
+
DTEND;TZID=Europe/Copenhagen:20141119T100000
|
51
|
+
EXDATE;TZID=Europe/Copenhagen:20150408T090000
|
52
|
+
EXDATE;TZID=Europe/Copenhagen:20150610T090000
|
53
|
+
EXDATE;TZID=Europe/Copenhagen:20150415T090000
|
54
|
+
EXDATE;TZID=Europe/Copenhagen:20150520T090000
|
55
|
+
EXDATE;TZID=Europe/Copenhagen:20150325T090000
|
56
|
+
EXDATE;TZID=Europe/Copenhagen:20150603T090000
|
57
|
+
EXDATE;TZID=Europe/Copenhagen:20141203T090000
|
58
|
+
EXDATE;TZID=Europe/Copenhagen:20150311T090000
|
59
|
+
EXDATE;TZID=Europe/Copenhagen:20150708T090000
|
60
|
+
EXDATE;TZID=Europe/Copenhagen:20141224T090000
|
61
|
+
EXDATE;TZID=Europe/Copenhagen:20141231T090000
|
62
|
+
EXDATE;TZID=Europe/Copenhagen:20150701T090000
|
63
|
+
EXDATE;TZID=Europe/Copenhagen:20150624T090000
|
64
|
+
EXDATE;TZID=Europe/Copenhagen:20150401T090000
|
65
|
+
TRANSP:OPAQUE
|
66
|
+
SUMMARY:recurring event with exdates
|
67
|
+
DTSTART;TZID=Europe/Copenhagen:20141119T090000
|
68
|
+
DTSTAMP:20150614T193544Z
|
69
|
+
SEQUENCE:0
|
70
|
+
END:VEVENT
|
71
|
+
END:VCALENDAR
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ics_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matúš Tomlein
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: ''
|
56
|
+
email:
|
57
|
+
- matus@tomlein.org
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- Gemfile
|
64
|
+
- README.md
|
65
|
+
- ics_parser.gemspec
|
66
|
+
- lib/event_parser.rb
|
67
|
+
- lib/ics_parser.rb
|
68
|
+
- spec/event_parser_spec.rb
|
69
|
+
- spec/ics_parser_spec.rb
|
70
|
+
- spec/sample.ics
|
71
|
+
- spec/spec_helper.rb
|
72
|
+
homepage: https://github.com/matus-tomlein/ics_parser
|
73
|
+
licenses:
|
74
|
+
- MIT
|
75
|
+
metadata: {}
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 2.2.2
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: Reads iCalendar feeds and returns events in an array.
|
96
|
+
test_files:
|
97
|
+
- spec/event_parser_spec.rb
|
98
|
+
- spec/ics_parser_spec.rb
|
99
|
+
- spec/sample.ics
|
100
|
+
- spec/spec_helper.rb
|