icalendar 2.9.0 → 2.10.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f083428b61c781e197d459b5ba375139056f75e95b1b99e596169106a57ed20
4
- data.tar.gz: acb3cdb07b0dc052664fc67619fa6301951daf70ac83a0430a839a0bdd3a5923
3
+ metadata.gz: 7b9f7e30ef6614ad4175a9d282d1b03b57f140f98a2962b4e0268aa015f8f942
4
+ data.tar.gz: 7ebabfddd0f3d8e8e05e1ef82d2389007c1419c727c5404d2ec2c1c09565a8bb
5
5
  SHA512:
6
- metadata.gz: 595032415b8465be6f662f136a56dd6f4dd8af27e888c7a7b27ad1c688b3963466e34a949daa0111a65ea89037b33ea01d8f2ea24991f5d9a3869647521b6c7c
7
- data.tar.gz: ac464077d0c421d27b39270f1d12af23b59383e3e8351b68ec41a8385cc26670ca31b2f8dba72212e8db0996ea4a9e7c4a1b7b6a9b1b34d632169fae5a715725
6
+ metadata.gz: 8d3221e4e5bd2120014ae11fe80a8e0a3b36af37b10aadd18f3bc6022e296efa47ea27d09572900bb6d6419fff64054caa6709e6b14e5182d32a188d0130b7f0
7
+ data.tar.gz: 5d7d996d53a12543de0830fdb8214e2ae39df4c19c649e81cd95ceb8d30d61f1f178b7a9a4f4e37adb591609eeac7e89d930cf5ffc24951c9cbfcb0b815c2a03
@@ -17,13 +17,12 @@ jobs:
17
17
  strategy:
18
18
  matrix:
19
19
  ruby:
20
- - 2.7.6
21
- - 3.0.4
22
- - 3.1.2
20
+ - 3.0.6
21
+ - 3.1.4
23
22
  - 3.2.2
24
23
 
25
24
  steps:
26
- - uses: actions/checkout@v2
25
+ - uses: actions/checkout@v4
27
26
  - name: Set up Ruby
28
27
  uses: ruby/setup-ruby@v1
29
28
  with:
data/History.txt CHANGED
@@ -1,5 +1,13 @@
1
1
  === Unreleased
2
2
 
3
+ === 2.10.1 2023-12-01
4
+ * Parsing now handles VTIMEZONE blocks defined after their TZID is used in events and other components
5
+
6
+ === 2.10.0 2023-11-01
7
+ * Add changelog metadata to gemspec - Juri Hahn
8
+ * Attempt to rescue timezone info when given a nonstandard tzid with no VTIMEZONE
9
+ * Move Values classes that shouldn't be directly used into Helpers module
10
+
3
11
  === 2.9.0 2023-08-11
4
12
  * Always include the VALUE of Event URLs for improved compatibility - Sean Kelley
5
13
  * Improved parse performance - Thomas Cannon
data/icalendar.gemspec CHANGED
@@ -20,6 +20,10 @@ variety of calendaring applications.
20
20
  ActiveSupport is required for TimeWithZone support, but not required for general use.
21
21
  EOM
22
22
 
23
+ s.metadata = {
24
+ 'changelog_uri' => 'https://github.com/icalendar/icalendar/blob/main/History.txt'
25
+ }
26
+
23
27
  s.files = `git ls-files`.split "\n"
24
28
  s.test_files = `git ls-files -- {test,spec,features}/*`.split "\n"
25
29
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename f }
@@ -34,13 +38,13 @@ ActiveSupport is required for TimeWithZone support, but not required for general
34
38
 
35
39
  # test with all groups of tzinfo dependencies
36
40
  # tzinfo 2.x
37
- # s.add_development_dependency 'tzinfo', '~> 2.0'
38
- # s.add_development_dependency 'tzinfo-data', '~> 1.2020'
39
- # tzinfo 1.x
40
- s.add_development_dependency 'activesupport', '~> 6.0'
41
- s.add_development_dependency 'i18n', '~> 1.8'
42
- s.add_development_dependency 'tzinfo', '~> 1.2'
41
+ s.add_development_dependency 'activesupport', '~> 7.1'
42
+ s.add_development_dependency 'tzinfo', '~> 2.0'
43
43
  s.add_development_dependency 'tzinfo-data', '~> 1.2020'
44
+ # tzinfo 1.x
45
+ # s.add_development_dependency 'activesupport', '~> 6.0'
46
+ # s.add_development_dependency 'tzinfo', '~> 1.2'
47
+ # s.add_development_dependency 'tzinfo-data', '~> 1.2020'
44
48
  # tzinfo 0.x
45
49
  # s.add_development_dependency 'tzinfo', '~> 0.3'
46
50
  # end tzinfo
@@ -48,4 +52,5 @@ ActiveSupport is required for TimeWithZone support, but not required for general
48
52
  s.add_development_dependency 'timecop', '~> 0.9'
49
53
  s.add_development_dependency 'rspec', '~> 3.8'
50
54
  s.add_development_dependency 'simplecov', '~> 0.16'
55
+ s.add_development_dependency 'byebug'
51
56
  end
@@ -148,7 +148,7 @@ module Icalendar
148
148
 
149
149
  define_method "#{prop}=" do |value|
150
150
  mapped = map_property_value value, klass, true, new_property
151
- if mapped.is_a? Icalendar::Values::Array
151
+ if mapped.is_a? Icalendar::Values::Helpers::Array
152
152
  instance_variable_set property_var, mapped.to_a.compact
153
153
  else
154
154
  instance_variable_set property_var, [mapped].compact
@@ -179,7 +179,7 @@ module Icalendar
179
179
  if value.nil? || value.is_a?(Icalendar::Value)
180
180
  value
181
181
  elsif value.is_a? ::Array
182
- Icalendar::Values::Array.new value, klass, params, {delimiter: (multi_valued ? ',' : ';')}
182
+ Icalendar::Values::Helpers::Array.new value, klass, params, {delimiter: (multi_valued ? ',' : ';')}
183
183
  else
184
184
  klass.new value, params
185
185
  end
@@ -84,7 +84,7 @@ module Icalendar
84
84
  klass = get_wrapper_class component, fields
85
85
  if wrap_in_array? klass, fields[:value], multi_property
86
86
  delimiter = fields[:value].match(WRAP_PROPERTY_VALUE_DELIMETER_REGEX)[1]
87
- Icalendar::Values::Array.new fields[:value].split(WRAP_PROPERTY_VALUE_SPLIT_REGEX),
87
+ Icalendar::Values::Helpers::Array.new fields[:value].split(WRAP_PROPERTY_VALUE_SPLIT_REGEX),
88
88
  klass,
89
89
  fields[:params],
90
90
  delimiter: delimiter
@@ -211,7 +211,7 @@ module Icalendar
211
211
  param_value = param_value.gsub(PVALUE_GSUB_REGEX, '')
212
212
  params[param_name] << param_value
213
213
  if param_name == 'tzid'
214
- params['x-tz-info'] = timezone_store.retrieve param_value
214
+ params['x-tz-store'] = timezone_store
215
215
  end
216
216
  end
217
217
  end
@@ -108,15 +108,17 @@ module Icalendar
108
108
 
109
109
  def standard_for(local)
110
110
  possible = standards.map do |std|
111
- [std.previous_occurrence(local.to_time), std]
112
- end
111
+ prev = std.previous_occurrence(local.to_time)
112
+ [prev, std] unless prev.nil?
113
+ end.compact
113
114
  possible.sort_by(&:first).last
114
115
  end
115
116
 
116
117
  def daylight_for(local)
117
118
  possible = daylights.map do |day|
118
- [day.previous_occurrence(local.to_time), day]
119
- end
119
+ prev = day.previous_occurrence(local.to_time)
120
+ [prev, day] unless prev.nil?
121
+ end.compact
120
122
  possible.sort_by(&:first).last
121
123
  end
122
124
  end
@@ -72,7 +72,7 @@ module Icalendar
72
72
  end
73
73
 
74
74
  # helpers; not actual iCalendar value type
75
- require_relative 'values/array'
75
+ require_relative 'values/helpers/array'
76
76
  require_relative 'values/date_or_date_time'
77
77
 
78
78
  # iCalendar value types
@@ -10,7 +10,7 @@ module Icalendar
10
10
 
11
11
  def initialize(value, params = {})
12
12
  params.delete 'tzid'
13
- params.delete 'x-tz-info'
13
+ params.delete 'x-tz-store'
14
14
  if value.is_a? String
15
15
  begin
16
16
  parsed_date = ::Date.strptime(value, FORMAT)
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'date'
4
- require_relative 'time_with_zone'
4
+ require_relative 'helpers/time_with_zone'
5
5
 
6
6
  module Icalendar
7
7
  module Values
8
8
 
9
9
  class DateTime < Value
10
- include TimeWithZone
10
+ include Helpers::TimeWithZone
11
11
 
12
12
  FORMAT = '%Y%m%dT%H%M%S'
13
13
 
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Icalendar
4
+ module Values
5
+ module Helpers
6
+ class ActiveSupportTimeWithZoneAdapter < ActiveSupport::TimeWithZone
7
+ # ActiveSupport::TimeWithZone implements a #to_a method that will cause
8
+ # unexpected behavior in components with multi_property DateTime
9
+ # properties when the setters for those properties are invoked with an
10
+ # Icalendar::Values::DateTime that is delegating for an
11
+ # ActiveSupport::TimeWithZone. To avoid this behavior, undefine #to_a.
12
+ undef_method :to_a
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Icalendar
4
+ module Values
5
+ module Helpers
6
+
7
+ class Array < Value
8
+
9
+ attr_reader :value_delimiter
10
+
11
+ def initialize(value, klass, params = {}, options = {})
12
+ @value_delimiter = options[:delimiter] || ','
13
+ mapped = if value.is_a? ::Array
14
+ value.map do |v|
15
+ if v.is_a? Icalendar::Values::Helpers::Array
16
+ Icalendar::Values::Helpers::Array.new v.value, klass, v.ical_params, delimiter: v.value_delimiter
17
+ elsif v.is_a? ::Array
18
+ Icalendar::Values::Helpers::Array.new v, klass, params, delimiter: value_delimiter
19
+ elsif v.is_a? Icalendar::Value
20
+ v
21
+ else
22
+ klass.new v, params
23
+ end
24
+ end
25
+ else
26
+ [klass.new(value, params)]
27
+ end
28
+ super mapped
29
+ end
30
+
31
+ def params_ical
32
+ value.each do |v|
33
+ ical_params.merge! v.ical_params
34
+ end
35
+ super
36
+ end
37
+
38
+ def value_ical
39
+ value.map do |v|
40
+ v.value_ical
41
+ end.join value_delimiter
42
+ end
43
+
44
+ def valid?
45
+ klass = value.first.class
46
+ !value.all? { |v| v.class == klass }
47
+ end
48
+
49
+ def value_type
50
+ value.first.value_type
51
+ end
52
+
53
+ private
54
+
55
+ def needs_value_type?(default_type)
56
+ value.first.class != default_type
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'active_support/time'
5
+
6
+ if defined?(ActiveSupport::TimeWithZone)
7
+ require_relative 'active_support_time_with_zone_adapter'
8
+ end
9
+ rescue NameError
10
+ # ActiveSupport v7+ needs the base require to be run first before loading
11
+ # specific parts of it.
12
+ # https://guides.rubyonrails.org/active_support_core_extensions.html#stand-alone-active-support
13
+ require 'active_support'
14
+ retry
15
+ rescue LoadError
16
+ # tis ok, just a bit less fancy
17
+ end
18
+
19
+ module Icalendar
20
+ module Values
21
+ module Helpers
22
+ module TimeWithZone
23
+ attr_reader :tz_utc, :timezone_store
24
+
25
+ def initialize(value, params = {})
26
+ params = Icalendar::DowncasedHash(params)
27
+ @tz_utc = params['tzid'] == 'UTC'
28
+ @timezone_store = params.delete 'x-tz-store'
29
+ super (offset_value(value, params) || value), params
30
+ end
31
+
32
+ def __getobj__
33
+ orig_value = super
34
+ if set_offset?
35
+ orig_value
36
+ else
37
+ offset = offset_value(orig_value, ical_params)
38
+ __setobj__(offset) unless offset.nil?
39
+ offset || orig_value
40
+ end
41
+ end
42
+
43
+ def params_ical
44
+ ical_params.delete 'tzid' if tz_utc
45
+ super
46
+ end
47
+
48
+ private
49
+
50
+ def offset_value(value, params)
51
+ @offset_value = unless params.nil? || params['tzid'].nil?
52
+ tzid = params['tzid'].is_a?(::Array) ? params['tzid'].first : params['tzid']
53
+ support_classes_defined = defined?(ActiveSupport::TimeZone) && defined?(ActiveSupportTimeWithZoneAdapter)
54
+ if support_classes_defined && (tz = ActiveSupport::TimeZone[tzid])
55
+ Icalendar.logger.debug("Plan a - parsing #{value}/#{tzid} as ActiveSupport::TimeWithZone")
56
+ # plan a - use ActiveSupport::TimeWithZone
57
+ ActiveSupportTimeWithZoneAdapter.new(nil, tz, value)
58
+ elsif !timezone_store.nil? && !(x_tz_info = timezone_store.retrieve(tzid)).nil?
59
+ # plan b - use definition from provided `VTIMEZONE`
60
+ offset = x_tz_info.offset_for_local(value).to_s
61
+ Icalendar.logger.debug("Plan b - parsing #{value} with offset: #{offset}")
62
+ if value.respond_to?(:change)
63
+ value.change offset: offset
64
+ else
65
+ ::Time.new value.year, value.month, value.day, value.hour, value.min, value.sec, offset
66
+ end
67
+ elsif support_classes_defined && (tz = ActiveSupport::TimeZone[tzid.split.first])
68
+ # plan c - try to find an ActiveSupport::TimeWithZone based on the first word of the tzid
69
+ Icalendar.logger.debug("Plan c - parsing #{value}/#{tz.tzinfo.name} as ActiveSupport::TimeWithZone")
70
+ params['tzid'] = [tz.tzinfo.name]
71
+ ActiveSupportTimeWithZoneAdapter.new(nil, tz, value)
72
+ else
73
+ # plan d - just ignore the tzid
74
+ Icalendar.logger.info("Ignoring timezone #{tzid} for time #{value}")
75
+ nil
76
+ end
77
+ end
78
+ end
79
+
80
+ def set_offset?
81
+ !!@offset_value
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'date'
4
- require_relative 'time_with_zone'
4
+ require_relative 'helpers/time_with_zone'
5
5
 
6
6
  module Icalendar
7
7
  module Values
8
8
 
9
9
  class Time < Value
10
- include TimeWithZone
10
+ include Helpers::TimeWithZone
11
11
 
12
12
  FORMAT = '%H%M%S'
13
13
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Icalendar
4
4
 
5
- VERSION = '2.9.0'
5
+ VERSION = '2.10.1'
6
6
 
7
7
  end
@@ -0,0 +1,143 @@
1
+ BEGIN:VCALENDAR
2
+ VERSION:2.0
3
+ X-WR-CALNAME:My Calendar
4
+ X-APPLE-CALENDAR-COLOR:#44A703
5
+ BEGIN:VEVENT
6
+ CREATED:20231026T211915Z
7
+ DTEND;TZID=NONSTANDARDTZ:20231025T180000
8
+ DTSTAMP:20231026T211916Z
9
+ DTSTART;TZID=NONSTANDARDTZ:20231025T163000
10
+ LAST-MODIFIED:20231026T211915Z
11
+ LOCATION:Somewhere
12
+ SEQUENCE:0
13
+ SUMMARY:Summary summary summary
14
+ UID:some-unique-uid
15
+ END:VEVENT
16
+ BEGIN:VTIMEZONE
17
+ TZID:NONSTANDARDTZ
18
+ X-LIC-LOCATION:NONSTANDARDTZ
19
+ BEGIN:STANDARD
20
+ DTSTART:18831118T120702
21
+ RDATE:18831118T120702
22
+ TZNAME:PST
23
+ TZOFFSETFROM:-075258
24
+ TZOFFSETTO:-0800
25
+ END:STANDARD
26
+ BEGIN:DAYLIGHT
27
+ DTSTART:19180331T020000
28
+ RRULE:FREQ=YEARLY;UNTIL=19190330T100000Z;BYMONTH=3;BYDAY=-1SU
29
+ TZNAME:PDT
30
+ TZOFFSETFROM:-0800
31
+ TZOFFSETTO:-0700
32
+ END:DAYLIGHT
33
+ BEGIN:STANDARD
34
+ DTSTART:19181027T020000
35
+ RRULE:FREQ=YEARLY;UNTIL=19191026T090000Z;BYMONTH=10;BYDAY=-1SU
36
+ TZNAME:PST
37
+ TZOFFSETFROM:-0700
38
+ TZOFFSETTO:-0800
39
+ END:STANDARD
40
+ BEGIN:DAYLIGHT
41
+ DTSTART:19420209T020000
42
+ RDATE:19420209T020000
43
+ TZNAME:PWT
44
+ TZOFFSETFROM:-0800
45
+ TZOFFSETTO:-0700
46
+ END:DAYLIGHT
47
+ BEGIN:DAYLIGHT
48
+ DTSTART:19450814T160000
49
+ RDATE:19450814T160000
50
+ TZNAME:PPT
51
+ TZOFFSETFROM:-0700
52
+ TZOFFSETTO:-0700
53
+ END:DAYLIGHT
54
+ BEGIN:STANDARD
55
+ DTSTART:19450930T020000
56
+ RDATE:19450930T020000
57
+ RDATE:19490101T020000
58
+ TZNAME:PST
59
+ TZOFFSETFROM:-0700
60
+ TZOFFSETTO:-0800
61
+ END:STANDARD
62
+ BEGIN:STANDARD
63
+ DTSTART:19460101T000000
64
+ RDATE:19460101T000000
65
+ RDATE:19670101T000000
66
+ TZNAME:PST
67
+ TZOFFSETFROM:-0800
68
+ TZOFFSETTO:-0800
69
+ END:STANDARD
70
+ BEGIN:DAYLIGHT
71
+ DTSTART:19480314T020100
72
+ RDATE:19480314T020100
73
+ RDATE:19740106T020000
74
+ RDATE:19750223T020000
75
+ TZNAME:PDT
76
+ TZOFFSETFROM:-0800
77
+ TZOFFSETTO:-0700
78
+ END:DAYLIGHT
79
+ BEGIN:DAYLIGHT
80
+ DTSTART:19500430T010000
81
+ RRULE:FREQ=YEARLY;UNTIL=19660424T090000Z;BYMONTH=4;BYDAY=-1SU
82
+ TZNAME:PDT
83
+ TZOFFSETFROM:-0800
84
+ TZOFFSETTO:-0700
85
+ END:DAYLIGHT
86
+ BEGIN:STANDARD
87
+ DTSTART:19500924T020000
88
+ RRULE:FREQ=YEARLY;UNTIL=19610924T090000Z;BYMONTH=9;BYDAY=-1SU
89
+ TZNAME:PST
90
+ TZOFFSETFROM:-0700
91
+ TZOFFSETTO:-0800
92
+ END:STANDARD
93
+ BEGIN:STANDARD
94
+ DTSTART:19621028T020000
95
+ RRULE:FREQ=YEARLY;UNTIL=19661030T090000Z;BYMONTH=10;BYDAY=-1SU
96
+ TZNAME:PST
97
+ TZOFFSETFROM:-0700
98
+ TZOFFSETTO:-0800
99
+ END:STANDARD
100
+ BEGIN:DAYLIGHT
101
+ DTSTART:19670430T020000
102
+ RRULE:FREQ=YEARLY;UNTIL=19730429T100000Z;BYMONTH=4;BYDAY=-1SU
103
+ TZNAME:PDT
104
+ TZOFFSETFROM:-0800
105
+ TZOFFSETTO:-0700
106
+ END:DAYLIGHT
107
+ BEGIN:STANDARD
108
+ DTSTART:19671029T020000
109
+ RRULE:FREQ=YEARLY;UNTIL=20061029T090000Z;BYMONTH=10;BYDAY=-1SU
110
+ TZNAME:PST
111
+ TZOFFSETFROM:-0700
112
+ TZOFFSETTO:-0800
113
+ END:STANDARD
114
+ BEGIN:DAYLIGHT
115
+ DTSTART:19760425T020000
116
+ RRULE:FREQ=YEARLY;UNTIL=19860427T100000Z;BYMONTH=4;BYDAY=-1SU
117
+ TZNAME:PDT
118
+ TZOFFSETFROM:-0800
119
+ TZOFFSETTO:-0700
120
+ END:DAYLIGHT
121
+ BEGIN:DAYLIGHT
122
+ DTSTART:19870405T020000
123
+ RRULE:FREQ=YEARLY;UNTIL=20060402T100000Z;BYMONTH=4;BYDAY=1SU
124
+ TZNAME:PDT
125
+ TZOFFSETFROM:-0800
126
+ TZOFFSETTO:-0700
127
+ END:DAYLIGHT
128
+ BEGIN:DAYLIGHT
129
+ DTSTART:20070311T020000
130
+ RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
131
+ TZNAME:PDT
132
+ TZOFFSETFROM:-0800
133
+ TZOFFSETTO:-0700
134
+ END:DAYLIGHT
135
+ BEGIN:STANDARD
136
+ DTSTART:20071104T020000
137
+ RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
138
+ TZNAME:PST
139
+ TZOFFSETFROM:-0700
140
+ TZOFFSETTO:-0800
141
+ END:STANDARD
142
+ END:VTIMEZONE
143
+ END:VCALENDAR
data/spec/parser_spec.rb CHANGED
@@ -5,6 +5,15 @@ describe Icalendar::Parser do
5
5
  let(:source) { File.read File.join(File.dirname(__FILE__), 'fixtures', fn) }
6
6
 
7
7
  describe '#parse' do
8
+ context 'reversed_timezone.ics' do
9
+ let(:fn) { 'reversed_timezone.ics' }
10
+
11
+ it 'correctly parses the event timezone' do
12
+ event = subject.parse.first.events.first
13
+ expect(event.dtstart.utc_offset).to eq -25200
14
+ end
15
+ end
16
+
8
17
  context 'single_event.ics' do
9
18
  let(:fn) { 'single_event.ics' }
10
19
 
@@ -14,7 +14,7 @@ describe Icalendar do
14
14
  event = Icalendar::Event.new
15
15
  parsed = Icalendar::Calendar.parse(source).first
16
16
  event.rdate = parsed.events.first.rdate
17
- expect(event.rdate.first).to be_kind_of Icalendar::Values::Array
17
+ expect(event.rdate.first).to be_kind_of Icalendar::Values::Helpers::Array
18
18
  expect(event.rdate.first.params_ical).to eq ";TZID=US-Mountain"
19
19
  end
20
20
  end
@@ -27,6 +27,22 @@ describe Icalendar::Values::DateTime do
27
27
  expect(subject.value.utc.hour).to eq 23
28
28
  end
29
29
  end
30
+
31
+ context 'nonstandard format tzid local time' do
32
+ let(:value) { '20230901T230404' }
33
+ let(:params) { {'tzid' => 'Singapore Standard Time'} }
34
+
35
+ it 'parses the value as local time' do
36
+ expect(subject.value.hour).to eq 23
37
+ expect(subject.value.utc_offset).to eq 28800
38
+ expect(subject.value.utc.hour).to eq 15
39
+ end
40
+
41
+ it 'updates the tzid' do
42
+ # use an array because that's how output from the parser will end up
43
+ expect(subject.ical_params['tzid']).to eq ['Asia/Singapore']
44
+ end
45
+ end
30
46
  end
31
47
 
32
48
  else
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.9.0
4
+ version: 2.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Ahearn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-11 00:00:00.000000000 Z
11
+ date: 2023-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ice_cube
@@ -58,42 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '6.0'
61
+ version: '7.1'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '6.0'
69
- - !ruby/object:Gem::Dependency
70
- name: i18n
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '1.8'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '1.8'
68
+ version: '7.1'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: tzinfo
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
73
  - - "~>"
88
74
  - !ruby/object:Gem::Version
89
- version: '1.2'
75
+ version: '2.0'
90
76
  type: :development
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
- version: '1.2'
82
+ version: '2.0'
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: tzinfo-data
99
85
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +136,20 @@ dependencies:
150
136
  - - "~>"
151
137
  - !ruby/object:Gem::Version
152
138
  version: '0.16'
139
+ - !ruby/object:Gem::Dependency
140
+ name: byebug
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
153
  description: |
154
154
  Implements the iCalendar specification (RFC-5545) in Ruby. This allows
155
155
  for the generation and parsing of .ics files, which are used by a
@@ -187,8 +187,6 @@ files:
187
187
  - lib/icalendar/todo.rb
188
188
  - lib/icalendar/tzinfo.rb
189
189
  - lib/icalendar/value.rb
190
- - lib/icalendar/values/active_support_time_with_zone_adapter.rb
191
- - lib/icalendar/values/array.rb
192
190
  - lib/icalendar/values/binary.rb
193
191
  - lib/icalendar/values/boolean.rb
194
192
  - lib/icalendar/values/cal_address.rb
@@ -197,12 +195,14 @@ files:
197
195
  - lib/icalendar/values/date_time.rb
198
196
  - lib/icalendar/values/duration.rb
199
197
  - lib/icalendar/values/float.rb
198
+ - lib/icalendar/values/helpers/active_support_time_with_zone_adapter.rb
199
+ - lib/icalendar/values/helpers/array.rb
200
+ - lib/icalendar/values/helpers/time_with_zone.rb
200
201
  - lib/icalendar/values/integer.rb
201
202
  - lib/icalendar/values/period.rb
202
203
  - lib/icalendar/values/recur.rb
203
204
  - lib/icalendar/values/text.rb
204
205
  - lib/icalendar/values/time.rb
205
- - lib/icalendar/values/time_with_zone.rb
206
206
  - lib/icalendar/values/uri.rb
207
207
  - lib/icalendar/values/utc_offset.rb
208
208
  - lib/icalendar/version.rb
@@ -216,6 +216,7 @@ files:
216
216
  - spec/fixtures/nondefault_values.ics
217
217
  - spec/fixtures/nonstandard.ics
218
218
  - spec/fixtures/recurrence.ics
219
+ - spec/fixtures/reversed_timezone.ics
219
220
  - spec/fixtures/single_event.ics
220
221
  - spec/fixtures/single_event_bad_dtstart.ics
221
222
  - spec/fixtures/single_event_bad_line.ics
@@ -247,7 +248,8 @@ licenses:
247
248
  - BSD-2-Clause
248
249
  - GPL-3.0-only
249
250
  - icalendar
250
- metadata: {}
251
+ metadata:
252
+ changelog_uri: https://github.com/icalendar/icalendar/blob/main/History.txt
251
253
  post_install_message: 'ActiveSupport is required for TimeWithZone support, but not
252
254
  required for general use.
253
255
 
@@ -266,7 +268,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
266
268
  - !ruby/object:Gem::Version
267
269
  version: '0'
268
270
  requirements: []
269
- rubygems_version: 3.3.7
271
+ rubygems_version: 3.3.26
270
272
  signing_key:
271
273
  specification_version: 4
272
274
  summary: A ruby implementation of the iCalendar specification (RFC-5545).
@@ -281,6 +283,7 @@ test_files:
281
283
  - spec/fixtures/nondefault_values.ics
282
284
  - spec/fixtures/nonstandard.ics
283
285
  - spec/fixtures/recurrence.ics
286
+ - spec/fixtures/reversed_timezone.ics
284
287
  - spec/fixtures/single_event.ics
285
288
  - spec/fixtures/single_event_bad_dtstart.ics
286
289
  - spec/fixtures/single_event_bad_line.ics
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Icalendar
4
- module Values
5
- class ActiveSupportTimeWithZoneAdapter < ActiveSupport::TimeWithZone
6
- # ActiveSupport::TimeWithZone implements a #to_a method that will cause
7
- # unexpected behavior in components with multi_property DateTime
8
- # properties when the setters for those properties are invoked with an
9
- # Icalendar::Values::DateTime that is delegating for an
10
- # ActiveSupport::TimeWithZone. To avoid this behavior, undefine #to_a.
11
- undef_method :to_a
12
- end
13
- end
14
- end
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Icalendar
4
- module Values
5
-
6
- class Array < Value
7
-
8
- attr_reader :value_delimiter
9
-
10
- def initialize(value, klass, params = {}, options = {})
11
- @value_delimiter = options[:delimiter] || ','
12
- mapped = if value.is_a? ::Array
13
- value.map do |v|
14
- if v.is_a? Icalendar::Values::Array
15
- Icalendar::Values::Array.new v.value, klass, v.ical_params, delimiter: v.value_delimiter
16
- elsif v.is_a? ::Array
17
- Icalendar::Values::Array.new v, klass, params, delimiter: value_delimiter
18
- elsif v.is_a? Icalendar::Value
19
- v
20
- else
21
- klass.new v, params
22
- end
23
- end
24
- else
25
- [klass.new(value, params)]
26
- end
27
- super mapped
28
- end
29
-
30
- def params_ical
31
- value.each do |v|
32
- ical_params.merge! v.ical_params
33
- end
34
- super
35
- end
36
-
37
- def value_ical
38
- value.map do |v|
39
- v.value_ical
40
- end.join value_delimiter
41
- end
42
-
43
- def valid?
44
- klass = value.first.class
45
- !value.all? { |v| v.class == klass }
46
- end
47
-
48
- def value_type
49
- value.first.value_type
50
- end
51
-
52
- private
53
-
54
- def needs_value_type?(default_type)
55
- value.first.class != default_type
56
- end
57
- end
58
-
59
- end
60
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'icalendar/timezone_store'
4
-
5
- begin
6
- require 'active_support/time'
7
-
8
- if defined?(ActiveSupport::TimeWithZone)
9
- require 'icalendar/values/active_support_time_with_zone_adapter'
10
- end
11
- rescue NameError
12
- # ActiveSupport v7+ needs the base require to be run first before loading
13
- # specific parts of it.
14
- # https://guides.rubyonrails.org/active_support_core_extensions.html#stand-alone-active-support
15
- require 'active_support'
16
- retry
17
- rescue LoadError
18
- # tis ok, just a bit less fancy
19
- end
20
-
21
- module Icalendar
22
- module Values
23
- module TimeWithZone
24
- attr_reader :tz_utc
25
-
26
- def initialize(value, params = {})
27
- params = Icalendar::DowncasedHash(params)
28
- @tz_utc = params['tzid'] == 'UTC'
29
- x_tz_info = params.delete 'x-tz-info'
30
-
31
- offset_value = unless params['tzid'].nil?
32
- tzid = params['tzid'].is_a?(::Array) ? params['tzid'].first : params['tzid']
33
- if defined?(ActiveSupport::TimeZone) &&
34
- defined?(ActiveSupportTimeWithZoneAdapter) &&
35
- (tz = ActiveSupport::TimeZone[tzid])
36
- ActiveSupportTimeWithZoneAdapter.new(nil, tz, value)
37
- elsif !x_tz_info.nil?
38
- offset = x_tz_info.offset_for_local(value).to_s
39
- if value.respond_to?(:change)
40
- value.change offset: offset
41
- else
42
- ::Time.new value.year, value.month, value.day, value.hour, value.min, value.sec, offset
43
- end
44
- end
45
- end
46
- super((offset_value || value), params)
47
- end
48
-
49
- def params_ical
50
- ical_params.delete 'tzid' if tz_utc
51
- super
52
- end
53
- end
54
- end
55
- end