ics 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ *.sw*
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
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
@@ -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)
@@ -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.
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -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
@@ -0,0 +1 @@
1
+ require 'ics/event'
@@ -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
@@ -0,0 +1,3 @@
1
+ module ICS
2
+ VERSION = "0.1"
3
+ end
@@ -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
@@ -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
@@ -0,0 +1,10 @@
1
+ module Macros
2
+
3
+ def file_with_content(content)
4
+ file = Tempfile.new('tmp')
5
+ file.write content
6
+ file.rewind
7
+ file
8
+ end
9
+
10
+ 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