icalendar 2.12.2 → 2.12.4

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: ad06e861392ab70f0e800ac4f2a6b81f019aaf3548a35e513f02bcc975968b86
4
- data.tar.gz: 16562bdeae817fc8afd4e0b6de7090a42c0b095cb56640d5b9183cfb3a07bb74
3
+ metadata.gz: 6a9a656fd81bc80eb43cf61e14d95a3b582f66bae80417da16a7e5d621910581
4
+ data.tar.gz: df88f0f0a1619dbdcba157316aba616019d146fe74e46aba6d7603dc30b40c26
5
5
  SHA512:
6
- metadata.gz: 927cd1536b413039b75f4c2a100ca169bb17897c10754b4806762d341aaa4b7800fc93e7bc81566681a678a853fefc0d54fad5fdd0316c10f0245f91864d2faf
7
- data.tar.gz: 5d9c09347062a5dd73ad23cd75905c5508b8a72ce0447241ee282fa6bbcc7d259e4a26309fc90af718f14f14b18ca78403bc849898b42147c5368ae6edb21d13
6
+ metadata.gz: a0ad4eb07a4123fba9260916530046bd008a9f076a26a276f09a31cce789aa0801a38fff3d553b7b11fcb3de072c72aff758921ad601d7e643b808495425b0df
7
+ data.tar.gz: 06bab135b068613fdf8c4d10554a327a35b2072eb5e37c5e7bc7509b8e62b05e596153cfa8985065b2739e99eb7bc90dd8282c173972929900aa763d58e218b1
@@ -22,9 +22,10 @@ jobs:
22
22
  - 3.2
23
23
  - 3.3
24
24
  - 3.4
25
+ - "4.0"
25
26
 
26
27
  steps:
27
- - uses: actions/checkout@v4
28
+ - uses: actions/checkout@v6
28
29
  - name: Set up Ruby
29
30
  uses: ruby/setup-ruby@v1
30
31
  with:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  ## Unreleased
2
2
 
3
+ ## 2.12.4 - 2026-07-31
4
+ - TEXT unescape fix - Vincent Gao
5
+
6
+ ## 2.12.3 - 2026-05-13
7
+ - Memory use optimization - Jared Menard
8
+ - Run CI against Ruby 4.0 - Artem Chubchenko
9
+
3
10
  ## 2.12.2 - 2026-03-21
4
11
  - Fix a potential property injection issue through escaping control characters in URI values - Wes Ring
5
12
 
@@ -0,0 +1,27 @@
1
+ require 'memory_profiler'
2
+ require 'icalendar'
3
+
4
+ # Profiles the per-event calendar wrapping pattern:
5
+ # cal = Icalendar::Calendar.new
6
+ # ical_event.parent&.timezones&.each { |tz| cal.add_timezone tz }
7
+ # cal.add_event(ical_event)
8
+ # cal.to_ical
9
+
10
+ cal_string = File.read(File.join(__dir__, '..', 'spec/fixtures/timezone.ics'))
11
+ source_calendar = Icalendar::Calendar.parse(cal_string).first
12
+ events = source_calendar.events
13
+
14
+ ITERATIONS = 1000
15
+
16
+ report = MemoryProfiler.report do
17
+ ITERATIONS.times do
18
+ events.each do |ical_event|
19
+ cal = Icalendar::Calendar.new
20
+ ical_event.parent&.timezones&.each { |tz| cal.add_timezone tz }
21
+ cal.add_event(ical_event)
22
+ cal.to_ical
23
+ end
24
+ end
25
+ end
26
+
27
+ report.pretty_print(scale_bytes: true, top: 20)
data/icalendar.gemspec CHANGED
@@ -37,7 +37,7 @@ ActiveSupport is required for TimeWithZone support, but not required for general
37
37
  s.add_dependency 'ostruct'
38
38
 
39
39
  s.add_development_dependency 'rake', '~> 13.0'
40
- s.add_development_dependency 'bundler', '~> 2.0'
40
+ s.add_development_dependency 'bundler'
41
41
 
42
42
  # test with all groups of tzinfo dependencies
43
43
  # tzinfo 2.x
@@ -172,13 +172,11 @@ module Icalendar
172
172
  private
173
173
 
174
174
  def map_property_value(value, klass, multi_valued, new_property)
175
- params = {}
176
- if new_property
177
- params.merge!('VALUE': klass.value_type)
178
- end
179
- if value.nil? || value.is_a?(Icalendar::Value)
180
- value
181
- elsif value.is_a? ::Array
175
+ return value if value.nil? || value.is_a?(Icalendar::Value)
176
+
177
+ params = new_property ? {'VALUE': klass.value_type} : {}
178
+
179
+ if value.is_a? ::Array
182
180
  Icalendar::Values::Helpers::Array.new value, klass, params, {delimiter: (multi_valued ? ',' : ';')}
183
181
  else
184
182
  klass.new value, params
@@ -3,11 +3,11 @@
3
3
  module Icalendar
4
4
  module Values
5
5
  class Text < Value
6
+ UNESCAPE_GSUB_REGEX = /\\([\\,;nN])/.freeze
7
+
6
8
  def initialize(value, *args)
7
- value = value.gsub('\n', "\n")
8
- value.gsub!('\,', ',')
9
- value.gsub!('\;', ';')
10
- value.gsub!('\\\\') { '\\' }
9
+ # One left-to-right pass keeps unescape the exact inverse of value_ical; \n and \N are newline.
10
+ value = value.gsub(UNESCAPE_GSUB_REGEX) { |_| %w[n N].include?($1) ? "\n" : $1 }
11
11
  super value, *args
12
12
  end
13
13
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Icalendar
4
4
 
5
- VERSION = '2.12.2'
5
+ VERSION = '2.12.4'
6
6
 
7
7
  end
@@ -30,6 +30,39 @@ describe Icalendar::Values::Text do
30
30
  end
31
31
  end
32
32
 
33
+ describe 'unescape is the exact inverse of value_ical' do
34
+ bs = "\\"
35
+ {
36
+ 'a literal backslash before n (windows path)' => ["C:#{bs}#{bs}next", "C:#{bs}next"],
37
+ 'a UNC path with several backslashes' => ["#{bs * 4}srv#{bs * 2}sh", "#{bs * 2}srv#{bs}sh"],
38
+ 'an escaped backslash alone' => ["a#{bs}#{bs}b", "a#{bs}b"],
39
+ 'an escaped comma' => ["a#{bs},b", 'a,b'],
40
+ 'an escaped semicolon' => ["a#{bs};b", 'a;b'],
41
+ 'a lowercase newline escape' => ["a#{bs}nb", "a\nb"],
42
+ 'plain text without backslashes' => ['plain summary text', 'plain summary text'],
43
+ }.each do |desc, (onwire, content)|
44
+ context "given #{desc}" do
45
+ subject { described_class.new onwire.dup }
46
+
47
+ it 'decodes to the original content' do
48
+ expect(subject.value).to eq content
49
+ end
50
+
51
+ it 'round-trips back to the on-wire form' do
52
+ expect(subject.value_ical).to eq onwire
53
+ end
54
+ end
55
+ end
56
+
57
+ it 'decodes a capital-N newline escape (RFC 5545 3.3.11)' do
58
+ expect(described_class.new("a#{bs}Nb").value).to eq "a\nb"
59
+ end
60
+
61
+ it 'leaves a backslash before a non-escape char untouched' do
62
+ expect(described_class.new("a#{bs}:b").value).to eq "a#{bs}:b"
63
+ end
64
+ end
65
+
33
66
  describe 'escapes parameter text properly' do
34
67
  subject { described_class.new escaped, {'param' => param_value} }
35
68
  context 'single value, no special characters' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: icalendar
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.12.2
4
+ version: 2.12.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Ahearn
@@ -83,16 +83,16 @@ dependencies:
83
83
  name: bundler
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
- - - "~>"
86
+ - - ">="
87
87
  - !ruby/object:Gem::Version
88
- version: '2.0'
88
+ version: '0'
89
89
  type: :development
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - "~>"
93
+ - - ">="
94
94
  - !ruby/object:Gem::Version
95
- version: '2.0'
95
+ version: '0'
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: activesupport
98
98
  requirement: !ruby/object:Gem::Requirement
@@ -209,6 +209,7 @@ files:
209
209
  - LICENSE
210
210
  - README.md
211
211
  - Rakefile
212
+ - benchmarks/memory_per_event_ical.rb
212
213
  - icalendar.gemspec
213
214
  - lib/icalendar.rb
214
215
  - lib/icalendar/alarm.rb
@@ -319,7 +320,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
319
320
  - !ruby/object:Gem::Version
320
321
  version: '0'
321
322
  requirements: []
322
- rubygems_version: 3.6.9
323
+ rubygems_version: 4.0.6
323
324
  specification_version: 4
324
325
  summary: A ruby implementation of the iCalendar specification (RFC-5545).
325
326
  test_files: