icalendar 2.5.3 → 2.6.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: 5cc6bb6eba99ce8e25232bb417cb9f3c5e9438b20a56a4a136e9b0d2f9a71b7c
4
- data.tar.gz: f9022e04c0aad637791e0c964f6c27eef986f610bc2417c5f70b85ec65275445
3
+ metadata.gz: 165b0d4192335c7fb36354195666ea4d386d63029190d7c1248ab3d4fe1554ec
4
+ data.tar.gz: 3781a361f70f099aff7e891e7f3bc26eaaac059c615a40d377634d41d4905d3c
5
5
  SHA512:
6
- metadata.gz: 2bd684301596f90024af2a690f7cbc20bdba2d02a902105fddc298a4108ac23825d444c2658dace796146cc0581c88ef2c6e62e229d4fa89ff2e89d8ac41eadb
7
- data.tar.gz: e62e5f8f4fe3983d19cf213c505fe8f9f002cf7e0b1054a958af4874eddaf376b80660a3e3d1b6cac50cab96a0535169738adf443f5fcc982c318750f5f16200
6
+ metadata.gz: 682932f688906567e95fc58b4952b05664e9eeece75708bd83c1ebc42362e927a252f77a8124bf028500359e23aa1d7b071b9af5ccf1032d92074c29cecd6f3f
7
+ data.tar.gz: 38a5153c80c3b170c2d973104f565d3e0ff5a3c74b8573870331cc842e23e2918de712b6a0046cecb758a1aa3450c72f4aedaa2f22bb302a7343332f2c0a017a
data/.gitignore CHANGED
@@ -6,3 +6,4 @@ pkg/
6
6
  .bundle
7
7
  coverage/
8
8
  tags
9
+ .idea
@@ -6,15 +6,11 @@ rvm:
6
6
  - 2.6
7
7
  - 2.5
8
8
  - 2.4
9
- - 2.3
10
- - 2.2
11
9
  - jruby-19mode
12
- - rbx-3
13
10
  - ruby-head
14
11
  - jruby-head
15
12
  matrix:
16
13
  allow_failures:
17
- - rvm: 2.2
18
14
  - rvm: ruby-head
19
15
  - rvm: jruby-head
20
16
  script: bundle exec rake spec
@@ -1,3 +1,9 @@
1
+ === 2.6.0 2019-11-26
2
+ * Improve performance for calculating timezone offsets - Justin Howard
3
+ * Make it possible to de/serialize with Marshal - Pawel Niewiadomski
4
+ * Avoid FrozenError when running with frozen_string_literal
5
+ * Update minimum Ruby version to supported versions
6
+
1
7
  === 2.5.3 2019-03-04
2
8
  * Improve parsing performance - nehresma
3
9
  * Support tzinfo 2.0 - Misty De Meo
@@ -24,7 +24,7 @@ ActiveSupport is required for TimeWithZone support, but not required for general
24
24
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename f }
25
25
  s.require_paths = ['lib']
26
26
 
27
- s.required_ruby_version = '>= 2.2.0'
27
+ s.required_ruby_version = '>= 2.4.0'
28
28
 
29
29
  s.add_dependency 'ice_cube', '~> 0.16'
30
30
 
@@ -22,6 +22,7 @@ end
22
22
 
23
23
  require 'icalendar/has_properties'
24
24
  require 'icalendar/has_components'
25
+ require 'icalendar/marshable'
25
26
  require 'icalendar/component'
26
27
  require 'icalendar/value'
27
28
  require 'icalendar/alarm'
@@ -10,7 +10,7 @@ module Icalendar
10
10
  end
11
11
 
12
12
  def initialize(*args)
13
- @custom_components = Hash.new { |h, k| h[k] = [] }
13
+ @custom_components = Hash.new
14
14
  super
15
15
  end
16
16
 
@@ -26,7 +26,7 @@ module Icalendar
26
26
  if method_name =~ /^add_(x_\w+)$/
27
27
  component_name = $1
28
28
  custom = args.first || Component.new(component_name, component_name.upcase)
29
- custom_components[component_name] << custom
29
+ (custom_components[component_name] ||= []) << custom
30
30
  yield custom if block_given?
31
31
  custom
32
32
  else
@@ -10,7 +10,7 @@ module Icalendar
10
10
  end
11
11
 
12
12
  def initialize(*args)
13
- @custom_properties = Hash.new { |h, k| h[k] = [] }
13
+ @custom_properties = Hash.new
14
14
  super
15
15
  end
16
16
 
@@ -39,7 +39,7 @@ module Icalendar
39
39
  end
40
40
 
41
41
  def custom_property(property_name)
42
- custom_properties[property_name.downcase]
42
+ custom_properties[property_name.downcase] || []
43
43
  end
44
44
 
45
45
  def append_custom_property(property_name, value)
@@ -49,9 +49,9 @@ module Icalendar
49
49
  elsif self.class.multiple_properties.include? property_name
50
50
  send "append_#{property_name}", value
51
51
  elsif value.is_a? Icalendar::Value
52
- custom_properties[property_name] << value
52
+ (custom_properties[property_name] ||= []) << value
53
53
  else
54
- custom_properties[property_name] << Icalendar::Values::Text.new(value)
54
+ (custom_properties[property_name] ||= []) << Icalendar::Values::Text.new(value)
55
55
  end
56
56
  end
57
57
 
@@ -0,0 +1,34 @@
1
+ module Icalendar
2
+ module Marshable
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ def marshal_dump
8
+ instance_variables
9
+ .reject { |ivar| self.class.transient_variables.include?(ivar) }
10
+ .each_with_object({}) do |ivar, serialized|
11
+
12
+ serialized[ivar] = instance_variable_get(ivar)
13
+ end
14
+ end
15
+
16
+ def marshal_load(serialized)
17
+ serialized.each do |ivar, value|
18
+ unless self.class.transient_variables.include?(ivar)
19
+ instance_variable_set(ivar, value)
20
+ end
21
+ end
22
+ end
23
+
24
+ module ClassMethods
25
+ def transient_variables
26
+ @transient_variables ||= [:@transient_variables]
27
+ end
28
+
29
+ def transient_variable(name)
30
+ transient_variables.push(name.to_sym)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -14,10 +14,40 @@ module Icalendar
14
14
  optional_property :comment
15
15
  optional_property :rdate, Icalendar::Values::DateTime
16
16
  optional_property :tzname
17
+
18
+ transient_variable :@cached_occurrences
19
+ transient_variable :@occurrences
17
20
  end
18
21
  end
22
+
23
+ def occurrences
24
+ @occurrences ||= IceCube::Schedule.new(dtstart.to_time) do |s|
25
+ rrule.each do |rule|
26
+ s.add_recurrence_rule IceCube::Rule.from_ical(rule.value_ical)
27
+ end
28
+ rdate.each do |date|
29
+ s.add_recurrence_time date.to_time
30
+ end
31
+ end.all_occurrences_enumerator
32
+ end
33
+
34
+ def previous_occurrence(from)
35
+ from = IceCube::TimeUtil.match_zone(from, dtstart.to_time)
36
+
37
+ @cached_occurrences ||= []
38
+ while @cached_occurrences.empty? || @cached_occurrences.last <= from
39
+ begin
40
+ @cached_occurrences << occurrences.next
41
+ rescue StopIteration
42
+ break
43
+ end
44
+ end
45
+
46
+ @cached_occurrences.reverse_each.find { |occurrence| occurrence < from }
47
+ end
19
48
  end
20
49
  class Daylight < Component
50
+ include Marshable
21
51
  include TzProperties
22
52
 
23
53
  def initialize
@@ -25,6 +55,7 @@ module Icalendar
25
55
  end
26
56
  end
27
57
  class Standard < Component
58
+ include Marshable
28
59
  include TzProperties
29
60
 
30
61
  def initialize
@@ -75,30 +106,14 @@ module Icalendar
75
106
 
76
107
  def standard_for(local)
77
108
  possible = standards.map do |std|
78
- schedule = IceCube::Schedule.new(std.dtstart.to_time) 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_time date.to_time
84
- end
85
- end
86
- [schedule.previous_occurrence(local.to_time), std]
109
+ [std.previous_occurrence(local.to_time), std]
87
110
  end
88
111
  possible.sort_by(&:first).last
89
112
  end
90
113
 
91
114
  def daylight_for(local)
92
115
  possible = daylights.map do |day|
93
- schedule = IceCube::Schedule.new(day.dtstart.to_time) 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_time date.to_time
99
- end
100
- end
101
- [schedule.previous_occurrence(local.to_time), day]
116
+ [day.previous_occurrence(local.to_time), day]
102
117
  end
103
118
  possible.sort_by(&:first).last
104
119
  end
@@ -37,8 +37,7 @@ module Icalendar
37
37
  end
38
38
 
39
39
  def parse_fields(value)
40
- value.gsub!(/\s+/, '')
41
- md = /\A(?<behind>[+-])(?<hours>\d{2})(?<minutes>\d{2})(?<seconds>\d{2})?\z/.match value
40
+ md = /\A(?<behind>[+-])(?<hours>\d{2})(?<minutes>\d{2})(?<seconds>\d{2})?\z/.match value.gsub(/\s+/, '')
42
41
  {
43
42
  behind: (md[:behind] == '-'),
44
43
  hours: md[:hours].to_i,
@@ -1,5 +1,5 @@
1
1
  module Icalendar
2
2
 
3
- VERSION = '2.5.3'
3
+ VERSION = '2.6.0'
4
4
 
5
5
  end
@@ -2,6 +2,12 @@ require 'spec_helper'
2
2
 
3
3
  describe Icalendar::Calendar do
4
4
 
5
+ context 'marshalling' do
6
+ it 'can be de/serialized' do
7
+ Marshal.load(Marshal.dump(subject))
8
+ end
9
+ end
10
+
5
11
  context 'values' do
6
12
  let(:property) { 'my-value' }
7
13
 
@@ -113,6 +113,13 @@ describe Icalendar::Event do
113
113
  end
114
114
  end
115
115
 
116
+ describe "#custom_property" do
117
+ it "returns a default for missing properties" do
118
+ expect(subject.x_doesnt_exist).to eq([])
119
+ expect(subject.custom_property "x_doesnt_exist").to eq([])
120
+ end
121
+ end
122
+
116
123
  describe '.parse' do
117
124
  let(:source) { File.read File.join(File.dirname(__FILE__), 'fixtures', fn) }
118
125
  let(:fn) { 'event.ics' }
@@ -28,4 +28,52 @@ describe Icalendar::Timezone do
28
28
  it { should_not be_valid }
29
29
  end
30
30
  end
31
+
32
+ context 'marshalling' do
33
+ context 'with standard/daylight components' do
34
+ before do
35
+ subject.standard do |standard|
36
+ standard.rrule = Icalendar::Values::Recur.new("FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10")
37
+ standard.dtstart = Icalendar::Values::DateTime.new("16010101T030000")
38
+ standard.tzoffsetfrom = Icalendar::Values::UtcOffset.new("+0200")
39
+ standard.tzoffsetto = Icalendar::Values::UtcOffset.new("+0100")
40
+ end
41
+
42
+ subject.daylight do |daylight|
43
+ daylight.rrule = Icalendar::Values::Recur.new("FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3")
44
+ daylight.dtstart = Icalendar::Values::DateTime.new("16010101T020000")
45
+ daylight.tzoffsetfrom = Icalendar::Values::UtcOffset.new("+0100")
46
+ daylight.tzoffsetto = Icalendar::Values::UtcOffset.new("+0200")
47
+ end
48
+ end
49
+
50
+ it 'can be de/serialized' do
51
+ first_standard = subject.standards.first
52
+ first_daylight = subject.daylights.first
53
+
54
+ expect(first_standard.valid?).to be_truthy
55
+ expect(first_daylight.valid?).to be_truthy
56
+
57
+ # calling previous_occurrence intializes @cached_occurrences with a time that's not handled by ruby marshaller
58
+ first_occurence_for = Time.new(1601, 10, 31)
59
+
60
+ standard_previous_occurrence = first_standard.previous_occurrence(first_occurence_for)
61
+ expect(standard_previous_occurrence).not_to be_nil
62
+
63
+ daylight_previous_occurrence = first_daylight.previous_occurrence(first_occurence_for)
64
+ expect(daylight_previous_occurrence).not_to be_nil
65
+
66
+ deserialized = nil
67
+
68
+ expect { deserialized = Marshal.load(Marshal.dump(subject)) }.not_to raise_exception
69
+
70
+ expect(deserialized.standards.first.previous_occurrence(first_occurence_for)).to eq(standard_previous_occurrence)
71
+ expect(deserialized.daylights.first.previous_occurrence(first_occurence_for)).to eq(daylight_previous_occurrence)
72
+ end
73
+ end
74
+
75
+ it 'can be de/serialized' do
76
+ expect { Marshal.load(Marshal.dump(subject)) }.not_to raise_exception
77
+ end
78
+ end
31
79
  end
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.5.3
4
+ version: 2.6.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: 2019-03-05 00:00:00.000000000 Z
11
+ date: 2019-11-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ice_cube
@@ -180,6 +180,7 @@ files:
180
180
  - lib/icalendar/has_properties.rb
181
181
  - lib/icalendar/journal.rb
182
182
  - lib/icalendar/logger.rb
183
+ - lib/icalendar/marshable.rb
183
184
  - lib/icalendar/parser.rb
184
185
  - lib/icalendar/timezone.rb
185
186
  - lib/icalendar/timezone_store.rb
@@ -253,14 +254,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
253
254
  requirements:
254
255
  - - ">="
255
256
  - !ruby/object:Gem::Version
256
- version: 2.2.0
257
+ version: 2.4.0
257
258
  required_rubygems_version: !ruby/object:Gem::Requirement
258
259
  requirements:
259
260
  - - ">="
260
261
  - !ruby/object:Gem::Version
261
262
  version: '0'
262
263
  requirements: []
263
- rubygems_version: 3.0.1
264
+ rubygems_version: 3.0.3
264
265
  signing_key:
265
266
  specification_version: 4
266
267
  summary: A ruby implementation of the iCalendar specification (RFC-5545).