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.
@@ -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