icalendar 1.5.4 → 2.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -1
- data/.rspec +2 -0
- data/.travis.yml +1 -2
- data/History.txt +2 -7
- data/README.md +82 -107
- data/Rakefile +6 -7
- data/icalendar.gemspec +10 -9
- data/lib/icalendar.rb +17 -33
- data/lib/icalendar/alarm.rb +35 -0
- data/lib/icalendar/calendar.rb +17 -100
- data/lib/icalendar/component.rb +41 -403
- data/lib/icalendar/event.rb +51 -0
- data/lib/icalendar/freebusy.rb +27 -0
- data/lib/icalendar/has_components.rb +83 -0
- data/lib/icalendar/has_properties.rb +156 -0
- data/lib/icalendar/journal.rb +39 -0
- data/lib/icalendar/parser.rb +75 -403
- data/lib/icalendar/timezone.rb +53 -0
- data/lib/icalendar/todo.rb +52 -0
- data/lib/icalendar/tzinfo.rb +30 -30
- data/lib/icalendar/value.rb +80 -0
- data/lib/icalendar/values/array.rb +43 -0
- data/lib/icalendar/values/binary.rb +31 -0
- data/lib/icalendar/values/boolean.rb +17 -0
- data/lib/icalendar/values/cal_address.rb +8 -0
- data/lib/icalendar/values/date.rb +26 -0
- data/lib/icalendar/values/date_time.rb +34 -0
- data/lib/icalendar/values/duration.rb +48 -0
- data/lib/icalendar/values/float.rb +17 -0
- data/lib/icalendar/values/integer.rb +17 -0
- data/lib/icalendar/values/period.rb +46 -0
- data/lib/icalendar/values/recur.rb +63 -0
- data/lib/icalendar/values/text.rb +26 -0
- data/lib/icalendar/values/time.rb +34 -0
- data/lib/icalendar/values/time_with_zone.rb +31 -0
- data/lib/icalendar/values/uri.rb +19 -0
- data/lib/icalendar/values/utc_offset.rb +39 -0
- data/lib/icalendar/version.rb +5 -0
- data/spec/alarm_spec.rb +108 -0
- data/spec/calendar_spec.rb +167 -0
- data/spec/event_spec.rb +108 -0
- data/{test/fixtures/folding.ics → spec/fixtures/nondefault_values.ics} +2 -2
- data/{test → spec}/fixtures/single_event.ics +11 -14
- data/spec/fixtures/timezone.ics +35 -0
- data/spec/freebusy_spec.rb +7 -0
- data/spec/journal_spec.rb +7 -0
- data/spec/parser_spec.rb +26 -0
- data/spec/roundtrip_spec.rb +40 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/timezone_spec.rb +31 -0
- data/spec/todo_spec.rb +24 -0
- data/spec/tzinfo_spec.rb +85 -0
- data/spec/values/date_time_spec.rb +80 -0
- data/spec/values/duration_spec.rb +67 -0
- data/spec/values/period_spec.rb +47 -0
- data/spec/values/recur_spec.rb +47 -0
- data/spec/values/text_spec.rb +72 -0
- data/spec/values/utc_offset_spec.rb +41 -0
- metadata +129 -88
- data/GPL +0 -340
- data/examples/create_cal.rb +0 -45
- data/examples/parse_cal.rb +0 -20
- data/examples/single_event.ics +0 -18
- data/lib/hash_attrs.rb +0 -34
- data/lib/icalendar/base.rb +0 -47
- data/lib/icalendar/component/alarm.rb +0 -47
- data/lib/icalendar/component/event.rb +0 -131
- data/lib/icalendar/component/freebusy.rb +0 -38
- data/lib/icalendar/component/journal.rb +0 -60
- data/lib/icalendar/component/timezone.rb +0 -91
- data/lib/icalendar/component/todo.rb +0 -64
- data/lib/icalendar/conversions.rb +0 -107
- data/lib/icalendar/helpers.rb +0 -109
- data/lib/icalendar/parameter.rb +0 -33
- data/lib/icalendar/rrule.rb +0 -133
- data/lib/meta.rb +0 -32
- data/script/console +0 -10
- data/script/recur1.ics +0 -38
- data/script/tryit.rb +0 -13
- data/test/component/test_event.rb +0 -253
- data/test/component/test_timezone.rb +0 -74
- data/test/component/test_todo.rb +0 -31
- data/test/fixtures/life.ics +0 -46
- data/test/fixtures/nonstandard.ics +0 -25
- data/test/fixtures/simplecal.ics +0 -119
- data/test/interactive.rb +0 -17
- data/test/read_write.rb +0 -23
- data/test/test_calendar.rb +0 -167
- data/test/test_component.rb +0 -102
- data/test/test_conversions.rb +0 -104
- data/test/test_helper.rb +0 -7
- data/test/test_parameter.rb +0 -91
- data/test/test_parser.rb +0 -100
- data/test/test_tzinfo.rb +0 -83
- data/website/index.html +0 -70
- data/website/index.txt +0 -38
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -159
- data/website/template.html.erb +0 -50
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start do
|
3
|
+
add_filter '/spec/'
|
4
|
+
end
|
5
|
+
|
6
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
7
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
8
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
9
|
+
# loaded once.
|
10
|
+
#
|
11
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
12
|
+
require 'timecop'
|
13
|
+
require 'icalendar'
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
17
|
+
config.run_all_when_everything_filtered = true
|
18
|
+
config.filter_run :focus
|
19
|
+
|
20
|
+
# Run specs in random order to surface order dependencies. If you find an
|
21
|
+
# order dependency and want to debug it, you can fix the order by providing
|
22
|
+
# the seed, which is printed after each run.
|
23
|
+
# --seed 1234
|
24
|
+
config.order = 'random'
|
25
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Icalendar::Timezone do
|
4
|
+
|
5
|
+
describe "valid?" do
|
6
|
+
subject { described_class.new.tap { |t| t.tzid = 'Eastern' } }
|
7
|
+
|
8
|
+
context 'with both standard and daylight components' do
|
9
|
+
before(:each) do
|
10
|
+
subject.daylight { |d| d.should_receive(:valid?).and_return true }
|
11
|
+
subject.standard { |s| s.should_receive(:valid?).and_return true }
|
12
|
+
end
|
13
|
+
|
14
|
+
it { should be_valid }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with only standard' do
|
18
|
+
before(:each) { subject.standard { |s| s.stub(:valid?).and_return true } }
|
19
|
+
it { should be_valid }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with only daylight' do
|
23
|
+
before(:each) { subject.daylight { |d| d.stub(:valid?).and_return true } }
|
24
|
+
it { should be_valid }
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with neither standard or daylight' do
|
28
|
+
it { should_not be_valid }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/spec/todo_spec.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Icalendar::Todo do
|
4
|
+
|
5
|
+
describe '#dtstart' do
|
6
|
+
it 'is not normally required' do
|
7
|
+
subject.dtstart = nil
|
8
|
+
subject.should be_valid
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with duration set' do
|
12
|
+
before(:each) { subject.duration = 'PT15M' }
|
13
|
+
|
14
|
+
it 'is invalid if not set' do
|
15
|
+
subject.should_not be_valid
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'is valid when set' do
|
19
|
+
subject.dtstart = Date.today
|
20
|
+
subject.should be_valid
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/spec/tzinfo_spec.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../lib/icalendar/tzinfo'
|
3
|
+
|
4
|
+
describe 'TZInfo::Timezone' do
|
5
|
+
|
6
|
+
let(:tz) { TZInfo::Timezone.get 'Europe/Copenhagen' }
|
7
|
+
let(:date) { DateTime.new 1970 }
|
8
|
+
subject { tz.ical_timezone date }
|
9
|
+
|
10
|
+
describe 'daylight offset' do
|
11
|
+
specify { expect(subject.daylights.first.tzoffsetto.value_ical).to eq "+0200" }
|
12
|
+
specify { expect(subject.daylights.first.tzoffsetfrom.value_ical).to eq "+0100" }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'standard offset' do
|
16
|
+
specify { expect(subject.standards.first.tzoffsetto.value_ical).to eq "+0100" }
|
17
|
+
specify { expect(subject.standards.first.tzoffsetfrom.value_ical).to eq "+0200" }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'no end transition' do
|
21
|
+
let(:tz) { TZInfo::Timezone.get 'America/Cayman' }
|
22
|
+
let(:date) { DateTime.now }
|
23
|
+
|
24
|
+
it 'only creates a standard component' do
|
25
|
+
expect(subject.to_ical).to eq <<-EXPECTED.gsub "\n", "\r\n"
|
26
|
+
BEGIN:VTIMEZONE
|
27
|
+
TZID:America/Cayman
|
28
|
+
BEGIN:STANDARD
|
29
|
+
DTSTART:19120201T000711
|
30
|
+
TZOFFSETFROM:-0652
|
31
|
+
TZOFFSETTO:-0500
|
32
|
+
TZNAME:EST
|
33
|
+
END:STANDARD
|
34
|
+
END:VTIMEZONE
|
35
|
+
EXPECTED
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'no transition' do
|
40
|
+
let(:tz) { TZInfo::Timezone.get 'UTC' }
|
41
|
+
let(:date) { DateTime.now }
|
42
|
+
|
43
|
+
it 'creates a standard component with equal offsets' do
|
44
|
+
expect(subject.to_ical).to eq <<-EXPECTED.gsub "\n", "\r\n"
|
45
|
+
BEGIN:VTIMEZONE
|
46
|
+
TZID:UTC
|
47
|
+
BEGIN:STANDARD
|
48
|
+
DTSTART:19700101T000000
|
49
|
+
TZOFFSETFROM:+0000
|
50
|
+
TZOFFSETTO:+0000
|
51
|
+
TZNAME:UTC
|
52
|
+
END:STANDARD
|
53
|
+
END:VTIMEZONE
|
54
|
+
EXPECTED
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'dst transition' do
|
59
|
+
subject { TZInfo::Timezone.get 'America/Los_Angeles' }
|
60
|
+
let(:now) { subject.now }
|
61
|
+
# freeze in DST transition in America/Los_Angeles
|
62
|
+
before(:each) { Timecop.freeze DateTime.new(2013, 11, 03, 1, 30, 0, '-08:00') }
|
63
|
+
after(:each) { Timecop.return }
|
64
|
+
|
65
|
+
specify { expect { subject.ical_timezone now, nil }.to raise_error TZInfo::AmbiguousTime }
|
66
|
+
specify { expect { subject.ical_timezone now, true }.not_to raise_error }
|
67
|
+
specify { expect { subject.ical_timezone now, false }.not_to raise_error }
|
68
|
+
|
69
|
+
context 'TZInfo::Timezone.default_dst = nil' do
|
70
|
+
before(:each) { TZInfo::Timezone.default_dst = nil }
|
71
|
+
specify { expect { subject.ical_timezone now }.to raise_error TZInfo::AmbiguousTime }
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'TZInfo::Timezone.default_dst = true' do
|
75
|
+
before(:each) { TZInfo::Timezone.default_dst = true }
|
76
|
+
specify { expect { subject.ical_timezone now }.not_to raise_error }
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'TZInfo::Timezone.default_dst = false' do
|
80
|
+
before(:each) { TZInfo::Timezone.default_dst = false }
|
81
|
+
specify { expect { subject.ical_timezone now }.not_to raise_error }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Icalendar::Values::DateTime do
|
4
|
+
|
5
|
+
subject { described_class.new value, params }
|
6
|
+
let(:value) { '20140209T194355Z' }
|
7
|
+
let(:params) { {} }
|
8
|
+
|
9
|
+
# not sure how to automatically test both sides of this.
|
10
|
+
# For now - relying on commenting out dev dependency in gemspec
|
11
|
+
# AND uninstalling gem manually
|
12
|
+
if defined? ActiveSupport
|
13
|
+
|
14
|
+
context 'with ActiveSupport' do
|
15
|
+
it 'parses a string to a ActiveSupport::TimeWithZone instance' do
|
16
|
+
expect(subject.value).to be_a_kind_of ActiveSupport::TimeWithZone
|
17
|
+
expect(subject.value_ical).to eq value
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'local time' do
|
21
|
+
let(:value) { '20140209T160652' }
|
22
|
+
let(:params) { {'tzid' => 'America/Denver'} }
|
23
|
+
|
24
|
+
it 'parses the value as local time' do
|
25
|
+
expect(subject.value.hour).to eq 16
|
26
|
+
expect(subject.value.utc_offset).to eq -25200
|
27
|
+
expect(subject.value.utc.hour).to eq 23
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
else
|
33
|
+
|
34
|
+
context 'without ActiveSupport' do
|
35
|
+
it 'parses a string to a DateTime instance' do
|
36
|
+
expect(subject.value).to be_a_kind_of ::DateTime
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'local time' do
|
40
|
+
let(:value) { '20140209T160652' }
|
41
|
+
let(:params) { {'tzid' => 'America/Denver'} }
|
42
|
+
|
43
|
+
it 'parses the value as local time' do
|
44
|
+
expect(subject.value.hour).to eq 16
|
45
|
+
# TODO better offset support without ActiveSupport
|
46
|
+
#expect(subject.offset).to eq Rational(-7, 24)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
context 'common tests' do
|
55
|
+
it 'does not add any tzid parameter to output' do
|
56
|
+
expect(subject.to_ical described_class).to eq ":#{value}"
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'local time' do
|
60
|
+
let(:value) { '20140209T160652' }
|
61
|
+
let(:params) { {'tzid' => 'America/Denver'} }
|
62
|
+
|
63
|
+
it 'keeps value and tzid as localtime on output' do
|
64
|
+
expect(subject.to_ical described_class).to eq ";TZID=America/Denver:#{value}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'floating local time' do
|
69
|
+
let(:value) { '20140209T162845' }
|
70
|
+
|
71
|
+
it 'keeps the value as a DateTime' do
|
72
|
+
expect(subject.value).to be_a_kind_of ::DateTime
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'does not append a Z on output' do
|
76
|
+
expect(subject.to_ical described_class).to eq ":#{value}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Icalendar::Values::Duration do
|
4
|
+
|
5
|
+
subject { described_class.new value }
|
6
|
+
|
7
|
+
describe '#past?' do
|
8
|
+
context 'positive explicit' do
|
9
|
+
let(:value) { '+P15M' }
|
10
|
+
specify { expect(subject.past?).to be_false }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'positive implicit' do
|
14
|
+
let(:value) { 'P15M' }
|
15
|
+
specify { expect(subject.past?).to be_false }
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'negative' do
|
19
|
+
let(:value) { '-P15M' }
|
20
|
+
specify { expect(subject.past?).to be_true }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#days' do
|
25
|
+
context 'days given' do
|
26
|
+
let(:value) { 'P5DT3H' }
|
27
|
+
specify { expect(subject.days).to eq 5 }
|
28
|
+
end
|
29
|
+
context 'no days given' do
|
30
|
+
let(:value) { 'P5W' }
|
31
|
+
specify { expect(subject.days).to eq 0 }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#weeks' do
|
36
|
+
let(:value) { 'P3W' }
|
37
|
+
specify { expect(subject.weeks).to eq 3 }
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#hours' do
|
41
|
+
let(:value) { 'PT6H' }
|
42
|
+
specify { expect(subject.hours).to eq 6 }
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#minutes' do
|
46
|
+
let(:value) { 'P2DT5H45M12S' }
|
47
|
+
specify { expect(subject.minutes).to eq 45 }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#seconds' do
|
51
|
+
let(:value) { '-PT5M30S' }
|
52
|
+
specify { expect(subject.seconds).to eq 30 }
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#value_ical' do
|
56
|
+
let(:value) { 'P2DT4H' }
|
57
|
+
specify { expect(subject.value_ical).to eq value }
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#days=' do
|
61
|
+
let(:value) { 'P3D' }
|
62
|
+
it 'can set the number of days' do
|
63
|
+
subject.days = 4
|
64
|
+
expect(subject.value_ical).to eq 'P4D'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
describe Icalendar::Values::Period do
|
5
|
+
|
6
|
+
subject { described_class.new value }
|
7
|
+
|
8
|
+
context 'date-time/date-time' do
|
9
|
+
let(:value) { '19830507T000600Z/20140128T201400Z' }
|
10
|
+
|
11
|
+
describe '#value_ical' do
|
12
|
+
specify { expect(subject.value_ical).to eq value }
|
13
|
+
end
|
14
|
+
describe '#period_start' do
|
15
|
+
specify { expect(subject.period_start).to eq DateTime.new(1983, 5, 7, 0, 6) }
|
16
|
+
end
|
17
|
+
describe '#duration' do
|
18
|
+
specify { expect(subject.duration).to be_nil }
|
19
|
+
end
|
20
|
+
describe '#explicit_end' do
|
21
|
+
specify { expect(subject.explicit_end).to eq DateTime.new(2014, 01, 28, 20, 14) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'date-time/duration' do
|
26
|
+
let(:value) { '19830507T000600Z/P1604W' }
|
27
|
+
let(:expected_duration) { OpenStruct.new past: false, weeks: 1604, days: 0, hours: 0, minutes: 0, seconds: 0 }
|
28
|
+
|
29
|
+
describe '#value_ical' do
|
30
|
+
specify { expect(subject.value_ical).to eq value }
|
31
|
+
|
32
|
+
it 'allows updating duration' do
|
33
|
+
subject.duration = 'PT30M'
|
34
|
+
expect(subject.value_ical).to eq '19830507T000600Z/PT30M'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
describe '#period_start' do
|
38
|
+
specify { expect(subject.period_start).to eq DateTime.new(1983, 5, 7, 0, 6) }
|
39
|
+
end
|
40
|
+
describe '#duration' do
|
41
|
+
specify { expect(subject.duration).to eq expected_duration }
|
42
|
+
end
|
43
|
+
describe '#explicit_end' do
|
44
|
+
specify { expect(subject.explicit_end).to eq nil }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Icalendar::Values::Recur do
|
4
|
+
|
5
|
+
subject { described_class.new value }
|
6
|
+
let(:value) { 'FREQ=DAILY' }
|
7
|
+
|
8
|
+
describe 'parsing' do
|
9
|
+
context 'multiple bydays' do
|
10
|
+
let(:value) { 'FREQ=WEEKLY;COUNT=4;BYDAY=MO,WE,FR' }
|
11
|
+
|
12
|
+
specify { expect(subject.frequency).to eq 'WEEKLY' }
|
13
|
+
specify { expect(subject.count).to eq 4 }
|
14
|
+
specify { expect(subject.by_day).to eq %w(MO WE FR) }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'single byday' do
|
18
|
+
let(:value) { 'FREQ=YEARLY;BYDAY=2SU;BYMONTH=3' }
|
19
|
+
|
20
|
+
specify { expect(subject.frequency).to eq 'YEARLY' }
|
21
|
+
specify { expect(subject.by_day).to eq %w(2SU) }
|
22
|
+
specify { expect(subject.by_month).to eq [3] }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#valid?' do
|
27
|
+
it 'requires frequency' do
|
28
|
+
expect(subject.valid?).to be_true
|
29
|
+
subject.frequency = nil
|
30
|
+
expect(subject.valid?).to be_false
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'cannot have both until and count' do
|
34
|
+
subject.until = '20140201'
|
35
|
+
subject.count = 4
|
36
|
+
expect(subject.valid?).to be_false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#value_ical' do
|
41
|
+
let(:value) { 'FREQ=DAILY;BYYEARDAY=1,34,56,240;BYDAY=SU,SA' }
|
42
|
+
|
43
|
+
it 'outputs in spec order' do
|
44
|
+
expect(subject.value_ical).to eq 'FREQ=DAILY;BYDAY=SU,SA;BYYEARDAY=1,34,56,240'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Icalendar::Values::Text do
|
4
|
+
|
5
|
+
subject { described_class.new value }
|
6
|
+
let(:unescaped) { "This \\ that, semi; colons\r\nAnother line: \"why not?\"" }
|
7
|
+
let(:escaped) { 'This \\\\ that\, semi\; colons\nAnother line: "why not?"' }
|
8
|
+
|
9
|
+
describe '#value_ical' do
|
10
|
+
let(:value) { unescaped }
|
11
|
+
it 'escapes \ , ; NL' do
|
12
|
+
expect(subject.value_ical).to eq escaped
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'unescapes in initializer' do
|
17
|
+
context 'given escaped version' do
|
18
|
+
let(:unescaped_no_cr) { unescaped.gsub "\r", '' }
|
19
|
+
let(:value) { escaped }
|
20
|
+
it 'removes escaping' do
|
21
|
+
expect(subject.value).to eq unescaped_no_cr
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'given unescaped version' do
|
26
|
+
let(:value) { unescaped }
|
27
|
+
it 'does not try to double unescape' do
|
28
|
+
expect(subject.value).to eq unescaped
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'escapes parameter text properly' do
|
34
|
+
subject { described_class.new escaped, {'param' => param_value} }
|
35
|
+
context 'single value, no special characters' do
|
36
|
+
let(:param_value) { 'HelloWorld' }
|
37
|
+
it 'does not wrap param in double quotes' do
|
38
|
+
expect(subject.params_ical).to eq %(;PARAM=HelloWorld)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
context 'single value, special characters' do
|
42
|
+
let(:param_value) { 'Hello:World' }
|
43
|
+
it 'wraps param value in double quotes' do
|
44
|
+
expect(subject.params_ical).to eq %(;PARAM="Hello:World")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
context 'single value, double quotes' do
|
48
|
+
let(:param_value) { 'Hello "World"' }
|
49
|
+
it 'replaces double quotes with single' do
|
50
|
+
expect(subject.params_ical).to eq %(;PARAM=Hello 'World')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
context 'multiple values, no special characters' do
|
54
|
+
let(:param_value) { ['HelloWorld', 'GoodbyeMoon'] }
|
55
|
+
it 'joins with comma' do
|
56
|
+
expect(subject.params_ical).to eq %(;PARAM=HelloWorld,GoodbyeMoon)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
context 'multiple values, with special characters' do
|
60
|
+
let(:param_value) { ['Hello, World', 'GoodbyeMoon'] }
|
61
|
+
it 'quotes values with special characters, joins with comma' do
|
62
|
+
expect(subject.params_ical).to eq %(;PARAM="Hello, World",GoodbyeMoon)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
context 'multiple values, double quotes' do
|
66
|
+
let(:param_value) { ['Hello, "World"', 'GoodbyeMoon'] }
|
67
|
+
it 'replaces double quotes with single' do
|
68
|
+
expect(subject.params_ical).to eq %(;PARAM="Hello, 'World'",GoodbyeMoon)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|