icalendar 2.9.0 → 2.10.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
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