icalendar 2.9.0 → 2.10.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
2
  SHA256:
3
- metadata.gz: 0f083428b61c781e197d459b5ba375139056f75e95b1b99e596169106a57ed20
4
- data.tar.gz: acb3cdb07b0dc052664fc67619fa6301951daf70ac83a0430a839a0bdd3a5923
3
+ metadata.gz: 4a4c654b36ffe5a09f521ad3c012686f12e582ba5d380242c646334f47153360
4
+ data.tar.gz: 184399a11e6e8a39b18ceeef59de8a9b9f7cd581f0c7169cce5c7dca63575e3b
5
5
  SHA512:
6
- metadata.gz: 595032415b8465be6f662f136a56dd6f4dd8af27e888c7a7b27ad1c688b3963466e34a949daa0111a65ea89037b33ea01d8f2ea24991f5d9a3869647521b6c7c
7
- data.tar.gz: ac464077d0c421d27b39270f1d12af23b59383e3e8351b68ec41a8385cc26670ca31b2f8dba72212e8db0996ea4a9e7c4a1b7b6a9b1b34d632169fae5a715725
6
+ metadata.gz: 61837b5d19193d80d72f37edff89290fc2e5ffa0c6b9ee500036de58b0fbd9aacb5e0e9bc9f1a0a4e1ce7a3ad494ed0147e87bf697b54523d8b799e9eaa275fa
7
+ data.tar.gz: 00d54cc0ab4b7fc6acf616a537b426d110ddbe65dda1d6ab8ec938ba2df64e87def99023916c6193ab25d1885a2a60e8a1706617ed5a6e0adb5cb34671dae1ec
@@ -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,10 @@
1
1
  === Unreleased
2
2
 
3
+ === 2.10.0 2023-11-01
4
+ * Add changelog metadata to gemspec - Juri Hahn
5
+ * Attempt to rescue timezone info when given a nonstandard tzid with no VTIMEZONE
6
+ * Move Values classes that shouldn't be directly used into Helpers module
7
+
3
8
  === 2.9.0 2023-08-11
4
9
  * Always include the VALUE of Event URLs for improved compatibility - Sean Kelley
5
10
  * 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 }
@@ -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
@@ -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
@@ -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,61 @@
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
24
+
25
+ def initialize(value, params = {})
26
+ params = Icalendar::DowncasedHash(params)
27
+ @tz_utc = params['tzid'] == 'UTC'
28
+ x_tz_info = params.delete 'x-tz-info'
29
+
30
+ offset_value = unless params['tzid'].nil?
31
+ tzid = params['tzid'].is_a?(::Array) ? params['tzid'].first : params['tzid']
32
+ support_classes_defined = defined?(ActiveSupport::TimeZone) && defined?(ActiveSupportTimeWithZoneAdapter)
33
+ if support_classes_defined && (tz = ActiveSupport::TimeZone[tzid])
34
+ # plan a - use ActiveSupport::TimeWithZone
35
+ ActiveSupportTimeWithZoneAdapter.new(nil, tz, value)
36
+ elsif !x_tz_info.nil?
37
+ # plan b - use definition from provided `VTIMEZONE`
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
+ elsif support_classes_defined && (tz = ActiveSupport::TimeZone[tzid.split.first])
45
+ # plan c - try to find an ActiveSupport::TimeWithZone based on the first word of the tzid
46
+ params['tzid'] = [tz.tzinfo.name]
47
+ ActiveSupportTimeWithZoneAdapter.new(nil, tz, value)
48
+ end
49
+ # plan d - just ignore the tzid
50
+ end
51
+ super((offset_value || value), params)
52
+ end
53
+
54
+ def params_ical
55
+ ical_params.delete 'tzid' if tz_utc
56
+ super
57
+ end
58
+ end
59
+ end
60
+ end
61
+ 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.0'
6
6
 
7
7
  end
@@ -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.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: 2023-08-11 00:00:00.000000000 Z
11
+ date: 2023-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ice_cube
@@ -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
@@ -247,7 +247,8 @@ licenses:
247
247
  - BSD-2-Clause
248
248
  - GPL-3.0-only
249
249
  - icalendar
250
- metadata: {}
250
+ metadata:
251
+ changelog_uri: https://github.com/icalendar/icalendar/blob/main/History.txt
251
252
  post_install_message: 'ActiveSupport is required for TimeWithZone support, but not
252
253
  required for general use.
253
254
 
@@ -266,7 +267,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
266
267
  - !ruby/object:Gem::Version
267
268
  version: '0'
268
269
  requirements: []
269
- rubygems_version: 3.3.7
270
+ rubygems_version: 3.4.10
270
271
  signing_key:
271
272
  specification_version: 4
272
273
  summary: A ruby implementation of the iCalendar specification (RFC-5545).
@@ -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