vobject 0.1.0 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/macos.yml +38 -0
- data/.github/workflows/ubuntu.yml +56 -0
- data/.github/workflows/windows.yml +40 -0
- data/.hound.yml +3 -0
- data/.rubocop.tb.yml +650 -0
- data/.rubocop.yml +1077 -0
- data/Gemfile +1 -1
- data/LICENSE.txt +21 -17
- data/README.adoc +151 -0
- data/Rakefile +1 -1
- data/lib/c.rb +173 -0
- data/lib/error.rb +19 -0
- data/lib/vcalendar.rb +77 -0
- data/lib/vcard.rb +67 -0
- data/lib/vobject.rb +13 -170
- data/lib/vobject/component.rb +87 -36
- data/lib/vobject/parameter.rb +116 -0
- data/lib/vobject/parametervalue.rb +26 -0
- data/lib/vobject/property.rb +134 -55
- data/lib/vobject/propertyvalue.rb +46 -0
- data/lib/vobject/vcalendar/component.rb +106 -0
- data/lib/vobject/vcalendar/grammar.rb +595 -0
- data/lib/vobject/vcalendar/paramcheck.rb +259 -0
- data/lib/vobject/vcalendar/propertyparent.rb +98 -0
- data/lib/vobject/vcalendar/propertyvalue.rb +606 -0
- data/lib/vobject/vcalendar/typegrammars.rb +605 -0
- data/lib/vobject/vcard/v3_0/component.rb +40 -0
- data/lib/vobject/vcard/v3_0/grammar.rb +175 -0
- data/lib/vobject/vcard/v3_0/paramcheck.rb +110 -0
- data/lib/vobject/vcard/v3_0/parameter.rb +17 -0
- data/lib/vobject/vcard/v3_0/property.rb +18 -0
- data/lib/vobject/vcard/v3_0/propertyvalue.rb +401 -0
- data/lib/vobject/vcard/v3_0/typegrammars.rb +425 -0
- data/lib/vobject/vcard/v4_0/component.rb +40 -0
- data/lib/vobject/vcard/v4_0/grammar.rb +224 -0
- data/lib/vobject/vcard/v4_0/paramcheck.rb +269 -0
- data/lib/vobject/vcard/v4_0/parameter.rb +18 -0
- data/lib/vobject/vcard/v4_0/property.rb +63 -0
- data/lib/vobject/vcard/v4_0/propertyvalue.rb +404 -0
- data/lib/vobject/vcard/v4_0/typegrammars.rb +539 -0
- data/lib/vobject/version.rb +1 -1
- data/vobject.gemspec +19 -16
- metadata +81 -26
- data/.travis.yml +0 -5
- data/README.md +0 -94
data/Gemfile
CHANGED
data/LICENSE.txt
CHANGED
@@ -1,21 +1,25 @@
|
|
1
|
-
|
1
|
+
BSD 2-Clause License
|
2
2
|
|
3
|
-
Copyright (c)
|
3
|
+
Copyright (c) 2018, Ribose
|
4
|
+
All rights reserved.
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
in the Software without restriction, including without limitation the rights
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
10
|
-
furnished to do so, subject to the following conditions:
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
11
8
|
|
12
|
-
|
13
|
-
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this
|
10
|
+
list of conditions and the following disclaimer.
|
14
11
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
14
|
+
and/or other materials provided with the distribution.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
20
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
21
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
22
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
23
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
24
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
25
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.adoc
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
== Ruby vObject parser
|
2
|
+
|
3
|
+
image:https://img.shields.io/gem/v/ruby-vobject.svg["Gem Version", link="https://rubygems.org/gems/vobject"]
|
4
|
+
image:https://github.com/riboseinc/ruby-vobject/workflows/macos/badge.svg["Build Status (macOS)", link="https://github.com/riboseinc/ruby-vobject/actions?workflow=macos"]
|
5
|
+
image:https://github.com/riboseinc/ruby-vobject/workflows/ubuntu/badge.svg["Build Status (ubuntu)", link="https://github.com/riboseinc/ruby-vobject/actions?workflow=ubuntu"]
|
6
|
+
image:https://github.com/riboseinc/ruby-vobject/workflows/windows/badge.svg["Build Status (Windows)", link="https://github.com/riboseinc/ruby-vobject/actions?workflow=windows"]
|
7
|
+
image:https://codeclimate.com/github/riboseinc/ruby-vobject/badges/gpa.svg["Code Climate", link="https://codeclimate.com/github/riboseinc/ruby-vobject"]
|
8
|
+
image:https://img.shields.io/github/issues-pr-raw/riboseinc/ruby-vobject.svg["Pull Requests", link="https://github.com/riboseinc/ruby-vobject/pulls"]
|
9
|
+
image:https://img.shields.io/github/commits-since/riboseinc/ruby-vobject/latest.svg["Commits since latest",link="https://github.com/riboseinc/ruby-vobject/releases"]
|
10
|
+
|
11
|
+
|
12
|
+
The main purpose of the gem is to parse vobject formatted text into a ruby
|
13
|
+
hash format. Currently there are two possiblities of vobjects, namely
|
14
|
+
iCalendar (https://tools.ietf.org/html/rfc5545) and vCard
|
15
|
+
(https://tools.ietf.org/html/rfc6350). This gem parses iCalendar objects
|
16
|
+
and vCard objects in versions 3.0 and 4.0, together with any subsequent
|
17
|
+
additions to those specifications in other RFCs (see below).
|
18
|
+
|
19
|
+
A secondary purpose is to create a normalised form of Vobjects (iCalendars
|
20
|
+
and vCards version 4.0), which can be used to compare two Vobjects with minor
|
21
|
+
formatting differences
|
22
|
+
|
23
|
+
NOTE: This gem used to be named `ruby-vobject` (from versions 0.1.0 to 1.0.1),
|
24
|
+
but for clarity purposes it is now simply called `vobject` (from version 1.0.2
|
25
|
+
onwards).
|
26
|
+
|
27
|
+
== Installation
|
28
|
+
|
29
|
+
Add this line to your application's Gemfile:
|
30
|
+
|
31
|
+
[source,ruby]
|
32
|
+
----
|
33
|
+
gem 'vobject'
|
34
|
+
----
|
35
|
+
|
36
|
+
And then execute:
|
37
|
+
|
38
|
+
[source,console]
|
39
|
+
----
|
40
|
+
$ bundle
|
41
|
+
----
|
42
|
+
|
43
|
+
Or install it yourself as:
|
44
|
+
|
45
|
+
[source,console]
|
46
|
+
----
|
47
|
+
$ gem install vobject
|
48
|
+
----
|
49
|
+
|
50
|
+
== Usage
|
51
|
+
|
52
|
+
[source,ruby]
|
53
|
+
----
|
54
|
+
require 'vcalendar'
|
55
|
+
require 'JSON'
|
56
|
+
require 'pp'
|
57
|
+
|
58
|
+
ics = File.read "spec/examples/vcalendar/timezones/America/Denver.ics"
|
59
|
+
# parse VCalendar into native object structure, with strict validation
|
60
|
+
# (raises exception on any deviation from the spec)
|
61
|
+
pp Vcalendar.parse(ics, true)
|
62
|
+
# parse VCalendar into native object structure, without strict validation
|
63
|
+
# (errors other than syntax errors are logged, but object still parses)
|
64
|
+
pp Vcalendar.parse(ics, false)
|
65
|
+
# list any errors
|
66
|
+
pp Vcalendar.parse(ics, false).get_errors
|
67
|
+
# convert VCalendar into Ruby hash
|
68
|
+
pp Vcalendar.parse(ics).to_hash
|
69
|
+
# convert VCalendar into JSON
|
70
|
+
pp JSON.parse(Vcalendar.parse(ics).to_json)
|
71
|
+
# convert VCalendar into VCalendar text
|
72
|
+
print Vcalendar.parse(ics).to_s
|
73
|
+
# convert VCalendar into normalised VCalendar text
|
74
|
+
print Vcalendar.parse(ics).to_norm
|
75
|
+
----
|
76
|
+
|
77
|
+
[source,ruby]
|
78
|
+
----
|
79
|
+
require 'vcard'
|
80
|
+
require 'JSON'
|
81
|
+
require 'pp'
|
82
|
+
|
83
|
+
vcf = File.read "spec/examples/vcard/vcard3.vcf"
|
84
|
+
# parse Vcard into native object structure (version 3), strict validation
|
85
|
+
pp Vcard.parse(vcf, '3.0', true)
|
86
|
+
# parse Vcard into Ruby hash
|
87
|
+
pp Vcard.parse(vcf, '3.0', true).to_hash
|
88
|
+
# parse Vcard into JSON
|
89
|
+
pp JSON.parse(Vcard.parse(vcf, '3.0', true).to_json)
|
90
|
+
# parse Vcard into VCard text
|
91
|
+
print Vcard.parse(vcf, '3.0', true).to_s
|
92
|
+
vcf = File.read "spec/examples/vcard/example61.vcf"
|
93
|
+
# parse Vcard into native object structure (version 4), lax validation
|
94
|
+
pp Vcard.parse(vcf, '4.0', false)
|
95
|
+
# list any errors
|
96
|
+
pp Vcard.parse(vcf, '4.0', false).get_errors
|
97
|
+
----
|
98
|
+
|
99
|
+
* Recognises all of VCard v3.0, Vcard v4.0, and Vcalendar v2.0
|
100
|
+
* Components, properties, and parameters are all objects.
|
101
|
+
** Each type of component is a distinct object.
|
102
|
+
* The parameters of a property are represented as an array of parameter objects.
|
103
|
+
* If a property has multiple values, given on separate lines, they are represented
|
104
|
+
as an array of value properties. Each value hash may have its own parameters.
|
105
|
+
* The values of properties are also typed objects.
|
106
|
+
* Objects can be parsed from text files.
|
107
|
+
* Objects can be populated from hashes of property value objects.
|
108
|
+
* Objects can be converted to Ruby hashes with native property value types (`.to_hash`), JSON objects with the same value types (`.to_json`), and round-tripped back to ICAL/VCARD string representations (`.to_s`).
|
109
|
+
* The normalised form of Vobjects (`.to_norm`) applies normalising conventions to the string representation; most notably presenting elements of a vCard in sorted order.
|
110
|
+
** Normalisation follows the draft RFC `draft-calconnect-vobject-and-normalization`.
|
111
|
+
* Validation can be strict or lax.
|
112
|
+
** If strict, an exception is raised on any syntax error, type mismatch, or other mismatch to the specification, such as mandatory elements.
|
113
|
+
** If lax, an exception is still raised on syntax errors, but other issues are listed in an error field of the resulting object.
|
114
|
+
* Normalisation follows the draft RFC `draft-calconnect-vobject-and-normalization`.
|
115
|
+
|
116
|
+
Running spec:
|
117
|
+
|
118
|
+
[source,console]
|
119
|
+
----
|
120
|
+
bundle exec rspec
|
121
|
+
----
|
122
|
+
|
123
|
+
== Implementation
|
124
|
+
|
125
|
+
This gem is implemented using ttps://github.com/luikore/rsec[Rsec], a very fast PEG grammar based on StringScanner.
|
126
|
+
|
127
|
+
== Coverage
|
128
|
+
|
129
|
+
This tool is intended as a reference implementation, and it is very strict in its conformance: it requires all rules for parameter coocurrence,
|
130
|
+
property typing, parameter typing, permitted properties within components, etc to be met by objects.
|
131
|
+
|
132
|
+
The tool only parses one object at a time, and does not parse Vobject streams.
|
133
|
+
|
134
|
+
This tool supports v2.0 iCal as specified in RFC 5545, and as updated in RFC 5546 (registry for values of METHOD and REQUEST-STATUS),
|
135
|
+
RFC 6868 (caret escapes for parameter values), RFC 7529 (non-Gregorian Calendars), RFC 7953 (VAVAILABILITY component), and
|
136
|
+
RFC 7986 (new properties).
|
137
|
+
|
138
|
+
This tool supports v3.0 vCard as specified in RFC 2425 and RFC 2426, and as updated in RFC 2739 (calendar attributes) and RFC 4770 (extensions for Instant Messaging). It allows for the VCARD 2.1 style specification of PREF parameters in RFC 2739.
|
139
|
+
|
140
|
+
This tool supports v4.0 vCard as specified in RFC 6350, and as updated in RFC 6868 (parameter encoding), RFC 6474 (place of birth, place and date of death), RFC 6715 (OMA CAB extensions), and RF 6473 (KIND:application).
|
141
|
+
|
142
|
+
|
143
|
+
== Contributing
|
144
|
+
|
145
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/riboseinc/vobject. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the http://contributor-covenant.org[Contributor Covenant] code of conduct.
|
146
|
+
|
147
|
+
|
148
|
+
== License
|
149
|
+
|
150
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
151
|
+
|
data/Rakefile
CHANGED
data/lib/c.rb
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
require "rsec"
|
2
|
+
require "set"
|
3
|
+
require "uri"
|
4
|
+
require_relative "vobject/vcalendar/propertyvalue"
|
5
|
+
|
6
|
+
module C
|
7
|
+
# definitions common to classes
|
8
|
+
SIGN = /[+-]/i.r
|
9
|
+
BOOLEAN = /TRUE/i.r.map { true } | /FALSE/i.r.map { false }
|
10
|
+
IANATOKEN = /[a-zA-Z\d\-]+/.r
|
11
|
+
vendorid_vcal = /[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]/.r
|
12
|
+
XNAME_VCAL = seq(/[xX]-/, vendorid_vcal, "-", IANATOKEN).map(&:join)
|
13
|
+
vendorid_vcard = /[a-zA-Z0-9]+/.r # different from iCal
|
14
|
+
XNAME_VCARD = seq(/[xX]-/, vendorid_vcard, "-", IANATOKEN).map(&:join)
|
15
|
+
TEXT = /([ \t\u0021\u0023-\u002b\u002d-\u0039\u003c-\u005b\u005d-\u007e\u0080-\u3ffff:"]|\\[nN;,\\])*/.r
|
16
|
+
TEXT3 = /([ \t\u0021\u0023-\u002b\u002d-\u0039\u003c-\u005b\u005d-\u007e\u0080-\u3ffff:"]|\\[nN;,\\]?)*/.r
|
17
|
+
TEXT4 = /([ \t\u0021\u0023-\u002b\u002d-\u005b\u005d-\u007e\u0080-\u3ffff:"]|\\[nN,\\])*/.r
|
18
|
+
COMPONENT4 = /([ \t\u0021\u0023-\u002b\u002d-\u003a\u003c-\u005b\u005d-\u007e\u0080-\u3ffff:"]|\\[nN,;\\])*/.r
|
19
|
+
DATE = seq(/[0-9]{4}/.r, /[0-9]{2}/.r, /[0-9]{2}/.r) do |yy, mm, dd|
|
20
|
+
Vobject::Vcalendar::PropertyValue::Date.new Time.utc(yy, mm, dd)
|
21
|
+
end
|
22
|
+
DATE_TIME = seq(/[0-9]{4}/.r, /[0-9]{2}/.r, /[0-9]{2}/.r << "T".r,
|
23
|
+
/[0-9]{2}/.r, /[0-9]{2}/.r, /[0-9]{2}/.r, /Z/i.r._?) do |yy, mm, dd, h, m, s, z|
|
24
|
+
if z.empty?
|
25
|
+
#Vobject::Vcalendar::PropertyValue::DateTimeLocal.new(time: Time.local(yy, mm, dd, h, m, s), zone: "")
|
26
|
+
Vobject::Vcalendar::PropertyValue::DateTimeLocal.new(year: yy, month: mm, day: dd, hour: h, min: m, sec: s, zone: "")
|
27
|
+
else
|
28
|
+
#Vobject::Vcalendar::PropertyValue::DateTimeUTC.new(time: Time.utc(yy, mm, dd, h, m, s), zone: "Z")
|
29
|
+
Vobject::Vcalendar::PropertyValue::DateTimeUTC.new(year: yy, month: mm, day: dd, hour: h, min: m, sec: s, zone: "Z")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
DATE_TIME_UTC = seq(/[0-9]{4}/.r, /[0-9]{2}/.r, /[0-9]{2}/.r << "T".r,
|
33
|
+
/[0-9]{2}/.r, /[0-9]{2}/.r, /[0-9]{2}/.r, /Z/i.r._?) do |yy, mm, dd, h, m, s, _z|
|
34
|
+
#Vobject::Vcalendar::PropertyValue::DateTimeUTC.new(time: Time.utc(yy, mm, dd, h, m, s), zone: "Z")
|
35
|
+
Vobject::Vcalendar::PropertyValue::DateTimeUTC.new(year: yy, month: mm, day: dd, hour: h, min: m, sec: s, zone: "Z")
|
36
|
+
end
|
37
|
+
TIME = seq(/[0-9]{2}/.r, /[0-9]{2}/.r, /[0-9]{2}/.r, /Z/i.r._?) do |h, m, s, z|
|
38
|
+
hash = { hour: h, min: m, sec: s }
|
39
|
+
hash[:utc] = not(z.empty?)
|
40
|
+
hash
|
41
|
+
end
|
42
|
+
ICALPROPNAMES = /BEGIN/i.r | /END/i.r | /CALSCALE/i.r | /METHOD/i.r | /VERSION/i.r |
|
43
|
+
/ATTACH/i.r | /IMAGE/i.r | /CATEGORIES/i.r | /RESOURCERS/i.r | /CLASS/i.r |
|
44
|
+
/COMMENT/i.r | /DESCRIPTION/i.r | /LOCATION/i.r | /SUMMARY/i.r | /TZID/i.r |
|
45
|
+
/TZNAME/i.r | /CONTACT/i.r | /RELATED-TO/i.r | /UID/i.r | /PRODID/i.r | /NAME/i.r |
|
46
|
+
/GEO/i.r | /PERCENT-COMPLETE/i.r | /PRIORITY/i.r | /STATUS/i.r | /COMPLETED/i.r |
|
47
|
+
/CREATEED/i.r | /DTSTAMP/i.r | /LAST-MODIFIED/i.r | /DTEND/i.r | /DTSTART/i.r |
|
48
|
+
/DUE/i.r | /RECURRENCE-ID/i.r | /EXDATE/i.r | /RDATE/i.r | /TRIGGER/i.r |
|
49
|
+
/FREEBUSY/i.r | /TRANSP/i.r | /TZOFFSETFROM/i.r | /TZOFFSETTO/i.r |
|
50
|
+
/TZURI/i.r | /URL/i.r | /SOURCE/i.r | /CONFERENCE/i.r | /ATTENDEE/i.r |
|
51
|
+
/ORGANIZER/i.r | /RRULE/i.r | /ACTION/i.r | /REPEAT/i.r | /SEQUENCE/i.r |
|
52
|
+
/REQUEST-STATUS/i.r | /BUSYTYPE/i.r | /REFRESH-INTERVAL/i.r | /COLOR/i.r
|
53
|
+
VCARD3PROPNAMES = /BEGIN/i.r | /END/i.r | /SOURCE/i.r | /NAME/i.r | /PROFILE/i.r |
|
54
|
+
/VERSION/i.r | /URL/i.r | /FN/i.r | /NICKNAME/i.r | /LABEL/i.r | /EMAIL/i.r |
|
55
|
+
/MAILER/i.r | /TITLE/i.r | /ROLE/i.r | /NOTE/i.r | /PRODID/.r | /SORT-STRING/i.r |
|
56
|
+
/UID/i.r | /CLASS/i.r | /ORG/i.r | /CATEGORIES/i.r | /N/i.r | /PHOTO/i.r |
|
57
|
+
/LOGO/i.r | /SOUND/i.r | /KEY/i.r | /BDAY/i.r | /REV/i.r | /ADR/i.r |
|
58
|
+
/TEL/i.r | /TZ/i.r | /GEO/i.r | /AGENT/i.r | /IMPP/i.r |
|
59
|
+
/FBURL/i.r | /CALADRURI/i.r | /CALURI/i.r | /CAPURI/i.r
|
60
|
+
VCARD4PROPNAMES = /SOURCE/i.r | /KIND/i.r | /FN/i.r | /NICKNAME/i.r | /NOTE/i.r | /N/i.r |
|
61
|
+
/PHOTO/i.r | /BDAY/i.r | /ANNIVERSARY/i.r | /GENDER/i.r | /ADR/i.r |
|
62
|
+
/TEL/i.r | /EMAIL/i.r | /IMPP/i.r | /LANG/i.r | /TZ/i.r |
|
63
|
+
/GEO/i.r | /TITLE/i.r | /ROLE/i.r | /LOGO/i.r | /ORG/i.r |
|
64
|
+
/MEMBER/i.r | /RELATED/i.r | /CATEGORIES/i.r | /PRODID/i.r |
|
65
|
+
/REV/i.r | /SOUND/i.r | /UID/i.r | /CLIENTPIDMAP/i.r | /URL/i.r |
|
66
|
+
/KEY/i.r | /FBURL/i.r | /CALADRURI/i.r | /CALURI/i.r | /XML/i.r |
|
67
|
+
/BIRTHPLACE/i.r | /DEATHPLACE/i.r | /DEATHDATE/i.r | /EXPERTISE/i.r |
|
68
|
+
/HOBBY/i.r | /INTEREST/i.r | /ORG-DIRECTORY/i.r |
|
69
|
+
beginend = /BEGIN/i.r | /END/i.r
|
70
|
+
NAME_VCAL = C::XNAME_VCAL | seq("".r ^ beginend, C::IANATOKEN)[1]
|
71
|
+
NAME_VCARD = C::XNAME_VCARD | seq("".r ^ beginend, C::IANATOKEN)[1]
|
72
|
+
durday = seq(/[0-9]+/.r, "D") { |d, _| { days: d.to_i } }
|
73
|
+
dursecond = seq(/[0-9]+/.r, "S") { |d, _| { seconds: d.to_i } }
|
74
|
+
durminute = seq(/[0-9]+/.r, "M", dursecond._?) do |d, _, s|
|
75
|
+
hash = { minutes: d.to_i }
|
76
|
+
hash = hash.merge s[0] unless s.empty?
|
77
|
+
hash
|
78
|
+
end
|
79
|
+
durhour = seq(/[0-9]+/.r, "H", durminute._?) do |d, _, m|
|
80
|
+
hash = { hours: d.to_i }
|
81
|
+
hash = hash.merge m[0] unless m.empty?
|
82
|
+
hash
|
83
|
+
end
|
84
|
+
durweek = seq(/[0-9]+/.r, "W") { |d, _| { weeks: d.to_i } }
|
85
|
+
durtime1 = durhour | durminute | dursecond
|
86
|
+
durtime = seq("T", durtime1) { |_, d| d }
|
87
|
+
durdate = seq(durday, durtime._?) do |d, t|
|
88
|
+
d = d.merge t[0] unless t.empty?
|
89
|
+
d
|
90
|
+
end
|
91
|
+
duration1 = durdate | durtime | durweek
|
92
|
+
DURATION = seq(SIGN._?, "P", duration1) do |s, _, d|
|
93
|
+
d[:sign] = s[0] unless s.empty?
|
94
|
+
d
|
95
|
+
end
|
96
|
+
|
97
|
+
non_ascii = /[\u0080-\u3ffff]/
|
98
|
+
wsp = /[ \t]/.r
|
99
|
+
q_safe_char_vcal = wsp | /[\u0021\u0023-\u007e]/ | non_ascii
|
100
|
+
safe_char_vcal = wsp | /[\u0021\u0023-\u0039\u003c-\u007e]/ | non_ascii
|
101
|
+
q_safe_char_vcard = wsp | /[!\u0023-\u007e]/ | non_ascii
|
102
|
+
safe_char_vcard = wsp | /[!\u0023-\u0039\u003c-\u007e]/ | non_ascii
|
103
|
+
v_char = /[\u0021-\u007e]/.r
|
104
|
+
value_char = wsp | v_char | non_ascii
|
105
|
+
|
106
|
+
QUOTEDSTRING_VCAL = seq(/"/.r >> q_safe_char_vcal.star <<
|
107
|
+
/"/.r) { |q| q.join("") }
|
108
|
+
PTEXT_VCAL = safe_char_vcal.star.map(&:join)
|
109
|
+
QUOTEDSTRING_VCARD = seq(/"/.r >> q_safe_char_vcard.star <<
|
110
|
+
/"/.r) { |q| q.join("") }
|
111
|
+
PTEXT_VCARD = safe_char_vcard.star.map(&:join)
|
112
|
+
VALUE = value_char.star.map(&:join)
|
113
|
+
|
114
|
+
rfc5646irregular = /en-GB-oed/i.r | /i-ami/i.r | /i-bnn/i.r | /i-default/i.r | /i-enochian/i.r |
|
115
|
+
/i-hak/i.r | /i-klingon/i.r | /i-lux/i.r | /i-mingo/i.r |
|
116
|
+
/i-navajo/i.r | /i-pwn/i.r | /i-tao/i.r | /i-tay/i.r |
|
117
|
+
/i-tsu/i.r | /sgn-BE-FR/i.r | /sgn-BE-NL/i.r | /sgn-CH-DE/i.r
|
118
|
+
rfc5646regular = /art-lojban/i.r | /cel-gaulish/i.r | /no-bok/i.r | /no-nyn/i.r |
|
119
|
+
/zh-guoyu/i.r | /zh-hakka/i.r | /zh-min/i.r | /zh-min-nan/i.r |
|
120
|
+
/zh-xiang/i.r
|
121
|
+
rfc5646grandfathered = rfc5646irregular | rfc5646regular
|
122
|
+
rfc5646privateuse1 = seq("-", /[0-9A-Za-z]{1,8}/.r)
|
123
|
+
rfc5646privateuse = seq("x", rfc5646privateuse1 * (1..-1))
|
124
|
+
rfc5646extension1 = seq("-", /[0-9A-Za-z]{2,8}/.r)
|
125
|
+
rfc5646extension = seq("-", /[0-9][A-WY-Za-wy-z]/.r, rfc5646extension1 * (1..-1))
|
126
|
+
rfc5646variant = seq("-", /[A-Za-z]{5,8}/.r) | seq("-", /[0-9][A-Za-z0-9]{3}/)
|
127
|
+
rfc5646region = seq("-", /[A-Za-z]{2}/.r) | seq("-", /[0-9]{3}/)
|
128
|
+
rfc5646script = seq("-", /[A-Za-z]{4}/.r)
|
129
|
+
rfc5646extlang = seq(/[A-Za-z]{3}/.r, /[A-Za-z]{3}/.r._?, /[A-Za-z]{3}/.r._?)
|
130
|
+
rfc5646language = seq(/[A-Za-z]{2,3}/.r, rfc5646extlang._?) | /[A-Za-z]{4}/.r | /[A-Za-z]{5,8}/.r
|
131
|
+
rfc5646langtag = seq(rfc5646language, rfc5646script._?, rfc5646region._?,
|
132
|
+
rfc5646variant.star, rfc5646extension.star, rfc5646privateuse._?) do |a, b, c, d, e, f|
|
133
|
+
[a, b, c, d, e, f].flatten.join("")
|
134
|
+
end
|
135
|
+
RFC5646LANGVALUE = rfc5646langtag | rfc5646privateuse | rfc5646grandfathered
|
136
|
+
|
137
|
+
# https://www.w3.org/TR/2011/REC-css3-color-20110607/#svg-color
|
138
|
+
COLOR = /AliceBlue/i.r | /AntiqueWhite/i.r | /Aqua/i.r | /Aquamarine/i.r | /Azure/i.r | /Beige/i.r |
|
139
|
+
/Bisque/i.r | /Black/i.r | /BlanchedAlmond/i.r | /Blue/i.r | /BlueViolet/i.r | /Brown/i.r |
|
140
|
+
/BurlyWood/i.r | /CadetBlue/i.r | /Chartreuse/i.r | /Chocolate/i.r | /Coral/i.r |
|
141
|
+
/CornflowerBlue/i.r | /Cornsilk/i.r | /Crimson/i.r | /Cyan/i.r | /DarkBlue/i.r |
|
142
|
+
/DarkCyan/i.r | /DarkGoldenRod/i.r | /DarkGray/i.r | /DarkGrey/i.r | /DarkGreen/i.r |
|
143
|
+
/DarkKhaki/i.r | /DarkMagenta/i.r | /DarkOliveGreen/i.r | /DarkOrange/i.r | /DarkOrchid/i.r |
|
144
|
+
/DarkRed/i.r | /DarkSalmon/i.r | /DarkSeaGreen/i.r | /DarkSlateBlue/i.r | /DarkSlateGray/i.r |
|
145
|
+
/DarkSlateGrey/i.r | /DarkTurquoise/i.r | /DarkViolet/i.r | /DeepPink/i.r | /DeepSkyBlue/i.r |
|
146
|
+
/DimGray/i.r | /DimGrey/i.r | /DodgerBlue/i.r | /FireBrick/i.r | /FloralWhite/i.r | /ForestGreen/i.r |
|
147
|
+
/Fuchsia/i.r | /Gainsboro/i.r | /GhostWhite/i.r | /Gold/i.r | /GoldenRod/i.r | /Gray/i.r | /Grey/i.r |
|
148
|
+
/Green/i.r | /GreenYellow/i.r | /HoneyDew/i.r | /HotPink/i.r | /IndianRed/i.r | /Indigo/i.r |
|
149
|
+
/Ivory/i.r | /Khaki/i.r | /Lavender/i.r | /LavenderBlush/i.r | /LawnGreen/i.r | /LemonChiffon/i.r |
|
150
|
+
/LightBlue/i.r | /LightCoral/i.r | /LightCyan/i.r | /LightGoldenRodYellow/i.r | /LightGray/i.r |
|
151
|
+
/LightGrey/i.r | /LightGreen/i.r | /LightPink/i.r | /LightSalmon/i.r | /LightSeaGreen/i.r |
|
152
|
+
/LightSkyBlue/i.r | /LightSlateGray/i.r | /LightSlateGrey/i.r | /LightSteelBlue/i.r |
|
153
|
+
/LightYellow/i.r | /Lime/i.r | /LimeGreen/i.r | /Linen/i.r | /Magenta/i.r | /Maroon/i.r |
|
154
|
+
/MediumAquaMarine/i.r | /MediumBlue/i.r | /MediumOrchid/i.r | /MediumPurple/i.r |
|
155
|
+
/MediumSeaGreen/i.r | /MediumSlateBlue/i.r | /MediumSpringGreen/i.r | /MediumTurquoise/i.r |
|
156
|
+
/MediumVioletRed/i.r | /MidnightBlue/i.r | /MintCream/i.r | /MistyRose/i.r | /Moccasin/i.r |
|
157
|
+
/NavajoWhite/i.r | /Navy/i.r | /OldLace/i.r | /Olive/i.r | /OliveDrab/i.r | /Orange/i.r |
|
158
|
+
/OrangeRed/i.r | /Orchid/i.r | /PaleGoldenRod/i.r | /PaleGreen/i.r | /PaleTurquoise/i.r |
|
159
|
+
/PaleVioletRed/i.r | /PapayaWhip/i.r | /PeachPuff/i.r | /Peru/i.r | /Pink/i.r | /Plum/i.r |
|
160
|
+
/PowderBlue/i.r | /Purple/i.r | /RebeccaPurple/i.r | /Red/i.r | /RosyBrown/i.r | /RoyalBlue/i.r |
|
161
|
+
/SaddleBrown/i.r | /Salmon/i.r | /SandyBrown/i.r | /SeaGreen/i.r | /SeaShell/i.r | /Sienna/i.r |
|
162
|
+
/Silver/i.r | /SkyBlue/i.r | /SlateBlue/i.r | /SlateGray/i.r | /SlateGrey/i.r | /Snow/i.r |
|
163
|
+
/SpringGreen/i.r | /SteelBlue/i.r | /Tan/i.r | /Teal/i.r | /Thistle/i.r | /Tomato/i.r |
|
164
|
+
/Turquoise/i.r | /Violet/i.r | /Wheat/i.r | /White/i.r | /WhiteSmoke/i.r | /Yellow/i.r | /YellowGreen/i.r
|
165
|
+
|
166
|
+
UTC_OFFSET = seq(C::SIGN, /[0-9]{2}/.r, /[0-9]{2}/.r, /[0-9]{2}/.r._?) do |s, h, m, z|
|
167
|
+
h = { sign: s, hour: h, min: m }
|
168
|
+
h[:sec] = z[0] unless z.empty?
|
169
|
+
h
|
170
|
+
end
|
171
|
+
ZONE = UTC_OFFSET.map { |u| u } |
|
172
|
+
/Z/i.r.map { "Z" }
|
173
|
+
end
|
data/lib/error.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# expand error reporting of Rsec
|
2
|
+
class Rsec::ParseContext
|
3
|
+
def report_error(msg, source)
|
4
|
+
if pos <= @last_fail_pos
|
5
|
+
line = line @last_fail_pos
|
6
|
+
col = col @last_fail_pos
|
7
|
+
line_text = line_text @last_fail_pos
|
8
|
+
expect_tokens = Rsec::Fail.get_tokens @last_fail_mask
|
9
|
+
expects = ", expect token [ #{expect_tokens.join ' | '} ]"
|
10
|
+
else
|
11
|
+
line = line pos
|
12
|
+
col = col pos
|
13
|
+
line_text = line_text pos
|
14
|
+
expects = nil
|
15
|
+
end
|
16
|
+
msg = "#{msg}\nin #{source}:#{line} at #{col}#{expects}"
|
17
|
+
Rsec::SyntaxError.new msg, line_text, line, col
|
18
|
+
end
|
19
|
+
end
|
data/lib/vcalendar.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require "vobject"
|
2
|
+
require "vobject/component"
|
3
|
+
require "vobject/vcalendar/component"
|
4
|
+
require "vobject/vcalendar/grammar"
|
5
|
+
require "json"
|
6
|
+
|
7
|
+
class Vcalendar < Vobject::Component
|
8
|
+
attr_accessor :comp_name, :children, :version
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def parse(vcf, strict)
|
12
|
+
Vobject::Component::Vcalendar.parse(vcf, strict)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(key, cs, err)
|
17
|
+
super key, cs, err
|
18
|
+
end
|
19
|
+
|
20
|
+
def child_class(key, val)
|
21
|
+
base_class = if key == :VTODO
|
22
|
+
Vobject::Component::Vcalendar::ToDo
|
23
|
+
elsif key == :VFREEBUSY
|
24
|
+
Vobject::Component::Vcalendar::FreeBusy
|
25
|
+
elsif key == :JOURNAL
|
26
|
+
Vobject::Component::Vcalendar::Journal
|
27
|
+
elsif key == :STANDARD
|
28
|
+
Vobject::Component::Vcalendar::Timezone::Standard
|
29
|
+
elsif key == :DAYLIGHT
|
30
|
+
Vobject::Component::Vcalendar::Timezone::Daylight
|
31
|
+
elsif key == :VTIMEZONE
|
32
|
+
Vobject::Component::Vcalendar::Timezone
|
33
|
+
elsif key == :VEVENT
|
34
|
+
Vobject::Component::Vcalendar::Event
|
35
|
+
elsif key == :VALARM
|
36
|
+
Vobject::Component::Vcalendar::Alarm
|
37
|
+
elsif key == :VAVAILABILITY
|
38
|
+
Vobject::Component::Vcalendar::Vavailability
|
39
|
+
elsif key == :AVAILABLE
|
40
|
+
Vobject::Component::Vcalendar::Vavailability::Available
|
41
|
+
elsif !(val.is_a?(Hash) && !val.has_key?(:value))
|
42
|
+
property_base_class
|
43
|
+
else
|
44
|
+
Vobject::Component::Vcalendar
|
45
|
+
end
|
46
|
+
return base_class if [:CLASS, :OBJECT, :METHOD].include?
|
47
|
+
camelized_key = key.to_s.downcase.split("_").map(&:capitalize).join("")
|
48
|
+
base_class.const_get(camelized_key) rescue base_class
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def raise_invalid_parsing
|
54
|
+
raise "Vobject component parse failed"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Vobject::Component::Vcalendar::ToDo < Vobject::Component::Vcalendar
|
59
|
+
end
|
60
|
+
class Vobject::Component::Vcalendar::Freebusy < Vobject::Component::Vcalendar
|
61
|
+
end
|
62
|
+
class Vobject::Component::Vcalendar::Journal < Vobject::Component::Vcalendar
|
63
|
+
end
|
64
|
+
class Vobject::Component::Vcalendar::Timezone < Vobject::Component::Vcalendar
|
65
|
+
end
|
66
|
+
class Vobject::Component::Vcalendar::Timezone::Standard < Vobject::Component::Vcalendar::Timezone
|
67
|
+
end
|
68
|
+
class Vobject::Component::Vcalendar::Timezone::Daylight < Vobject::Component::Vcalendar::Timezone
|
69
|
+
end
|
70
|
+
class Vobject::Component::Vcalendar::Event < Vobject::Component::Vcalendar
|
71
|
+
end
|
72
|
+
class Vobject::Component::Vcalendar::Alarm < Vobject::Component::Vcalendar
|
73
|
+
end
|
74
|
+
class Vobject::Component::Vcalendar::Vavailability < Vobject::Component::Vcalendar
|
75
|
+
end
|
76
|
+
# class Vobject::Component::Vcalendar::Vavailability::Available < Vobject::Component::Vcalendar::Vavailability
|
77
|
+
# end
|