ics 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/.gitignore +4 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +30 -0
- data/README.rdoc +74 -0
- data/Rakefile +2 -0
- data/ics.gemspec +24 -0
- data/lib/ics.rb +1 -0
- data/lib/ics/event.rb +60 -0
- data/lib/ics/version.rb +3 -0
- data/spec/event_spec.rb +47 -0
- data/spec/example_events.ics +33 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/macros.rb +10 -0
- metadata +121 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.2-p0@ics
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ics (0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ZenTest (4.4.2)
|
10
|
+
autotest (4.4.6)
|
11
|
+
ZenTest (>= 4.4.1)
|
12
|
+
awesome_print (0.3.1)
|
13
|
+
diff-lcs (1.1.2)
|
14
|
+
rspec (2.3.0)
|
15
|
+
rspec-core (~> 2.3.0)
|
16
|
+
rspec-expectations (~> 2.3.0)
|
17
|
+
rspec-mocks (~> 2.3.0)
|
18
|
+
rspec-core (2.3.1)
|
19
|
+
rspec-expectations (2.3.0)
|
20
|
+
diff-lcs (~> 1.1.2)
|
21
|
+
rspec-mocks (2.3.0)
|
22
|
+
|
23
|
+
PLATFORMS
|
24
|
+
ruby
|
25
|
+
|
26
|
+
DEPENDENCIES
|
27
|
+
autotest
|
28
|
+
awesome_print
|
29
|
+
ics!
|
30
|
+
rspec (= 2.3.0)
|
data/README.rdoc
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
= ICS
|
2
|
+
|
3
|
+
ICS is a library that reads ICS files and parses them into ICS::Event objects.
|
4
|
+
|
5
|
+
== Usage
|
6
|
+
|
7
|
+
=== Short version
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'ics'
|
11
|
+
events = ICS::Event.file(File.open('calendar.ics'))
|
12
|
+
events.map(&:summary)
|
13
|
+
#=> ['Walk dog', 'Solve world hunger, tell noone', ...]
|
14
|
+
|
15
|
+
=== Longer version
|
16
|
+
|
17
|
+
The ICS::Event class can read in and parse an exported .ics file. For example, from iCal, export a calendar (select calendar, File, Export..., Export...):
|
18
|
+
ICS::Event.file(File.open('calendar.ics'))
|
19
|
+
will return an array of events with whatever attributes are in the .ics file for each event. The ICS::Event object will have a method name for each attribute in lower case form.
|
20
|
+
# calendar.ics
|
21
|
+
...
|
22
|
+
SUMMARY:Grocery shopping
|
23
|
+
...
|
24
|
+
|
25
|
+
# ruby environment
|
26
|
+
event.summary
|
27
|
+
#=> 'Grocery shopping'
|
28
|
+
|
29
|
+
Here are a list of known attributes:
|
30
|
+
* TRANSP
|
31
|
+
* DTEND
|
32
|
+
* UID
|
33
|
+
* DTSTAMP
|
34
|
+
* LOCATION
|
35
|
+
* DESCRIPTION
|
36
|
+
* URL
|
37
|
+
* STATUS
|
38
|
+
* SEQUENCE
|
39
|
+
* SUMMARY
|
40
|
+
* DTSTART
|
41
|
+
* CREATED
|
42
|
+
# For the alarm...
|
43
|
+
* # BEGIN:VALARM (ignored)
|
44
|
+
* X-WR-ALARMUID
|
45
|
+
* TRIGGER
|
46
|
+
* ATTACH
|
47
|
+
* ACTION
|
48
|
+
* # END:VALARM (ignored)
|
49
|
+
|
50
|
+
=== Data type casting
|
51
|
+
|
52
|
+
By default, each attribute method returns a string literal. For convenience, attribute methods can be easily defined in the ICS::Event class for customized behavior. Currently <tt>ICS::Event#dtstart</tt> is the only one that is defined:
|
53
|
+
event.dtstart.class
|
54
|
+
#=> Time
|
55
|
+
|
56
|
+
=== More "Railsy"
|
57
|
+
|
58
|
+
<tt>ICS::Event#started_at</tt> is an alias for <tt>ICS::Event#dtstart</tt>. <tt>ICS::Event#started_on</tt> returns a Date object converted from <tt>ICS::Event#dtstart</tt>. More later...
|
59
|
+
|
60
|
+
=== Metadata
|
61
|
+
|
62
|
+
Some attributes have some metadata attached to them. For example, sometimes the DTSTART attribute has the time zone:
|
63
|
+
|
64
|
+
DTSTART;TZID=America/Chicago:20100331T190000
|
65
|
+
|
66
|
+
As of this version, metadata is ignored.
|
67
|
+
|
68
|
+
== Installation
|
69
|
+
|
70
|
+
gem install ics
|
71
|
+
|
72
|
+
== Ruby
|
73
|
+
|
74
|
+
Written in Ruby 1.9.2p0.
|
data/Rakefile
ADDED
data/ics.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "ics/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "ics"
|
7
|
+
s.version = ICS::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['Jared Ning']
|
10
|
+
s.email = ['jared@redningja.com']
|
11
|
+
s.summary = 'Read .ics files'
|
12
|
+
s.description = 'Parse exported .ics files into Event objects.'
|
13
|
+
|
14
|
+
s.rubyforge_project = "ics"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency 'autotest'
|
22
|
+
s.add_development_dependency 'awesome_print'
|
23
|
+
s.add_development_dependency 'rspec', '2.3.0'
|
24
|
+
end
|
data/lib/ics.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'ics/event'
|
data/lib/ics/event.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module ICS
|
4
|
+
|
5
|
+
class Event
|
6
|
+
|
7
|
+
# Given a hash of attributes, define a method for each key that returns the value.
|
8
|
+
# Attributes stored in instance variable.
|
9
|
+
def initialize(attributes = {})
|
10
|
+
@attributes = attributes
|
11
|
+
attributes.each do |key, val|
|
12
|
+
unless respond_to?(key)
|
13
|
+
self.class.send :define_method, key do
|
14
|
+
@attributes[key]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return time object.
|
21
|
+
# Assumes time in UTC.
|
22
|
+
def dtstart
|
23
|
+
return nil unless @attributes[:dtstart]
|
24
|
+
DateTime.parse(@attributes[:dtstart]).to_time.utc
|
25
|
+
end
|
26
|
+
alias_method :started_at, :dtstart
|
27
|
+
|
28
|
+
def started_on
|
29
|
+
dtstart.to_date if dtstart
|
30
|
+
end
|
31
|
+
|
32
|
+
class << self
|
33
|
+
|
34
|
+
# Given an exported ical file, parse it and create events.
|
35
|
+
def file(file)
|
36
|
+
# format line endings.
|
37
|
+
content = file.readlines.map(&:chomp).join($/)
|
38
|
+
line_ending = $/
|
39
|
+
content.split("BEGIN:VEVENT#{line_ending}")[1..-1].map do |data_string|
|
40
|
+
data_string = data_string.split("END:VEVENT#{line_ending}").first
|
41
|
+
new parse(data_string)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse(str)
|
46
|
+
str.split($/).inject({}) do |hash, line|
|
47
|
+
key, value = line.split(':', 2)
|
48
|
+
next hash if key =~ /^BEGIN/ # Ignore any other book ends.
|
49
|
+
value = value.chomp if value
|
50
|
+
key = key.split(';', 2).first # Ignore extra data other than just the name of the attribute.
|
51
|
+
hash[key.downcase.to_sym] = value
|
52
|
+
hash
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
data/lib/ics/version.rb
ADDED
data/spec/event_spec.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ICS::Event do
|
4
|
+
|
5
|
+
it 'parses event data string and generates a hash' do
|
6
|
+
ICS::Event.parse("NAME:value with spaces\nKEY:val").should == {:name => 'value with spaces', :key => 'val'}
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should read a file, parse it, and return an array of events' do
|
10
|
+
file = file_with_content(<<-END)
|
11
|
+
BEGIN:VEVENT
|
12
|
+
INDEX:0
|
13
|
+
END:VEVENT
|
14
|
+
BEGIN:VEVENT
|
15
|
+
INDEX:1
|
16
|
+
END:VEVENT
|
17
|
+
END
|
18
|
+
events = ICS::Event.file(file)
|
19
|
+
events.size.should == 2
|
20
|
+
events.each_with_index do |event, i|
|
21
|
+
event.index.should == i.to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should be initialized with a hash of attributes and have keys defined as methods returning values' do
|
26
|
+
event = ICS::Event.new(:attribute => '1')
|
27
|
+
event.should respond_to(:attribute)
|
28
|
+
event.attribute.should == '1'
|
29
|
+
end
|
30
|
+
|
31
|
+
it '#dtstart should return time object' do
|
32
|
+
time = Time.now.utc
|
33
|
+
event = ICS::Event.new(:dtstart => time.strftime('%Y%m%dT%H%M%SZ'))
|
34
|
+
event.dtstart.to_i.should == time.to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should handle real file' do
|
38
|
+
events = ICS::Event.file(File.open('spec/example_events.ics'))
|
39
|
+
events.size.should == 2
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should parse attributes ignoring extra data like time zone for DTSTART' do
|
43
|
+
data = 'DTSTART;TZID=asdfasdf:1'
|
44
|
+
ICS::Event.parse(data).should == {:dtstart => '1'}
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
BEGIN:VEVENT
|
2
|
+
TRANSP:OPAQUE
|
3
|
+
DTEND:20091011T020000Z
|
4
|
+
UID:D388E9D6-CD69-487F-80EB-A9095B8E29DC
|
5
|
+
DTSTAMP:20091123T233512Z
|
6
|
+
LOCATION:
|
7
|
+
DESCRIPTION:
|
8
|
+
URL;VALUE=URI:http://www.whatsthematterwithkansas.com/trailer.html
|
9
|
+
STATUS:CONFIRMED
|
10
|
+
SEQUENCE:5
|
11
|
+
SUMMARY:What's the Matter \nwith Kansas?
|
12
|
+
DTSTART:20091011T010000Z
|
13
|
+
CREATED:20090915T012027Z
|
14
|
+
BEGIN:VALARM
|
15
|
+
X-WR-ALARMUID:44215ABF-8E3E-490F-BE97-46EAAEAB526B
|
16
|
+
TRIGGER:PT0S
|
17
|
+
ATTACH;VALUE=URI:Glass
|
18
|
+
ACTION:AUDIO
|
19
|
+
END:VALARM
|
20
|
+
END:VEVENT
|
21
|
+
BEGIN:VEVENT
|
22
|
+
TRANSP:OPAQUE
|
23
|
+
DTEND;TZID=America/Chicago:20100331T200000
|
24
|
+
UID:C4676085-7B38-4A1A-9382-C3503A3A87A5
|
25
|
+
DTSTAMP:20100420T050645Z
|
26
|
+
LOCATION:
|
27
|
+
DESCRIPTION:
|
28
|
+
STATUS:CONFIRMED
|
29
|
+
SEQUENCE:2
|
30
|
+
SUMMARY:traffic
|
31
|
+
DTSTART;TZID=America/Chicago:20100331T190000
|
32
|
+
CREATED:20100401T004845Z
|
33
|
+
END:VEVENT
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'ics'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'awesome_print'
|
4
|
+
|
5
|
+
# Requires supporting files with custom matchers and macros, etc,
|
6
|
+
# in ./support/ and its subdirectories.
|
7
|
+
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.include Macros
|
11
|
+
end
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ics
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
version: "0.1"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- Jared Ning
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2011-01-02 00:00:00 -05:00
|
17
|
+
default_executable:
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: autotest
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :development
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: awesome_print
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 0
|
42
|
+
version: "0"
|
43
|
+
type: :development
|
44
|
+
version_requirements: *id002
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: rspec
|
47
|
+
prerelease: false
|
48
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - "="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
segments:
|
54
|
+
- 2
|
55
|
+
- 3
|
56
|
+
- 0
|
57
|
+
version: 2.3.0
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id003
|
60
|
+
description: Parse exported .ics files into Event objects.
|
61
|
+
email:
|
62
|
+
- jared@redningja.com
|
63
|
+
executables: []
|
64
|
+
|
65
|
+
extensions: []
|
66
|
+
|
67
|
+
extra_rdoc_files: []
|
68
|
+
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- .rspec
|
72
|
+
- .rvmrc
|
73
|
+
- Gemfile
|
74
|
+
- Gemfile.lock
|
75
|
+
- README.rdoc
|
76
|
+
- Rakefile
|
77
|
+
- ics.gemspec
|
78
|
+
- lib/ics.rb
|
79
|
+
- lib/ics/event.rb
|
80
|
+
- lib/ics/version.rb
|
81
|
+
- spec/event_spec.rb
|
82
|
+
- spec/example_events.ics
|
83
|
+
- spec/spec_helper.rb
|
84
|
+
- spec/support/macros.rb
|
85
|
+
has_rdoc: true
|
86
|
+
homepage:
|
87
|
+
licenses: []
|
88
|
+
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
segments:
|
108
|
+
- 0
|
109
|
+
version: "0"
|
110
|
+
requirements: []
|
111
|
+
|
112
|
+
rubyforge_project: ics
|
113
|
+
rubygems_version: 1.3.7
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: Read .ics files
|
117
|
+
test_files:
|
118
|
+
- spec/event_spec.rb
|
119
|
+
- spec/example_events.ics
|
120
|
+
- spec/spec_helper.rb
|
121
|
+
- spec/support/macros.rb
|