icalendar 2.5.3 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +0 -4
- data/History.txt +6 -0
- data/icalendar.gemspec +1 -1
- data/lib/icalendar.rb +1 -0
- data/lib/icalendar/has_components.rb +2 -2
- data/lib/icalendar/has_properties.rb +4 -4
- data/lib/icalendar/marshable.rb +34 -0
- data/lib/icalendar/timezone.rb +33 -18
- data/lib/icalendar/values/utc_offset.rb +1 -2
- data/lib/icalendar/version.rb +1 -1
- data/spec/calendar_spec.rb +6 -0
- data/spec/event_spec.rb +7 -0
- data/spec/timezone_spec.rb +48 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 165b0d4192335c7fb36354195666ea4d386d63029190d7c1248ab3d4fe1554ec
|
4
|
+
data.tar.gz: 3781a361f70f099aff7e891e7f3bc26eaaac059c615a40d377634d41d4905d3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 682932f688906567e95fc58b4952b05664e9eeece75708bd83c1ebc42362e927a252f77a8124bf028500359e23aa1d7b071b9af5ccf1032d92074c29cecd6f3f
|
7
|
+
data.tar.gz: 38a5153c80c3b170c2d973104f565d3e0ff5a3c74b8573870331cc842e23e2918de712b6a0046cecb758a1aa3450c72f4aedaa2f22bb302a7343332f2c0a017a
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/History.txt
CHANGED
@@ -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
|
data/icalendar.gemspec
CHANGED
@@ -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.
|
27
|
+
s.required_ruby_version = '>= 2.4.0'
|
28
28
|
|
29
29
|
s.add_dependency 'ice_cube', '~> 0.16'
|
30
30
|
|
data/lib/icalendar.rb
CHANGED
@@ -10,7 +10,7 @@ module Icalendar
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def initialize(*args)
|
13
|
-
@custom_components = Hash.new
|
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
|
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
|
data/lib/icalendar/timezone.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
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,
|
data/lib/icalendar/version.rb
CHANGED
data/spec/calendar_spec.rb
CHANGED
data/spec/event_spec.rb
CHANGED
@@ -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' }
|
data/spec/timezone_spec.rb
CHANGED
@@ -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.
|
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-
|
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.
|
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.
|
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).
|