icalendar 2.4.1 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
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