icalendar 2.0.0.beta.2 → 2.0.0
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 +4 -4
- data/.gitignore +1 -0
- data/History.txt +4 -0
- data/README.md +7 -3
- data/icalendar.gemspec +11 -1
- data/lib/icalendar.rb +11 -1
- data/lib/icalendar/logger.rb +16 -0
- data/lib/icalendar/parser.rb +16 -7
- data/lib/icalendar/tzinfo.rb +50 -22
- data/lib/icalendar/version.rb +1 -1
- data/spec/fixtures/nonstandard.ics +25 -0
- data/spec/roundtrip_spec.rb +17 -0
- data/spec/tzinfo_spec.rb +1 -1
- metadata +24 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bec860be74d825a4185f664e5faf729a7dab764
|
4
|
+
data.tar.gz: 5b4f8aa6e13794637bd35e1094df96426a8622c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2097431525222e84223153f4e1288363600c9635fa29ce951de03ddcb8f400b327d55561861f14032df344db8acc1157c44395cd5a42f1f95eef312555f7cb6
|
7
|
+
data.tar.gz: 7b26558a56b5a5e40ab08c4841288122810151de6f701deeb76da0785af4ae57cc0fc2a335354e587a7e2e433f9708640aa3db7108a722bbe48cd370a9d6f0e2
|
data/.gitignore
CHANGED
data/History.txt
CHANGED
data/README.md
CHANGED
@@ -64,20 +64,22 @@ EXAMPLES
|
|
64
64
|
|
65
65
|
params = {"altrep" => "http://my.language.net", "language" => "SPANISH"}
|
66
66
|
|
67
|
-
cal.event do |e|
|
67
|
+
event = cal.event do |e|
|
68
68
|
e.dtstart = Icalendar::Values::Date.new('20050428')
|
69
69
|
e.dtend = Icalendar::Values::Date.new('20050429')
|
70
70
|
e.summary = Icalendar::Values::Text.new "This is a summary with params.", params
|
71
71
|
end
|
72
|
+
event.summary.ical_params #=> {'altrep' => 'http://my.language.net', 'language' => 'SPANISH'}
|
72
73
|
|
73
74
|
# or
|
74
75
|
|
75
|
-
cal.event do |e|
|
76
|
+
event = cal.event do |e|
|
76
77
|
e.dtstart = Icalendar::Values::Date.new('20050428')
|
77
78
|
e.dtend = Icalendar::Values::Date.new('20050429')
|
78
79
|
e.summary = "This is a summary with params."
|
79
80
|
e.summary.ical_params = params
|
80
81
|
end
|
82
|
+
event.summary.ical_params #=> {'altrep' => 'http://my.language.net', 'language' => 'SPANISH'}
|
81
83
|
|
82
84
|
#### We can output the calendar as a string ####
|
83
85
|
|
@@ -184,7 +186,9 @@ TIMEZONES
|
|
184
186
|
# END:VTIMEZONE
|
185
187
|
|
186
188
|
iCalendar has some basic support for creating VTIMEZONE blocks from timezone information pulled from `tzinfo`.
|
187
|
-
You must require `tzinfo` support manually to take advantage
|
189
|
+
You must require `tzinfo` support manually to take advantage.
|
190
|
+
|
191
|
+
iCalendar has been tested and works with `tzinfo` versions 0.3 and 1.1
|
188
192
|
|
189
193
|
#### Example ####
|
190
194
|
|
data/icalendar.gemspec
CHANGED
@@ -22,9 +22,19 @@ variety of calendaring applications.
|
|
22
22
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename f }
|
23
23
|
s.require_paths = ['lib']
|
24
24
|
|
25
|
+
s.required_ruby_version = '>= 1.9.3'
|
26
|
+
|
25
27
|
s.add_development_dependency 'rake', '~> 10.0'
|
26
28
|
s.add_development_dependency 'bundler', '~> 1.3'
|
27
|
-
|
29
|
+
|
30
|
+
# test with both groups of tzinfo dependencies
|
31
|
+
# tzinfo 1.x
|
32
|
+
s.add_development_dependency 'tzinfo', '~> 1.1'
|
33
|
+
s.add_development_dependency 'tzinfo-data', '~> 1.2014'
|
34
|
+
# tzinfo 0.x
|
35
|
+
# s.add_development_dependency 'tzinfo', '~> 0.3'
|
36
|
+
# end tzinfo
|
37
|
+
|
28
38
|
s.add_development_dependency 'activesupport', '~> 3.2'
|
29
39
|
s.add_development_dependency 'timecop', '~> 0.7.0'
|
30
40
|
s.add_development_dependency 'rspec', '~> 2.14'
|
data/lib/icalendar.rb
CHANGED
@@ -1,7 +1,17 @@
|
|
1
|
+
require 'icalendar/logger'
|
2
|
+
|
1
3
|
module Icalendar
|
2
4
|
|
3
5
|
MAX_LINE_LENGTH = 75
|
4
6
|
|
7
|
+
def self.logger
|
8
|
+
@logger ||= Icalendar::Logger.new(STDERR)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.logger=(logger)
|
12
|
+
@logger = logger
|
13
|
+
end
|
14
|
+
|
5
15
|
def self.parse(source, single = false)
|
6
16
|
calendars = Parser.new(source).parse
|
7
17
|
single ? calendars.first : calendars
|
@@ -20,4 +30,4 @@ require 'icalendar/journal'
|
|
20
30
|
require 'icalendar/freebusy'
|
21
31
|
require 'icalendar/timezone'
|
22
32
|
require 'icalendar/calendar'
|
23
|
-
require 'icalendar/parser'
|
33
|
+
require 'icalendar/parser'
|
data/lib/icalendar/parser.rb
CHANGED
@@ -10,7 +10,9 @@ module Icalendar
|
|
10
10
|
elsif source.respond_to? :to_s
|
11
11
|
@source = StringIO.new source.to_s, 'r'
|
12
12
|
else
|
13
|
-
|
13
|
+
msg = 'Icalendar::Parser.new must be called with a String or IO object'
|
14
|
+
Icalendar.fatal msg
|
15
|
+
fail ArgumentError, msg
|
14
16
|
end
|
15
17
|
read_in_data
|
16
18
|
@strict = strict
|
@@ -49,13 +51,19 @@ module Icalendar
|
|
49
51
|
end
|
50
52
|
prop_name = %w(class method).include?(fields[:name]) ? "ip_#{fields[:name]}" : fields[:name]
|
51
53
|
begin
|
52
|
-
if component.class.multiple_properties.include? prop_name
|
53
|
-
|
54
|
+
method_name = if component.class.multiple_properties.include? prop_name
|
55
|
+
"append_#{prop_name}"
|
54
56
|
else
|
55
|
-
|
57
|
+
"#{prop_name}="
|
56
58
|
end
|
59
|
+
component.send method_name, prop_value
|
57
60
|
rescue NoMethodError => nme
|
58
|
-
|
61
|
+
if strict?
|
62
|
+
Icalendar.logger.error "No method \"#{method_name}\" for component #{component}"
|
63
|
+
raise nme
|
64
|
+
else
|
65
|
+
Icalendar.logger.warn "No method \"#{method_name}\" for component #{component}. Skipping."
|
66
|
+
end
|
59
67
|
end
|
60
68
|
end
|
61
69
|
|
@@ -71,6 +79,7 @@ module Icalendar
|
|
71
79
|
break
|
72
80
|
elsif fields[:name] == 'begin'
|
73
81
|
klass_name = fields[:value].gsub(/\AV/, '').downcase.capitalize
|
82
|
+
Icalendar.logger.debug "Adding component #{klass_name}"
|
74
83
|
if Icalendar.const_defined? klass_name
|
75
84
|
component.add_component parse_component(Icalendar.const_get(klass_name).new)
|
76
85
|
elsif Icalendar::Timezone.const_defined? klass_name
|
@@ -79,7 +88,6 @@ module Icalendar
|
|
79
88
|
component.add_component parse_component(Component.new klass_name.downcase, fields[:value])
|
80
89
|
end
|
81
90
|
else
|
82
|
-
# new property
|
83
91
|
parse_property component, fields
|
84
92
|
end
|
85
93
|
end
|
@@ -112,7 +120,7 @@ module Icalendar
|
|
112
120
|
LINE = "(?<name>#{NAME})(?<params>(?:;#{PARAM})*):(?<value>#{VALUE})"
|
113
121
|
|
114
122
|
def parse_fields(input)
|
115
|
-
parts = %r{#{LINE}}.match(input) or
|
123
|
+
parts = %r{#{LINE}}.match(input) or fail "Invalid iCalendar input line: #{input}"
|
116
124
|
params = {}
|
117
125
|
parts[:params].scan %r{#{PARAM}} do |match|
|
118
126
|
param_name = match[0].downcase
|
@@ -121,6 +129,7 @@ module Icalendar
|
|
121
129
|
params[param_name] << param_value.gsub(/\A"|"\z/, '') if param_value.size > 0
|
122
130
|
end
|
123
131
|
end
|
132
|
+
Icalendar.logger.debug "Found fields: #{parts.inspect} with params: #{params.inspect}"
|
124
133
|
{
|
125
134
|
name: parts[:name].downcase.gsub('-', '_'),
|
126
135
|
params: params,
|
data/lib/icalendar/tzinfo.rb
CHANGED
@@ -21,7 +21,7 @@
|
|
21
21
|
# # the mixins now generate all the timezone info for the date in question
|
22
22
|
# timezone = tz.ical_timezone(estart)
|
23
23
|
# cal.add(timezone)
|
24
|
-
#
|
24
|
+
#
|
25
25
|
# cal.event do
|
26
26
|
# dtstart estart
|
27
27
|
# dtend eend
|
@@ -40,26 +40,14 @@
|
|
40
40
|
|
41
41
|
|
42
42
|
require 'tzinfo'
|
43
|
+
begin
|
44
|
+
require 'tzinfo/data'
|
45
|
+
rescue LoadError
|
46
|
+
Icalendar.logger.info "Could not load tzinfo/data, hopefully tzinfo is accurate (ignore for tzinfo 0.x)"
|
47
|
+
end
|
43
48
|
|
44
|
-
module
|
45
|
-
|
46
|
-
def ical_timezone(date, dst = Timezone.default_dst)
|
47
|
-
period = period_for_local(date, dst)
|
48
|
-
timezone = Icalendar::Timezone.new
|
49
|
-
timezone.tzid = identifier
|
50
|
-
if period.start_transition.nil?
|
51
|
-
timezone.add_component period.single
|
52
|
-
elsif period.end_transition.nil?
|
53
|
-
timezone.add_component period.dst? ? period.daylight : period.standard
|
54
|
-
else
|
55
|
-
timezone.add_component period.daylight
|
56
|
-
timezone.add_component period.standard
|
57
|
-
end
|
58
|
-
timezone
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
class TimezoneTransitionInfo
|
49
|
+
module Icalendar
|
50
|
+
module TimezoneTransition
|
63
51
|
def offset_from
|
64
52
|
previous_offset.ical_offset
|
65
53
|
end
|
@@ -68,7 +56,7 @@ module TZInfo
|
|
68
56
|
offset.ical_offset
|
69
57
|
end
|
70
58
|
|
71
|
-
def rrule
|
59
|
+
def rrule
|
72
60
|
start = local_start.to_datetime
|
73
61
|
# this is somewhat of a hack, but seems to work ok
|
74
62
|
[sprintf(
|
@@ -84,12 +72,52 @@ module TZInfo
|
|
84
72
|
end
|
85
73
|
end
|
86
74
|
|
87
|
-
|
75
|
+
module TimezoneOffset
|
88
76
|
def ical_offset
|
89
77
|
o = utc_total_offset
|
90
78
|
sprintf '%+-2.2d%2.2d', (o / 3600).to_i, ((o / 60) % 60).to_i
|
91
79
|
end
|
92
80
|
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
module TZInfo
|
85
|
+
class Timezone
|
86
|
+
def ical_timezone(date, dst = Timezone.default_dst)
|
87
|
+
period = period_for_local(date, dst)
|
88
|
+
timezone = Icalendar::Timezone.new
|
89
|
+
timezone.tzid = identifier
|
90
|
+
if period.start_transition.nil?
|
91
|
+
timezone.add_component period.single
|
92
|
+
elsif period.end_transition.nil?
|
93
|
+
timezone.add_component period.dst? ? period.daylight : period.standard
|
94
|
+
else
|
95
|
+
timezone.add_component period.daylight
|
96
|
+
timezone.add_component period.standard
|
97
|
+
end
|
98
|
+
timezone
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
if defined? TimezoneTransitionInfo
|
103
|
+
class TimezoneTransitionInfo
|
104
|
+
include Icalendar::TimezoneTransition
|
105
|
+
end
|
106
|
+
else
|
107
|
+
class TimezoneTransition
|
108
|
+
include Icalendar::TimezoneTransition
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
if defined? TimezoneOffsetInfo
|
113
|
+
class TimezoneOffsetInfo
|
114
|
+
include Icalendar::TimezoneOffset
|
115
|
+
end
|
116
|
+
else
|
117
|
+
class TimezoneOffset
|
118
|
+
include Icalendar::TimezoneOffset
|
119
|
+
end
|
120
|
+
end
|
93
121
|
|
94
122
|
class TimezonePeriod
|
95
123
|
def daylight
|
data/lib/icalendar/version.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
BEGIN:VCALENDAR
|
2
|
+
VERSION:2.0
|
3
|
+
PRODID:bsprodidfortestabc123
|
4
|
+
BEGIN:VEVENT
|
5
|
+
UID:bsuidfortestabc123
|
6
|
+
ORGANIZER:mailto:joebob@random.net
|
7
|
+
ATTACH:http://bush.sucks.org/impeach/him.rhtml
|
8
|
+
ATTACH:http://corporations-dominate.existence.net/why.rhtml
|
9
|
+
SUMMARY:This is a really long summary
|
10
|
+
to test the method of unfolding lines\,
|
11
|
+
so I'm just going to ma
|
12
|
+
ke it
|
13
|
+
a whol
|
14
|
+
e
|
15
|
+
bunch of lines.
|
16
|
+
CLASS:PRIVATE
|
17
|
+
PRIORITY:2
|
18
|
+
CUSTOMFIELD:Not properly noted as custom with X- prefix.
|
19
|
+
GEO:37.386013;-122.0829322
|
20
|
+
DTSTART;TZID=US-Mountain:20050120T170000
|
21
|
+
DTEND:20050120T184500
|
22
|
+
DTSTAMP:20050118T211523Z
|
23
|
+
NAME:SomeName
|
24
|
+
END:VEVENT
|
25
|
+
END:VCALENDAR
|
data/spec/roundtrip_spec.rb
CHANGED
@@ -37,4 +37,21 @@ describe Icalendar do
|
|
37
37
|
expect(subject.dtend.to_ical(subject.class.default_property_types['dtend'])).to match /^;VALUE=DATE:20061215$/
|
38
38
|
end
|
39
39
|
end
|
40
|
+
|
41
|
+
describe 'non-standard values' do
|
42
|
+
before(:all) { Icalendar.logger = Icalendar::Logger.new File::NULL }
|
43
|
+
after(:all) { Icalendar.logger = nil }
|
44
|
+
let(:source) { File.read File.join(File.dirname(__FILE__), 'fixtures', 'nonstandard.ics') }
|
45
|
+
subject { Icalendar::Parser.new(source, strict) }
|
46
|
+
|
47
|
+
context 'strict parser' do
|
48
|
+
let(:strict) { true }
|
49
|
+
specify { expect { subject.parse }.to raise_error }
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'lenient parser' do
|
53
|
+
let(:strict) { false }
|
54
|
+
specify { expect { subject.parse}.to_not raise_error }
|
55
|
+
end
|
56
|
+
end
|
40
57
|
end
|
data/spec/tzinfo_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: icalendar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Ahearn
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -44,14 +44,28 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '1.1'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '1.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: tzinfo-data
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.2014'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.2014'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: activesupport
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,6 +150,7 @@ files:
|
|
136
150
|
- lib/icalendar/has_components.rb
|
137
151
|
- lib/icalendar/has_properties.rb
|
138
152
|
- lib/icalendar/journal.rb
|
153
|
+
- lib/icalendar/logger.rb
|
139
154
|
- lib/icalendar/parser.rb
|
140
155
|
- lib/icalendar/timezone.rb
|
141
156
|
- lib/icalendar/todo.rb
|
@@ -162,6 +177,7 @@ files:
|
|
162
177
|
- spec/calendar_spec.rb
|
163
178
|
- spec/event_spec.rb
|
164
179
|
- spec/fixtures/nondefault_values.ics
|
180
|
+
- spec/fixtures/nonstandard.ics
|
165
181
|
- spec/fixtures/single_event.ics
|
166
182
|
- spec/fixtures/timezone.ics
|
167
183
|
- spec/freebusy_spec.rb
|
@@ -192,12 +208,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
192
208
|
requirements:
|
193
209
|
- - '>='
|
194
210
|
- !ruby/object:Gem::Version
|
195
|
-
version:
|
211
|
+
version: 1.9.3
|
196
212
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
197
213
|
requirements:
|
198
|
-
- - '
|
214
|
+
- - '>='
|
199
215
|
- !ruby/object:Gem::Version
|
200
|
-
version:
|
216
|
+
version: '0'
|
201
217
|
requirements: []
|
202
218
|
rubyforge_project:
|
203
219
|
rubygems_version: 2.0.14
|
@@ -209,6 +225,7 @@ test_files:
|
|
209
225
|
- spec/calendar_spec.rb
|
210
226
|
- spec/event_spec.rb
|
211
227
|
- spec/fixtures/nondefault_values.ics
|
228
|
+
- spec/fixtures/nonstandard.ics
|
212
229
|
- spec/fixtures/single_event.ics
|
213
230
|
- spec/fixtures/timezone.ics
|
214
231
|
- spec/freebusy_spec.rb
|