icalendar 2.4.1 → 2.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 617189d256108d77d8cbf965621d324794e5ceb6
4
- data.tar.gz: 10041e3a5a825c812dc849d6ddc2997b5fcc5776
2
+ SHA256:
3
+ metadata.gz: 3f6d533875d40bbe7fe5f4ceedffb05f31207bf5e54fa9680f395c206c0e9a88
4
+ data.tar.gz: 85a0ddde7183fe00d00b3d71cb92ed2678ac7b34f63d9ffbbad20f03cc4adf6e
5
5
  SHA512:
6
- metadata.gz: ae3cf91f03aec36792d2f8a90b82265a71b66971bb535c6e41018bb6c611680e49d2535a0d165535011fffc85101447d545873d1f389960a4adb95e528891b59
7
- data.tar.gz: 59bb0240f2ff661a885792bacc976b273c2b10d234bc3cb32ca5c1f26031418d4f4ac58f6971dc1a2c6957c9074408674c557b98686dee83bdc6e24123efa1d5
6
+ metadata.gz: f645517ee3cb6960432f420c76edf0592c98b066d38ca893f66d04eb97d38e72853cdafe31835609750011dc0939dafbeaa0dc96337396418edbe9a830462ccf
7
+ data.tar.gz: b99f6e61e505a27b275c3da7555cf2017e891be6debcff89d045c5852d9e7ae0e88192c66b8134b221db6e8d3bb0c502f3b0c4cfa1186bdb0e3e280a11f56383
@@ -3,16 +3,17 @@ before_install:
3
3
  - gem install bundler
4
4
  language: ruby
5
5
  rvm:
6
- - 2.3.1
6
+ - 2.5
7
+ - 2.4
8
+ - 2.3
7
9
  - 2.2
8
- - 2.1
9
- - 2.0
10
10
  - jruby-19mode
11
- - rbx-2
11
+ - rbx-3
12
12
  - ruby-head
13
13
  - jruby-head
14
14
  matrix:
15
15
  allow_failures:
16
+ - rvm: 2.2
16
17
  - rvm: ruby-head
17
18
  - rvm: jruby-head
18
19
  script: bundle exec rake spec
@@ -1,3 +1,8 @@
1
+ === 2.5.0 2018-09-10
2
+ * Set timezone information from VTIMEZONE components in cases that ActiveSupport can't figure it out (or isn't installed)
3
+ * Prevent rewinding the Parser IO input during parsing - Niels Laukens
4
+ * Update tested/supported ruby versions & documentation updates.
5
+
1
6
  === 2.4.1 2016-09-03
2
7
  * Fix parsing multiple calendars or components in same file - Patrick Schnetger
3
8
  * Fix multi-byte folding bug - Niels Laukens
File without changes
data/README.md CHANGED
@@ -6,23 +6,6 @@ iCalendar -- Internet calendaring, Ruby style
6
6
 
7
7
  <http://github.com/icalendar/icalendar>
8
8
 
9
- 2.x Status
10
- ---
11
-
12
- iCalendar 2.0 is under active development, and can be followed in the
13
- [master branch](https://github.com/icalendar/icalendar/tree/master).
14
-
15
- iCalendar 1.x (currently the 1.x branch) will still survive for a
16
- while, but will only be accepting bug fixes from this point forward
17
- unless someone else wants to take over more active maintainership of
18
- the 1.x series.
19
-
20
- ### 2.0 Goals ###
21
-
22
- * Implements [RFC 5545](http://tools.ietf.org/html/rfc5545)
23
- * More obvious access to parameters and values
24
- * Cleaner & easier timezone support
25
-
26
9
  ### Upgrade from 1.x ###
27
10
 
28
11
  Better documentation is still to come, but in the meantime the changes needed to move from 1.x to 2.0 are summarized by the [diff needed to update the README](https://github.com/icalendar/icalendar/commit/bc3701e004c915a250054030a9375d1e7618857f)
@@ -92,11 +75,11 @@ event.summary.ical_params #=> {'altrep' => 'http://my.language.net', 'language'
92
75
 
93
76
  #### Support for Dates or DateTimes
94
77
 
95
- Sometimes we don't care if an event's start or end are `Date` or `DateTime` objects. For this, we can use `DateOrDateTime.new(value).call`
78
+ Sometimes we don't care if an event's start or end are `Date` or `DateTime` objects. For this, we can use `DateOrDateTime.new(value)`. Calling `.call` on the returned `DateOrDateTime` will immediately return the underlying `Date` or `DateTime` object.
96
79
 
97
80
  ```ruby
98
81
  event = cal.event do |e|
99
- e.dtstart = Icalendar::Values::DateOrDateTime.new('20140924').call
82
+ e.dtstart = Icalendar::Values::DateOrDateTime.new('20140924')
100
83
  e.dtend = Icalendar::Values::DateOrDateTime.new('20140925').call
101
84
  e.summary = 'This is an all-day event, because DateOrDateTime will return Dates'
102
85
  end
@@ -237,7 +220,7 @@ end
237
220
  iCalendar has some basic support for creating VTIMEZONE blocks from timezone information pulled from `tzinfo`.
238
221
  You must require `tzinfo` support manually to take advantage.
239
222
 
240
- iCalendar has been tested and works with `tzinfo` versions 0.3 and 1.1
223
+ iCalendar has been tested and works with `tzinfo` versions 0.3 and 1.x
241
224
 
242
225
  #### Example ####
243
226
 
@@ -16,11 +16,6 @@ for the generation and parsing of .ics files, which are used by a
16
16
  variety of calendaring applications.
17
17
  EOD
18
18
  s.post_install_message = <<-EOM
19
- HEADS UP! iCalendar 2.0 is not backwards-compatible with 1.x. Please see the README for the new syntax
20
-
21
- HEADS UP! icalendar 2.2.0 switches to non-strict parsing as default. Please see the README if you
22
- rely on strict parsing for information on how to enable it.
23
-
24
19
  ActiveSupport is required for TimeWithZone support, but not required for general use.
25
20
  EOM
26
21
 
@@ -29,24 +24,26 @@ ActiveSupport is required for TimeWithZone support, but not required for general
29
24
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename f }
30
25
  s.require_paths = ['lib']
31
26
 
32
- s.required_ruby_version = '>= 1.9.2'
27
+ s.required_ruby_version = '>= 2.2.0'
33
28
 
34
- s.add_development_dependency 'rake', '~> 10.0'
35
- s.add_development_dependency 'bundler', '~> 1.3'
29
+ s.add_dependency 'ice_cube', '~> 0.16'
30
+
31
+ s.add_development_dependency 'rake', '~> 12.0'
32
+ s.add_development_dependency 'bundler', '~> 1.16'
36
33
 
37
34
  # test with both groups of tzinfo dependencies
38
35
  # tzinfo 1.x
39
- s.add_development_dependency 'tzinfo', '~> 1.1'
40
- s.add_development_dependency 'tzinfo-data', '~> 1.2014'
36
+ s.add_development_dependency 'activesupport', '~> 5.2'
37
+ s.add_development_dependency 'i18n', '~> 1.1'
38
+ s.add_development_dependency 'tzinfo', '~> 1.2'
39
+ s.add_development_dependency 'tzinfo-data', '~> 1.2018'
41
40
  # tzinfo 0.x
41
+ # s.add_development_dependency 'activesupport', '~> 4.0'
42
+ # s.add_development_dependency 'i18n', '~> 0.7'
42
43
  # s.add_development_dependency 'tzinfo', '~> 0.3'
43
44
  # end tzinfo
44
45
 
45
- s.add_development_dependency 'activesupport', '~> 3.2'
46
- # lock i18n to < 0.7 to maintain ruby 1.9.2 compatibility
47
- s.add_development_dependency 'i18n', '< 0.7.0'
48
-
49
- s.add_development_dependency 'timecop', '~> 0.7.0'
50
- s.add_development_dependency 'rspec', '~> 3.0'
51
- s.add_development_dependency 'simplecov', '~> 0.8'
46
+ s.add_development_dependency 'timecop', '~> 0.9'
47
+ s.add_development_dependency 'rspec', '~> 3.8'
48
+ s.add_development_dependency 'simplecov', '~> 0.16'
52
49
  end
@@ -44,7 +44,11 @@ module Icalendar
44
44
 
45
45
  def append_custom_property(property_name, value)
46
46
  property_name = property_name.downcase
47
- if value.is_a? Icalendar::Value
47
+ if self.class.single_properties.include? property_name
48
+ send "#{property_name}=", value
49
+ elsif self.class.multiple_properties.include? property_name
50
+ send "append_#{property_name}", value
51
+ elsif value.is_a? Icalendar::Value
48
52
  custom_properties[property_name] << value
49
53
  else
50
54
  custom_properties[property_name] << Icalendar::Values::Text.new(value)
@@ -1,3 +1,5 @@
1
+ require 'icalendar/timezone_store'
2
+
1
3
  module Icalendar
2
4
 
3
5
  class Parser
@@ -19,8 +21,6 @@ module Icalendar
19
21
  end
20
22
 
21
23
  def parse
22
- source.rewind
23
- read_in_data
24
24
  components = []
25
25
  while (fields = next_fields)
26
26
  component = component_class.new
@@ -101,6 +101,8 @@ module Icalendar
101
101
  def parse_component(component)
102
102
  while (fields = next_fields)
103
103
  if fields[:name] == 'end'
104
+ klass_name = fields[:value].gsub(/\AV/, '').downcase.capitalize
105
+ TimezoneStore.store(component) if klass_name == 'Timezone'
104
106
  break
105
107
  elsif fields[:name] == 'begin'
106
108
  klass_name = fields[:value].gsub(/\AV/, '').downcase.capitalize
@@ -1,3 +1,5 @@
1
+ require 'ice_cube'
2
+
1
3
  module Icalendar
2
4
 
3
5
  class Timezone < Component
@@ -49,5 +51,56 @@ module Icalendar
49
51
  standards.all? { |s| s.valid? strict } or return false
50
52
  super
51
53
  end
54
+
55
+ def offset_for_local(local)
56
+ standard = standard_for local
57
+ daylight = daylight_for local
58
+
59
+ if standard.nil? && daylight.nil?
60
+ "+00:00"
61
+ elsif daylight.nil?
62
+ standard.last.tzoffsetto
63
+ elsif standard.nil?
64
+ daylight.last.tzoffsetto
65
+ else
66
+ sdst = standard.first
67
+ ddst = daylight.first
68
+ if sdst > ddst
69
+ standard.last.tzoffsetto
70
+ else
71
+ daylight.last.tzoffsetto
72
+ end
73
+ end
74
+ end
75
+
76
+ def standard_for(local)
77
+ possible = standards.map do |std|
78
+ schedule = IceCube::Schedule.new(std.dtstart) do |s|
79
+ std.rrule.each do |rule|
80
+ s.add_recurrence_rule IceCube::Rule.from_ical(rule.value_ical)
81
+ end
82
+ std.rdate.each do |date|
83
+ s.add_recurrence_date date
84
+ end
85
+ end
86
+ [schedule.previous_occurrence(local.to_time), std]
87
+ end
88
+ possible.sort_by(&:first).last
89
+ end
90
+
91
+ def daylight_for(local)
92
+ possible = daylights.map do |day|
93
+ schedule = IceCube::Schedule.new(day.dtstart) do |s|
94
+ day.rrule.each do |rule|
95
+ s.add_recurrence_rule IceCube::Rule.from_ical(rule.value_ical)
96
+ end
97
+ day.rdate.each do |date|
98
+ s.add_recurrence_date date
99
+ end
100
+ end
101
+ [schedule.previous_occurrence(local.to_time), day]
102
+ end
103
+ possible.sort_by(&:first).last
104
+ end
52
105
  end
53
106
  end
@@ -0,0 +1,33 @@
1
+ require 'delegate'
2
+ require 'icalendar/downcased_hash'
3
+
4
+ module Icalendar
5
+ class TimezoneStore < ::SimpleDelegator
6
+
7
+ def initialize
8
+ super DowncasedHash.new({})
9
+ end
10
+
11
+ def self.instance
12
+ @instance ||= new
13
+ end
14
+
15
+ def self.store(timezone)
16
+ instance.store timezone
17
+ end
18
+
19
+ def self.retrieve(tzid)
20
+ instance.retrieve tzid
21
+ end
22
+
23
+ def store(timezone)
24
+ self[timezone.tzid] = timezone
25
+ end
26
+
27
+ def retrieve(tzid)
28
+ self[tzid]
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -2,25 +2,37 @@ module Icalendar
2
2
  module Values
3
3
 
4
4
  # DateOrDateTime can be used to set an attribute to either a Date or a DateTime value.
5
- # It should not be used wihtout also invoking the `call` method.
6
- class DateOrDateTime
5
+ # It should not be used without also invoking the `call` method.
6
+ class DateOrDateTime < Value
7
7
 
8
- attr_reader :value, :params, :parsed
9
- def initialize(value, params = {})
10
- @value = value
11
- @params = params
8
+ def call
9
+ parsed
12
10
  end
13
11
 
14
- def call
12
+ def value_ical
13
+ parsed.value_ical
14
+ end
15
+
16
+ def params_ical
17
+ parsed.params_ical
18
+ end
19
+
20
+ private
21
+
22
+ def parsed
15
23
  @parsed ||= begin
16
- Icalendar::Values::DateTime.new value, params
24
+ Icalendar::Values::DateTime.new value, ical_params
17
25
  rescue Icalendar::Values::DateTime::FormatError
18
- Icalendar::Values::Date.new value, params
26
+ Icalendar::Values::Date.new value, ical_params
19
27
  end
20
28
  end
21
29
 
22
- def to_ical
23
- fail NoMethodError, 'You cannot use DateOrDateTime directly. Invoke `call` before `to_ical`'
30
+ def needs_value_type?(default_type)
31
+ parsed.class != default_type
32
+ end
33
+
34
+ def value_type
35
+ parsed.class.value_type
24
36
  end
25
37
 
26
38
  end
@@ -1,3 +1,5 @@
1
+ require 'icalendar/timezone_store'
2
+
1
3
  begin
2
4
  require 'active_support/time'
3
5
 
@@ -17,14 +19,17 @@ module Icalendar
17
19
  params = Icalendar::DowncasedHash(params)
18
20
  @tz_utc = params['tzid'] == 'UTC'
19
21
 
20
- if defined?(ActiveSupport::TimeZone) && defined?(ActiveSupportTimeWithZoneAdapter) && !params['tzid'].nil?
22
+ offset_value = if params['tzid'].present?
21
23
  tzid = params['tzid'].is_a?(::Array) ? params['tzid'].first : params['tzid']
22
- zone = ActiveSupport::TimeZone[tzid]
23
- value = ActiveSupportTimeWithZoneAdapter.new nil, zone, value unless zone.nil?
24
- super value, params
25
- else
26
- super value, params
24
+ if defined?(ActiveSupport::TimeZone) &&
25
+ defined?(ActiveSupportTimeWithZoneAdapter) &&
26
+ (tz = ActiveSupport::TimeZone[tzid])
27
+ ActiveSupportTimeWithZoneAdapter.new(nil, tz, value)
28
+ elsif (tz = TimezoneStore.retrieve(tzid))
29
+ value.change offset: tz.offset_for_local(value).to_s
30
+ end
27
31
  end
32
+ super((offset_value || value), params)
28
33
  end
29
34
 
30
35
  def params_ical
@@ -6,7 +6,7 @@ module Icalendar
6
6
  class Uri < Value
7
7
 
8
8
  def initialize(value, params = {})
9
- parsed = URI.parse value rescue value
9
+ parsed = URI.parse(value) rescue value
10
10
  super parsed, params
11
11
  end
12
12
 
@@ -16,4 +16,4 @@ module Icalendar
16
16
  end
17
17
 
18
18
  end
19
- end
19
+ end
@@ -21,6 +21,15 @@ module Icalendar
21
21
  "#{behind? ? '-' : '+'}#{'%02d' % hours}#{'%02d' % minutes}#{'%02d' % seconds if seconds > 0}"
22
22
  end
23
23
 
24
+ def to_s
25
+ str = "#{behind? ? '-' : '+'}#{'%02d' % hours}:#{'%02d' % minutes}"
26
+ if seconds > 0
27
+ "#{str}:#{'%02d' % seconds}"
28
+ else
29
+ str
30
+ end
31
+ end
32
+
24
33
  private
25
34
 
26
35
  def zero_offset?
@@ -1,5 +1,5 @@
1
1
  module Icalendar
2
2
 
3
- VERSION = '2.4.1'
3
+ VERSION = '2.5.0'
4
4
 
5
5
  end
@@ -96,6 +96,23 @@ describe Icalendar::Event do
96
96
  end
97
97
  end
98
98
 
99
+ describe "#append_custom_property" do
100
+ context "with custom property" do
101
+ it "appends to the custom properties hash" do
102
+ subject.append_custom_property "x_my_property", "test value"
103
+ expect(subject.custom_properties).to eq({"x_my_property" => ["test value"]})
104
+ end
105
+ end
106
+
107
+ context "with a defined property" do
108
+ it "sets the proper setter" do
109
+ subject.append_custom_property "summary", "event"
110
+ expect(subject.summary).to eq "event"
111
+ expect(subject.custom_properties).to eq({})
112
+ end
113
+ end
114
+ end
115
+
99
116
  describe '.parse' do
100
117
  let(:source) { File.read File.join(File.dirname(__FILE__), 'fixtures', fn) }
101
118
  let(:fn) { 'event.ics' }
@@ -9,7 +9,7 @@ DTSTART;TZID=US-Mountain:20050120T170000
9
9
  DTEND;TZID=US-Mountain:20050120T184500
10
10
  CLASS:PRIVATE
11
11
  GEO:37.386013;-122.0829322
12
- ORGANIZER:mailto:joebob@random.net
12
+ ORGANIZER;CN="Joe Bob: Magician":mailto:joebob@random.net
13
13
  PRIORITY:2
14
14
  SUMMARY:This is a really long summary to test the method of unfolding lines
15
15
  \, so I'm just going to make it a whole bunch of lines. With a twist: a "
@@ -0,0 +1,22 @@
1
+ BEGIN:VCALENDAR
2
+ VERSION:2.0
3
+ PRODID:bsprodidfortestabc123
4
+ CALSCALE:GREGORIAN
5
+ BEGIN:VEVENT
6
+ DTSTAMP:20050118T211523Z
7
+ UID:bsuidfortestabc123
8
+ DTSTART;TZID=US-Mountain:20050120T170000
9
+ DTEND;TZID=US-Mountain:20050120T184500
10
+ CLASS:PRIVATE
11
+ GEO:37.386013;-122.0829322
12
+ ORGANIZER;CN=Joe Bob\: Magician:mailto:joebob@random.net
13
+ PRIORITY:2
14
+ SUMMARY:This is a really long summary to test the method of unfolding lines
15
+ \, so I'm just going to make it a whole bunch of lines. With a twist: a "
16
+ ö" takes up multiple bytes\, and should be wrapped to the next line.
17
+ ATTACH:http://bush.sucks.org/impeach/him.rhtml
18
+ ATTACH:http://corporations-dominate.existence.net/why.rhtml
19
+ RDATE;TZID=US-Mountain:20050121T170000,20050122T170000
20
+ X-TEST-COMPONENT;QTEST="Hello, World":Shouldn't double double quotes
21
+ END:VEVENT
22
+ END:VCALENDAR
@@ -0,0 +1,22 @@
1
+ BEGIN:VCALENDAR
2
+ VERSION:2.0
3
+ PRODID:bsprodidfortestabc123
4
+ CALSCALE:GREGORIAN
5
+ BEGIN:VEVENT
6
+ DTSTAMP:20050118T211523Z
7
+ UID:bsuidfortestabc123
8
+ DTSTART;TZID=US-Mountain:20050120T170000
9
+ DTEND;TZID=US-Mountain:20050120T184500
10
+ CLASS:PRIVATE
11
+ GEO:37.386013;-122.0829322
12
+ ORGANIZER;CN=Joe Bob\:magician:mailto:joebob@random.net
13
+ PRIORITY:2
14
+ SUMMARY:This is a really long summary to test the method of unfolding lines
15
+ \, so I'm just going to make it a whole bunch of lines. With a twist: a "
16
+ ö" takes up multiple bytes\, and should be wrapped to the next line.
17
+ ATTACH:http://bush.sucks.org/impeach/him.rhtml
18
+ ATTACH:http://corporations-dominate.existence.net/why.rhtml
19
+ RDATE;TZID=US-Mountain:20050121T170000,20050122T170000
20
+ X-TEST-COMPONENT;QTEST="Hello, World":Shouldn't double double quotes
21
+ END:VEVENT
22
+ END:VCALENDAR
@@ -0,0 +1,31 @@
1
+ BEGIN:VCALENDAR
2
+ METHOD:PUBLISH
3
+ VERSION:2.0
4
+ CALSCALE:GREGORIAN
5
+ BEGIN:VTIMEZONE
6
+ TZID:(GMT-05:00) Eastern Time (US & Canada)
7
+ BEGIN:STANDARD
8
+ DTSTART:16011104T010000
9
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
10
+ TZOFFSETFROM:-0400
11
+ TZOFFSETTO:-0500
12
+ END:STANDARD
13
+ BEGIN:DAYLIGHT
14
+ DTSTART:16010311T030000
15
+ RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
16
+ TZOFFSETFROM:-0500
17
+ TZOFFSETTO:-0400
18
+ END:DAYLIGHT
19
+ END:VTIMEZONE
20
+ BEGIN:VEVENT
21
+ CREATED:20120104T225934Z
22
+ UID:23D50AF6-23D4-4CB5-85C6-4826F3F19999
23
+ DTEND;TZID="(GMT-05:00) Eastern Time (US & Canada)":20180104T130000
24
+ RRULE:FREQ=WEEKLY;INTERVAL=1
25
+ TRANSP:OPAQUE
26
+ SUMMARY:Recurring on Wed
27
+ DTSTART;TZID="(GMT-05:00) Eastern Time (US & Canada)":20180104T100000
28
+ DTSTAMP:20120104T231637Z
29
+ SEQUENCE:6
30
+ END:VEVENT
31
+ END:VCALENDAR
@@ -9,9 +9,10 @@ describe Icalendar::Parser do
9
9
  let(:fn) { 'single_event.ics' }
10
10
 
11
11
  it 'returns an array of calendars' do
12
- expect(subject.parse).to be_instance_of Array
13
- expect(subject.parse.count).to eq 1
14
- expect(subject.parse[0]).to be_instance_of Icalendar::Calendar
12
+ parsed = subject.parse
13
+ expect(parsed).to be_instance_of Array
14
+ expect(parsed.count).to eq 1
15
+ expect(parsed[0]).to be_instance_of Icalendar::Calendar
15
16
  end
16
17
 
17
18
  it 'properly splits multi-valued lines' do
@@ -38,9 +39,10 @@ describe Icalendar::Parser do
38
39
  before { subject.component_class = Icalendar::Event }
39
40
 
40
41
  it 'returns an array of events' do
41
- expect(subject.parse).to be_instance_of Array
42
- expect(subject.parse.count).to be 1
43
- expect(subject.parse[0]).to be_instance_of Icalendar::Event
42
+ parsed = subject.parse
43
+ expect(parsed).to be_instance_of Array
44
+ expect(parsed.count).to be 1
45
+ expect(parsed[0]).to be_instance_of Icalendar::Event
44
46
  end
45
47
  end
46
48
  context 'events.ics' do
@@ -55,15 +57,25 @@ describe Icalendar::Parser do
55
57
  expect(events.last.uid).to eq("uid-1234-uid-4321")
56
58
  end
57
59
  end
60
+ context 'tzid_search.ics' do
61
+ let(:fn) { 'tzid_search.ics' }
62
+
63
+ it 'correctly sets the weird tzid' do
64
+ parsed = subject.parse
65
+ event = parsed.first.events.first
66
+ expect(event.dtstart.utc).to eq Time.parse("20180104T150000Z")
67
+ end
68
+ end
58
69
  end
59
70
 
60
71
  describe '#parse with bad line' do
61
72
  let(:fn) { 'single_event_bad_line.ics' }
62
73
 
63
74
  it 'returns an array of calendars' do
64
- expect(subject.parse).to be_instance_of Array
65
- expect(subject.parse.count).to eq 1
66
- expect(subject.parse[0]).to be_instance_of Icalendar::Calendar
75
+ parsed = subject.parse
76
+ expect(parsed).to be_instance_of Array
77
+ expect(parsed.count).to eq 1
78
+ expect(parsed[0]).to be_instance_of Icalendar::Calendar
67
79
  end
68
80
 
69
81
  it 'properly splits multi-valued lines' do
@@ -19,6 +19,20 @@ describe Icalendar do
19
19
  end
20
20
  end
21
21
 
22
+ describe 'cleanly handle facebook organizers' do
23
+ let(:source) { File.read File.join(File.dirname(__FILE__), 'fixtures', 'single_event_bad_organizer.ics') }
24
+ let(:source_lowered_uri) { File.read File.join(File.dirname(__FILE__), 'fixtures', 'single_event_organizer_parsed.ics') }
25
+ it 'will generate the same file as it parsed' do
26
+ ical = Icalendar::Calendar.parse(source).first.to_ical
27
+ source_equal = ical == source
28
+ # rbx-3 parses the organizer as a URI, which strips the space and lowercases everything after the first :
29
+ # this is correct behavior, according to the icalendar spec, so we're not fudging the parser to accomodate
30
+ # facebook not properly wrapping the CN param in dquotes
31
+ source_lowered_equal = ical == source_lowered_uri
32
+ expect(source_equal || source_lowered_equal).to be true
33
+ end
34
+ end
35
+
22
36
  describe 'timezone round trip' do
23
37
  let(:source) { File.read File.join(File.dirname(__FILE__), 'fixtures', 'timezone.ics') }
24
38
  it 'will generate the same file as it parsed' do
@@ -38,4 +38,14 @@ describe Icalendar::Values::DateOrDateTime do
38
38
  end
39
39
  end
40
40
  end
41
+
42
+ describe "#to_ical" do
43
+ let(:event) { Icalendar::Event.new }
44
+ let(:time_stamp) { Time.now.strftime Icalendar::Values::DateTime::FORMAT }
45
+
46
+ it "should call parse behind the scenes" do
47
+ event.dtstart = described_class.new time_stamp, "tzid" => "UTC"
48
+ expect(event.to_ical).to include "DTSTART:#{time_stamp}Z"
49
+ end
50
+ end
41
51
  end
metadata CHANGED
@@ -1,141 +1,155 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: icalendar
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.1
4
+ version: 2.5.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: 2016-09-04 00:00:00.000000000 Z
11
+ date: 2018-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ice_cube
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.16'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.16'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rake
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: '10.0'
33
+ version: '12.0'
20
34
  type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: '10.0'
40
+ version: '12.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '1.3'
47
+ version: '1.16'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '1.3'
54
+ version: '1.16'
41
55
  - !ruby/object:Gem::Dependency
42
- name: tzinfo
56
+ name: activesupport
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '1.1'
61
+ version: '5.2'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '1.1'
68
+ version: '5.2'
55
69
  - !ruby/object:Gem::Dependency
56
- name: tzinfo-data
70
+ name: i18n
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '1.2014'
75
+ version: '1.1'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '1.2014'
82
+ version: '1.1'
69
83
  - !ruby/object:Gem::Dependency
70
- name: activesupport
84
+ name: tzinfo
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '3.2'
89
+ version: '1.2'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '3.2'
96
+ version: '1.2'
83
97
  - !ruby/object:Gem::Dependency
84
- name: i18n
98
+ name: tzinfo-data
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
- - - "<"
101
+ - - "~>"
88
102
  - !ruby/object:Gem::Version
89
- version: 0.7.0
103
+ version: '1.2018'
90
104
  type: :development
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
- - - "<"
108
+ - - "~>"
95
109
  - !ruby/object:Gem::Version
96
- version: 0.7.0
110
+ version: '1.2018'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: timecop
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: 0.7.0
117
+ version: '0.9'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
- version: 0.7.0
124
+ version: '0.9'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: rspec
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
129
  - - "~>"
116
130
  - !ruby/object:Gem::Version
117
- version: '3.0'
131
+ version: '3.8'
118
132
  type: :development
119
133
  prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
136
  - - "~>"
123
137
  - !ruby/object:Gem::Version
124
- version: '3.0'
138
+ version: '3.8'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: simplecov
127
141
  requirement: !ruby/object:Gem::Requirement
128
142
  requirements:
129
143
  - - "~>"
130
144
  - !ruby/object:Gem::Version
131
- version: '0.8'
145
+ version: '0.16'
132
146
  type: :development
133
147
  prerelease: false
134
148
  version_requirements: !ruby/object:Gem::Requirement
135
149
  requirements:
136
150
  - - "~>"
137
151
  - !ruby/object:Gem::Version
138
- version: '0.8'
152
+ version: '0.16'
139
153
  description: |
140
154
  Implements the iCalendar specification (RFC-5545) in Ruby. This allows
141
155
  for the generation and parsing of .ics files, which are used by a
@@ -149,9 +163,9 @@ files:
149
163
  - ".gitignore"
150
164
  - ".rspec"
151
165
  - ".travis.yml"
152
- - COPYING
153
166
  - Gemfile
154
167
  - History.txt
168
+ - LICENSE
155
169
  - README.md
156
170
  - Rakefile
157
171
  - icalendar.gemspec
@@ -168,6 +182,7 @@ files:
168
182
  - lib/icalendar/logger.rb
169
183
  - lib/icalendar/parser.rb
170
184
  - lib/icalendar/timezone.rb
185
+ - lib/icalendar/timezone_store.rb
171
186
  - lib/icalendar/todo.rb
172
187
  - lib/icalendar/tzinfo.rb
173
188
  - lib/icalendar/value.rb
@@ -201,11 +216,14 @@ files:
201
216
  - spec/fixtures/single_event.ics
202
217
  - spec/fixtures/single_event_bad_dtstart.ics
203
218
  - spec/fixtures/single_event_bad_line.ics
219
+ - spec/fixtures/single_event_bad_organizer.ics
220
+ - spec/fixtures/single_event_organizer_parsed.ics
204
221
  - spec/fixtures/timezone.ics
205
222
  - spec/fixtures/two_date_time_events.ics
206
223
  - spec/fixtures/two_day_events.ics
207
224
  - spec/fixtures/two_events.ics
208
225
  - spec/fixtures/two_time_events.ics
226
+ - spec/fixtures/tzid_search.ics
209
227
  - spec/freebusy_spec.rb
210
228
  - spec/journal_spec.rb
211
229
  - spec/parser_spec.rb
@@ -224,13 +242,10 @@ files:
224
242
  homepage: https://github.com/icalendar/icalendar
225
243
  licenses: []
226
244
  metadata: {}
227
- post_install_message: |
228
- HEADS UP! iCalendar 2.0 is not backwards-compatible with 1.x. Please see the README for the new syntax
229
-
230
- HEADS UP! icalendar 2.2.0 switches to non-strict parsing as default. Please see the README if you
231
- rely on strict parsing for information on how to enable it.
245
+ post_install_message: 'ActiveSupport is required for TimeWithZone support, but not
246
+ required for general use.
232
247
 
233
- ActiveSupport is required for TimeWithZone support, but not required for general use.
248
+ '
234
249
  rdoc_options: []
235
250
  require_paths:
236
251
  - lib
@@ -238,7 +253,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
238
253
  requirements:
239
254
  - - ">="
240
255
  - !ruby/object:Gem::Version
241
- version: 1.9.2
256
+ version: 2.2.0
242
257
  required_rubygems_version: !ruby/object:Gem::Requirement
243
258
  requirements:
244
259
  - - ">="
@@ -246,7 +261,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
246
261
  version: '0'
247
262
  requirements: []
248
263
  rubyforge_project:
249
- rubygems_version: 2.6.6
264
+ rubygems_version: 2.7.6
250
265
  signing_key:
251
266
  specification_version: 4
252
267
  summary: A ruby implementation of the iCalendar specification (RFC-5545).
@@ -262,11 +277,14 @@ test_files:
262
277
  - spec/fixtures/single_event.ics
263
278
  - spec/fixtures/single_event_bad_dtstart.ics
264
279
  - spec/fixtures/single_event_bad_line.ics
280
+ - spec/fixtures/single_event_bad_organizer.ics
281
+ - spec/fixtures/single_event_organizer_parsed.ics
265
282
  - spec/fixtures/timezone.ics
266
283
  - spec/fixtures/two_date_time_events.ics
267
284
  - spec/fixtures/two_day_events.ics
268
285
  - spec/fixtures/two_events.ics
269
286
  - spec/fixtures/two_time_events.ics
287
+ - spec/fixtures/tzid_search.ics
270
288
  - spec/freebusy_spec.rb
271
289
  - spec/journal_spec.rb
272
290
  - spec/parser_spec.rb