vobject 0.1.0 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/macos.yml +38 -0
  3. data/.github/workflows/ubuntu.yml +56 -0
  4. data/.github/workflows/windows.yml +40 -0
  5. data/.hound.yml +3 -0
  6. data/.rubocop.tb.yml +650 -0
  7. data/.rubocop.yml +1077 -0
  8. data/Gemfile +1 -1
  9. data/LICENSE.txt +21 -17
  10. data/README.adoc +151 -0
  11. data/Rakefile +1 -1
  12. data/lib/c.rb +173 -0
  13. data/lib/error.rb +19 -0
  14. data/lib/vcalendar.rb +77 -0
  15. data/lib/vcard.rb +67 -0
  16. data/lib/vobject.rb +13 -170
  17. data/lib/vobject/component.rb +87 -36
  18. data/lib/vobject/parameter.rb +116 -0
  19. data/lib/vobject/parametervalue.rb +26 -0
  20. data/lib/vobject/property.rb +134 -55
  21. data/lib/vobject/propertyvalue.rb +46 -0
  22. data/lib/vobject/vcalendar/component.rb +106 -0
  23. data/lib/vobject/vcalendar/grammar.rb +595 -0
  24. data/lib/vobject/vcalendar/paramcheck.rb +259 -0
  25. data/lib/vobject/vcalendar/propertyparent.rb +98 -0
  26. data/lib/vobject/vcalendar/propertyvalue.rb +606 -0
  27. data/lib/vobject/vcalendar/typegrammars.rb +605 -0
  28. data/lib/vobject/vcard/v3_0/component.rb +40 -0
  29. data/lib/vobject/vcard/v3_0/grammar.rb +175 -0
  30. data/lib/vobject/vcard/v3_0/paramcheck.rb +110 -0
  31. data/lib/vobject/vcard/v3_0/parameter.rb +17 -0
  32. data/lib/vobject/vcard/v3_0/property.rb +18 -0
  33. data/lib/vobject/vcard/v3_0/propertyvalue.rb +401 -0
  34. data/lib/vobject/vcard/v3_0/typegrammars.rb +425 -0
  35. data/lib/vobject/vcard/v4_0/component.rb +40 -0
  36. data/lib/vobject/vcard/v4_0/grammar.rb +224 -0
  37. data/lib/vobject/vcard/v4_0/paramcheck.rb +269 -0
  38. data/lib/vobject/vcard/v4_0/parameter.rb +18 -0
  39. data/lib/vobject/vcard/v4_0/property.rb +63 -0
  40. data/lib/vobject/vcard/v4_0/propertyvalue.rb +404 -0
  41. data/lib/vobject/vcard/v4_0/typegrammars.rb +539 -0
  42. data/lib/vobject/version.rb +1 -1
  43. data/vobject.gemspec +19 -16
  44. metadata +81 -26
  45. data/.travis.yml +0 -5
  46. data/README.md +0 -94
@@ -0,0 +1,259 @@
1
+ require "rsec"
2
+ require "set"
3
+ require "uri"
4
+ require "date"
5
+ require "tzinfo"
6
+ include Rsec::Helpers
7
+ require_relative "../../c"
8
+ require_relative "../../error"
9
+
10
+ module Vobject::Vcalendar
11
+ class Paramcheck
12
+ class << self
13
+ def paramcheck(strict, prop, params, ctx)
14
+ errors = []
15
+ if params && params[:ALTREP]
16
+ case prop
17
+ when :COMMENT, :DESCRIPTION, :LOCATION, :RESOURCES, :SUMMARY,
18
+ :CONTACT, :NAME, :IMAGE
19
+ else
20
+ parse_err(strict, errors, "(:ALTREP parameter given for #{prop}", ctx)
21
+ end
22
+ end
23
+ if params && params[:CN]
24
+ case prop
25
+ when :ATTENDEE, :ORGANIZER
26
+ else
27
+ parse_err(strict, errors, "(:CN parameter given for #{prop}", ctx)
28
+ end
29
+ end
30
+ if params && params[:CUTYPE]
31
+ case prop
32
+ when :ATTENDEE
33
+ else
34
+ parse_err(strict, errors, "(:CUTYPE parameter given for #{prop}", ctx)
35
+ end
36
+ end
37
+ if params && params[:DELEGATED_FROM]
38
+ case prop
39
+ when :ATTENDEE
40
+ else
41
+ parse_err(strict, errors, "(:DELEGATED_FROM parameter given for #{prop}", ctx)
42
+ end
43
+ end
44
+ if params && params[:DELEGATED_TO]
45
+ case prop
46
+ when :ATTENDEE
47
+ else
48
+ parse_err(strict, errors, "(:DELEGATED_TO parameter given for #{prop}", ctx)
49
+ end
50
+ end
51
+ if params && params[:DIR]
52
+ case prop
53
+ when :ATTENDEE, :ORGANIZER
54
+ else
55
+ parse_err(strict, errors, "(:DIR parameter given for #{prop}", ctx)
56
+ end
57
+ end
58
+ if params && params[:ENCODING]
59
+ case prop
60
+ when :ATTACH, :IMAGE
61
+ else
62
+ parse_err(strict, errors, "(:ENCODING parameter given for #{prop}", ctx)
63
+ end
64
+ end
65
+ if params && params[:FMTTYPE]
66
+ case prop
67
+ when :ATTACH, :IMAGE
68
+ else
69
+ parse_err(strict, errors, "(:FMTTYPE parameter given for #{prop}", ctx)
70
+ end
71
+ end
72
+ if params && params[:FBTYPE]
73
+ case prop
74
+ when :FREEBUSY
75
+ else
76
+ parse_err(strict, errors, "(:FBTYPE parameter given for #{prop}", ctx)
77
+ end
78
+ end
79
+ if params && params[:LANGUAGE]
80
+ case prop
81
+ when :CATEGORIES, :COMMENT, :DESCRIPTION, :LOCATION, :RESOURCES,
82
+ :SUMMARY, :TZNAME, :ATTENDEE, :CONTACT, :ORGANIZER, :REQUEST_STATUS,
83
+ :NAME, :CONFERENCE
84
+ else
85
+ parse_err(strict, errors, "(:LANGUAGE parameter given for #{prop}", ctx)
86
+ end
87
+ end
88
+ if params && params[:MEMBER]
89
+ case prop
90
+ when :ATTENDEE
91
+ else
92
+ parse_err(strict, errors, "(:MEMBER parameter given for #{prop}", ctx)
93
+ end
94
+ end
95
+ if params && params[:PARTSTAT]
96
+ case prop
97
+ when :ATTENDEE
98
+ else
99
+ parse_err(strict, errors, "(:PARTSTAT parameter given for #{prop}", ctx)
100
+ end
101
+ end
102
+ if params && params[:RANGE]
103
+ case prop
104
+ when :RECURRENCE_ID
105
+ else
106
+ parse_err(strict, errors, "(:RANGE parameter given for #{prop}", ctx)
107
+ end
108
+ end
109
+ if params && params[:RELATED]
110
+ case prop
111
+ when :TRIGGER
112
+ else
113
+ parse_err(strict, errors, "(:RELATED parameter given for #{prop}", ctx)
114
+ end
115
+ end
116
+ if params && params[:RELTYPE]
117
+ case prop
118
+ when :RELATED_TO
119
+ else
120
+ parse_err(strict, errors, "(:RELTYPE parameter given for #{prop}", ctx)
121
+ end
122
+ end
123
+ if params && params[:ROLE]
124
+ case prop
125
+ when :ATTENDEE
126
+ else
127
+ parse_err(strict, errors, "(:ROLE parameter given for #{prop}", ctx)
128
+ end
129
+ end
130
+ if params && params[:RSVP]
131
+ case prop
132
+ when :ATTENDEE
133
+ else
134
+ parse_err(strict, errors, "(:RSVP parameter given for #{prop}", ctx)
135
+ end
136
+ end
137
+ if params && params[:SENT_BY]
138
+ case prop
139
+ when :ATTENDEE, :ORGANIZER
140
+ else
141
+ parse_err(strict, errors, "(:SENT_BY parameter given for #{prop}", ctx)
142
+ end
143
+ end
144
+ if params && params[:TZID]
145
+ case prop
146
+ when :DTEND, :DUE, :DTSTART, :RECURRENCE_ID, :EXDATE, :RDATE
147
+ else
148
+ parse_err(strict, errors, "(:TZID parameter given for #{prop}", ctx)
149
+ end
150
+ end
151
+ if params && params[:DISPLAY]
152
+ case prop
153
+ when :IMAGE
154
+ else
155
+ parse_err(strict, errors, "(:DISPLAY parameter given for #{prop}", ctx)
156
+ end
157
+ end
158
+ if params && params[:FEATURE]
159
+ case prop
160
+ when :CONFERENCE
161
+ else
162
+ parse_err(strict, errors, "(:FEATURE parameter given for #{prop}", ctx)
163
+ end
164
+ end
165
+ if params && params[:LABEL]
166
+ case prop
167
+ when :CONFERENCE
168
+ else
169
+ parse_err(strict, errors, "(:LABEL parameter given for #{prop}", ctx)
170
+ end
171
+ end
172
+ if params && params[:EMAIL]
173
+ case prop
174
+ when :ORGANIZER, :ATTENDEE
175
+ else
176
+ parse_err(strict, errors, "(:EMAIL parameter given for #{prop}", ctx)
177
+ end
178
+ end
179
+
180
+ case prop
181
+ when :TZURL, :URL, :CONFERENCE, :SOURCE
182
+ params.each do |key, val|
183
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("uri") != 0
184
+ end
185
+ when :FREEBUSY
186
+ params.each do |key, val|
187
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("period") != 0
188
+ end
189
+ when :COMPLETED
190
+ params.each do |key, val|
191
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("date-time") != 0
192
+ end
193
+ when :PERCENT_COMPLETE, :PRIORITY, :REPEAT, :SEQUENCE
194
+ params.each do |key, val|
195
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("integer") != 0
196
+ end
197
+ when :DURATION, :REFRESH_INTERVAL
198
+ params.each do |key, val|
199
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("duration") != 0
200
+ end
201
+ when :GEO
202
+ params.each do |key, val|
203
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("float") != 0
204
+ end
205
+ when :CREATED, :DTSTAMP, :LAST_MODIFIED
206
+ params.each do |key, val|
207
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("date-time") != 0
208
+ end
209
+ when :CALSCALE, :METHOD, :PRODID, :VERSION, :CATEGORIES, :CLASS,
210
+ :COMMENT, :DESCRIPTION, :LOCATION, :RESOURCES, :STATUS, :SUMMARY,
211
+ :TRANSP, :TZID, :TZNAME, :CONTACT, :RELATED_TO, :UID, :ACTION,
212
+ :REQUEST_STATUS, :COLOR, :NAME
213
+ params.each do |key, val|
214
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("text") != 0
215
+ end
216
+ when :DTEND, :DUE, :DTSTART, :RECURRENCE_ID, :EXDATE
217
+ params.each do |key, val|
218
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("date-time") != 0 && val.casecmp("date") != 0
219
+ end
220
+ when :RDATE
221
+ params.each do |key, val|
222
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("period") != 0 && val.casecmp("date") != 0 && val.casecmp("date-time") != 0
223
+ end
224
+ when :RRULE
225
+ params.each do |key, val|
226
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("recur") != 0
227
+ end
228
+ when :TZOFFSETFROM, :TZOFFSETTO
229
+ params.each do |key, val|
230
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("utc-offset") != 0
231
+ end
232
+ when :ATTENDEE, :ORGANIZER
233
+ params.each do |key, val|
234
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("cal-address") != 0
235
+ end
236
+ when :TRIGGER
237
+ params.each do |key, val|
238
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("duration") != 0 && val.casecmp("date-time") != 0
239
+ end
240
+ when :ATTACH, :IMAGE
241
+ params.each do |key, val|
242
+ parse_err(strict, errors, "(illegal value #{val} given for parameter #{key} of #{prop}", ctx) if key == :VALUE && val.casecmp("uri") != 0 && val.casecmp("binary") != 0
243
+ end
244
+ end
245
+ errors
246
+ end
247
+
248
+ private
249
+
250
+ def parse_err(strict, errors, msg, ctx)
251
+ if strict
252
+ raise ctx.report_error msg, "source"
253
+ else
254
+ errors << ctx.report_error(msg, "source")
255
+ end
256
+ end
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,98 @@
1
+ require "rsec"
2
+ require "set"
3
+ require "uri"
4
+ require "date"
5
+ require "tzinfo"
6
+ include Rsec::Helpers
7
+ require_relative "../../c"
8
+ require_relative "../../error"
9
+ require "vobject"
10
+
11
+ module Vobject::Vcalendar
12
+ class Typegrammars
13
+ class << self
14
+ # Ensure each property belongs to a legal component
15
+ def property_parent(strict, key, component, _value, ctx1)
16
+ errors = []
17
+ if key !~ /^x/i && registered_propname?(key.to_s)
18
+ case component
19
+ when :EVENT
20
+ case key
21
+ when :DTSTAMP, :UID, :DTSTART, :CLASS, :CREATED, :DESCRIPTION,
22
+ :GEO, :LAST_MOD, :LOCATION, :ORGANIZER, :PRIORITY, :SEQUENCE, :STATUS,
23
+ :SUMMARY, :TRANSP, :URL, :RECURRENCE_ID, :RRULE, :DTEND, :DURATION,
24
+ :ATTACH, :ATTENDEE, :CATEGORIES, :COMMENT, :CONTACT, :EXDATE,
25
+ :RSTATUS, :RELATED, :RESOURCES, :RDATE, :COLOR, :CONFERENCE, :IMAGE
26
+ else
27
+ parse_err(strict, errors, "Invalid property #{key} specified for #{component}", ctx1)
28
+ end
29
+ when :TODO
30
+ case key
31
+ when :DTSTAMP, :UID, :DTSTART, :CLASS, :CREATED, :DESCRIPTION,
32
+ :GEO, :LAST_MOD, :LOCATION, :ORGANIZER, :PRIORITY, :PERCENT_COMPLETED, :SEQUENCE, :STATUS,
33
+ :SUMMARY, :URL, :RECURRENCE_ID, :RRULE, :DUE, :DURATION,
34
+ :ATTACH, :ATTENDEE, :CATEGORIES, :COMMENT, :CONTACT, :EXDATE,
35
+ :RSTATUS, :RELATED, :RESOURCES, :RDATE, :COLOR, :CONFERENCE, :IMAGE
36
+ else
37
+ parse_err(strict, errors, "Invalid property #{key} specified for #{component}", ctx1)
38
+ end
39
+ when :JOURNAL
40
+ case key
41
+ when :DTSTAMP, :UID, :DTSTART, :CLASS, :CREATED, :DESCRIPTION,
42
+ :LAST_MOD, :ORGANIZER, :RECURRENCE_ID, :SEQUENCE, :STATUS,
43
+ :SUMMARY, :URL, :RRULE,
44
+ :ATTACH, :ATTENDEE, :CATEGORIES, :COMMENT, :CONTACT, :EXDATE,
45
+ :RSTATUS, :RELATED, :RDATE, :COLOR, :IMAGE
46
+ else
47
+ parse_err(strict, errors, "Invalid property #{key} specified for #{component}", ctx1)
48
+ end
49
+ when :FREEBUSY
50
+ case key
51
+ when :DTSTAMP, :UID, :CONTACT, :DTSTART, :DTEND, :ORGANIZER, :URL,
52
+ :ATTENDEE, :COMMENT, :FREEBUSY, :RSTATUS
53
+ else
54
+ parse_err(strict, errors, "Invalid property #{key} specified for #{component}", ctx1)
55
+ end
56
+ when :TIMEZONE
57
+ case key
58
+ when :TZID, :LAST_MODIFIED, :TZURL
59
+ else
60
+ parse_err(strict, errors, "Invalid property #{key} specified for #{component}", ctx1)
61
+ end
62
+ when :DAYLIGHT, :STANDARD
63
+ case key
64
+ when :DTSTART, :TZOFFSETTO, :TZOFFSETFROM, :RRULE,
65
+ :COMMENT, :RDATE, :TZNAME
66
+ else
67
+ parse_err(strict, errors, "Invalid property #{key} specified for #{component}", ctx1)
68
+ end
69
+ when :ALARM
70
+ case key
71
+ when :ACTION, :TRIGGER, :DURATION, :REPEAT, :ATTACH, :DESCRIPTION,
72
+ :SUMMARY, :ATTENDEE
73
+ else
74
+ parse_err(strict, errors, "Invalid property #{key} specified for #{component}", ctx1)
75
+ end
76
+ when :VAVAILABILITY
77
+ case key
78
+ when :DTSTAMP, :UID, :BUSYTYPE, :CLASS, :CREATED, :DESCRIPTION,
79
+ :DTSTART, :LAST_MODIFIED, :LOCATION, :ORGANIZER, :PRIORITY, :SEQUENCE,
80
+ :SUMMARY, :URL, :DTEND, :DURATION, :CATEGORIES, :COMMENT, :CONTACT
81
+ else
82
+ parse_err(strict, errors, "Invalid property #{key} specified for #{component}", ctx1)
83
+ end
84
+ when :AVAILABLE
85
+ case key
86
+ when :DTSTAMP, :DTSTART, :UID, :DTEND, :DURATION, :CREATED,
87
+ :DESCRIPTION, :LAST_MODIFIED, :LOCATION, :RECURRENCE_ID, :RRULE,
88
+ :SUMMARY, :CATEGORIES, :COMMENT, :CONTACT, :EXDATE, :RDATE
89
+ else
90
+ parse_err(strict, errors, "Invalid property #{key} specified for #{component}", ctx1)
91
+ end
92
+ end
93
+ end
94
+ errors
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,606 @@
1
+ require "vobject"
2
+ require "vobject/propertyvalue"
3
+
4
+ module Vobject
5
+ module Vcalendar
6
+ module PropertyValue
7
+ class Text < Vobject::PropertyValue
8
+ class << self
9
+ def escape(x)
10
+ # temporarily escape \\ as \u007f, which is banned from text
11
+ x.tr("\\", "\u007f").gsub(/\n/, "\\n").gsub(/,/, "\\,").
12
+ gsub(/;/, "\\;").gsub(/\u007f/, "\\\\\\\\")
13
+ end
14
+ end
15
+
16
+ def initialize(val)
17
+ self.value = val
18
+ self.type = "text"
19
+ end
20
+
21
+ def to_s
22
+ Text.escape value
23
+ end
24
+
25
+ def to_hash
26
+ value
27
+ end
28
+ end
29
+
30
+ class ClassValue < Text
31
+ def initialize(val)
32
+ self.value = val
33
+ self.type = "classvalue"
34
+ end
35
+
36
+ def to_hash
37
+ value
38
+ end
39
+ end
40
+
41
+ class TranspValue < Text
42
+ def initialize(val)
43
+ self.value = val
44
+ self.type = "transpvalue"
45
+ end
46
+
47
+ def to_hash
48
+ value
49
+ end
50
+ end
51
+
52
+ class ActionValue < Text
53
+ def initialize(val)
54
+ self.value = val
55
+ self.type = "actionvalue"
56
+ end
57
+
58
+ def to_hash
59
+ value
60
+ end
61
+ end
62
+
63
+ class MethodValue < Text
64
+ def initialize(val)
65
+ self.value = val
66
+ self.type = "methodvalue"
67
+ end
68
+
69
+ def to_hash
70
+ value
71
+ end
72
+ end
73
+
74
+ class Busytype < Text
75
+ def initialize(val)
76
+ self.value = val
77
+ self.type = "busytype"
78
+ end
79
+
80
+ def to_hash
81
+ value
82
+ end
83
+ end
84
+
85
+ class Color < Text
86
+ def initialize(val)
87
+ self.value = val
88
+ self.type = "color"
89
+ end
90
+
91
+ def to_hash
92
+ value
93
+ end
94
+ end
95
+
96
+ class EventStatus < Text
97
+ def initialize(val)
98
+ self.value = val
99
+ self.type = "eventstatus"
100
+ end
101
+
102
+ def to_hash
103
+ value
104
+ end
105
+ end
106
+
107
+ class Todostatus < Text
108
+ def initialize(val)
109
+ self.value = val
110
+ self.type = "todostatus"
111
+ end
112
+
113
+ def to_hash
114
+ value
115
+ end
116
+ end
117
+
118
+ class Journalstatus < Text
119
+ def initialize(val)
120
+ self.value = val
121
+ self.type = "journalstatus"
122
+ end
123
+
124
+ def to_hash
125
+ value
126
+ end
127
+ end
128
+
129
+ class Ianatoken < Text
130
+ def initialize(val)
131
+ self.value = val
132
+ self.type = "ianatoken"
133
+ end
134
+
135
+ def to_hash
136
+ value
137
+ end
138
+ end
139
+
140
+ class Binary < Text
141
+ def initialize(val)
142
+ self.value = val
143
+ self.type = "binary"
144
+ end
145
+
146
+ def to_hash
147
+ value
148
+ end
149
+ end
150
+
151
+ class Uri < Text
152
+ def initialize(val)
153
+ self.value = val
154
+ self.type = "uri"
155
+ end
156
+
157
+ def to_hash
158
+ value
159
+ end
160
+ end
161
+
162
+ class Calscale < Vobject::PropertyValue
163
+ def initialize(val)
164
+ self.value = val
165
+ self.type = "calscale"
166
+ end
167
+
168
+ def to_s
169
+ value
170
+ end
171
+
172
+ def to_hash
173
+ value
174
+ end
175
+ end
176
+
177
+ class Float < Vobject::PropertyValue
178
+ include Comparable
179
+ def <=>(another)
180
+ value <=> another.value
181
+ end
182
+
183
+ def initialize(val)
184
+ self.value = val
185
+ self.type = "float"
186
+ end
187
+
188
+ def to_s
189
+ value.to_s
190
+ end
191
+
192
+ def to_hash
193
+ value
194
+ end
195
+ end
196
+
197
+ class Integer < Vobject::PropertyValue
198
+ include Comparable
199
+ def <=>(another)
200
+ value <=> another.value
201
+ end
202
+
203
+ def initialize(val)
204
+ self.value = val
205
+ self.type = "integer"
206
+ end
207
+
208
+ def to_s
209
+ value.to_s
210
+ end
211
+
212
+ def to_hash
213
+ value
214
+ end
215
+ end
216
+
217
+ class PercentComplete < Integer
218
+ def initialize(val)
219
+ self.value = val
220
+ self.type = "percentcomplete"
221
+ end
222
+
223
+ def to_hash
224
+ value
225
+ end
226
+ end
227
+
228
+ class Priority < Integer
229
+ def initialize(val)
230
+ self.value = val
231
+ self.type = "priority"
232
+ end
233
+
234
+ def to_hash
235
+ value
236
+ end
237
+ end
238
+
239
+ class Date < Vobject::PropertyValue
240
+ include Comparable
241
+ def <=>(another)
242
+ value <=> another.value
243
+ end
244
+
245
+ def initialize(val)
246
+ self.value = val
247
+ self.type = "date"
248
+ end
249
+
250
+ def to_s
251
+ sprintf("%04d%02d%02d", value.year, value.month, value.day)
252
+ end
253
+
254
+ def to_hash
255
+ value
256
+ end
257
+ end
258
+
259
+ class DateTimeLocal < Vobject::PropertyValue
260
+ include Comparable
261
+ def <=>(another)
262
+ value[:time] <=> another.value[:time]
263
+ end
264
+
265
+ def initialize(val)
266
+ self.value = val.clone
267
+ # val consists of :time && :zone values. If :zone is empty, floating local time (i.e. system local time) is assumed
268
+ self.type = "datetimeLocal"
269
+ value[:time] = if val[:zone].nil? || val[:zone].empty?
270
+ ::Time.local(val[:year], val[:month], val[:day], val[:hour], val[:min], val[:sec])
271
+ else
272
+ ::Time.utc(val[:year], val[:month], val[:day], val[:hour], val[:min], val[:sec])
273
+ end
274
+ value[:origtime] = value[:time]
275
+ end
276
+
277
+ def to_s
278
+ # ret = sprintf("%04d%02d%02dT%02d%02d%02d", value[:year], value[:month], value[:day], value[:hour], value[:min], value[:sec])
279
+ ret = sprintf("%s%s%sT%s%s%s", value[:year], value[:month], value[:day], value[:hour], value[:min], value[:sec])
280
+ zone = "Z" if value[:zone] && value[:zone] == "Z"
281
+ ret = ret + zone if !zone.nil?
282
+ ret
283
+ end
284
+
285
+
286
+ def to_hash
287
+ ret = {
288
+ year: value[:year],
289
+ month: value[:month],
290
+ day: value[:day],
291
+ hour: value[:hour],
292
+ min: value[:min],
293
+ sec: value[:sec],
294
+ }
295
+ ret[:zone] = value[:zone] if value[:zone]
296
+ ret
297
+ end
298
+ end
299
+
300
+ class DateTimeUTC < Vobject::PropertyValue
301
+ include Comparable
302
+ def <=>(another)
303
+ value[:time] <=> another.value[:time]
304
+ end
305
+
306
+ def initialize(val)
307
+ self.value = val.clone
308
+ value[:time] = ::Time.utc(val[:year], val[:month], val[:day], val[:hour], val[:min], val[:sec])
309
+ value[:origtime] = value[:time]
310
+ end
311
+
312
+ def to_s
313
+ localtime = value[:origtime]
314
+ ret = sprintf("%04d%02d%02dT%02d%02d%02dZ", localtime.year, localtime.month, localtime.day,
315
+ localtime.hour, localtime.min, localtime.sec)
316
+ ret
317
+ end
318
+
319
+ def to_hash
320
+ ret = {
321
+ year: value[:year],
322
+ month: value[:month],
323
+ day: value[:day],
324
+ hour: value[:hour],
325
+ min: value[:min],
326
+ sec: value[:sec],
327
+ }
328
+ ret
329
+ end
330
+ end
331
+
332
+ class Boolean < Vobject::PropertyValue
333
+ def initialize(val)
334
+ self.value = val
335
+ self.type = "boolean"
336
+ end
337
+
338
+ def to_s
339
+ value.to_s
340
+ end
341
+
342
+ def to_hash
343
+ value
344
+ end
345
+
346
+ def to_norm
347
+ value.to_s.upcase
348
+ end
349
+ end
350
+
351
+ class Duration < Vobject::PropertyValue
352
+ def initialize(val)
353
+ self.value = val
354
+ self.type = "duration"
355
+ end
356
+
357
+ def to_s
358
+ ret = "P"
359
+ ret = value[:sign] + ret if value[:sign]
360
+ ret = ret + "#{value[:weeks]}W" if value[:weeks]
361
+ ret = ret + "#{value[:days]}D" if value[:days]
362
+ ret = ret + "T" if value[:hours] || value[:minutes] || value[:seconds]
363
+ ret = ret + "#{value[:hours]}H" if value[:hours]
364
+ ret = ret + "#{value[:minutes]}M" if value[:minutes]
365
+ ret = ret + "#{value[:seconds]}S" if value[:seconds]
366
+ ret
367
+ end
368
+
369
+ def to_hash
370
+ value
371
+ end
372
+ end
373
+
374
+ class Time < Vobject::PropertyValue
375
+ def initialize(val)
376
+ self.value = val
377
+ self.type = "time"
378
+ end
379
+
380
+ def to_s
381
+ ret = "#{value[:hour]}#{value[:min]}#{value[:sec]}"
382
+ ret = ret + "Z" if value[:utc]
383
+ ret
384
+ end
385
+
386
+ def to_hash
387
+ value
388
+ end
389
+ end
390
+
391
+ class Utcoffset < Vobject::PropertyValue
392
+ def initialize(val)
393
+ self.value = val
394
+ self.type = "utcoffset"
395
+ end
396
+
397
+ def to_s
398
+ ret = "#{value[:sign]}#{value[:hr]}#{value[:min]}"
399
+ ret += value[:sec] if value[:sec]
400
+ ret
401
+ end
402
+
403
+ def to_hash
404
+ value
405
+ end
406
+ end
407
+
408
+ class Geovalue < Vobject::PropertyValue
409
+ def initialize(val)
410
+ self.value = val
411
+ self.type = "geovalue"
412
+ end
413
+
414
+ def to_s
415
+ ret = "#{value[:lat]};#{value[:long]}"
416
+ ret
417
+ end
418
+
419
+ def to_hash
420
+ value
421
+ end
422
+ end
423
+
424
+ class Version < Vobject::PropertyValue
425
+ def initialize(val)
426
+ self.value = val
427
+ self.type = "version"
428
+ end
429
+
430
+ def to_s
431
+ value.join(";")
432
+ end
433
+
434
+ def to_hash
435
+ if value.length == 1
436
+ value[0]
437
+ else
438
+ value
439
+ end
440
+ end
441
+ end
442
+
443
+ class Textlist < Vobject::PropertyValue
444
+ def initialize(val)
445
+ self.value = val
446
+ self.type = "textlist"
447
+ end
448
+
449
+ def to_s
450
+ value.map { |m| Text.escape m }.join(",")
451
+ end
452
+
453
+ def to_hash
454
+ value
455
+ end
456
+ end
457
+
458
+ class Periodlist < Vobject::PropertyValue
459
+ def initialize(val)
460
+ self.value = val
461
+ self.type = "periodlist"
462
+ end
463
+
464
+ def to_s
465
+ value.map do |m|
466
+ ret = m[:start].to_s + "/"
467
+ ret += m[:end].to_s if m.has_key? :end
468
+ ret += m[:duration].to_s if m.has_key? :duration
469
+ ret
470
+ end.join(",")
471
+ end
472
+
473
+ def to_hash
474
+ value.map { |m| m.each { |k, v| m[k] = v.to_hash } }
475
+ end
476
+ end
477
+
478
+ class Datelist < Vobject::PropertyValue
479
+ def initialize(val)
480
+ self.value = val
481
+ self.type = "datelist"
482
+ end
483
+
484
+ def to_s
485
+ value.map(&:to_s).join(",")
486
+ end
487
+
488
+ def to_hash
489
+ value.map(&:to_hash)
490
+ end
491
+ end
492
+
493
+ class Datetimelist < Vobject::PropertyValue
494
+ def initialize(val)
495
+ self.value = val
496
+ self.type = "datetimelist"
497
+ end
498
+
499
+ def to_s
500
+ value.map(&:to_s).join(",")
501
+ end
502
+
503
+ def to_hash
504
+ value.map(&:to_hash)
505
+ end
506
+ end
507
+
508
+ class Datetimeutclist < Vobject::PropertyValue
509
+ def initialize(val)
510
+ self.value = val
511
+ self.type = "datetimeutclist"
512
+ end
513
+
514
+ def to_s
515
+ value.map(&:to_s).join(",")
516
+ end
517
+
518
+ def to_hash
519
+ value.map(&:to_hash)
520
+ end
521
+ end
522
+
523
+ class Requeststatusvalue < Vobject::PropertyValue
524
+ def initialize(val)
525
+ self.value = val
526
+ self.type = "requeststatusvalue"
527
+ end
528
+
529
+ def to_s
530
+ ret = "#{value[:statcode]};#{value[:statdesc]}"
531
+ ret += ";#{value[:extdata]}" if value[:extdata]
532
+ ret
533
+ end
534
+
535
+ def to_hash
536
+ value
537
+ end
538
+ end
539
+
540
+ class Recur < Vobject::PropertyValue
541
+ def initialize(val)
542
+ self.value = val
543
+ self.type = "recur"
544
+ end
545
+
546
+ def to_s
547
+ ret = []
548
+ value.each do |k, v|
549
+ ret << "#{k.to_s.upcase}=#{valencode(k, v)}"
550
+ end
551
+ ret.join(";")
552
+ end
553
+
554
+ def to_hash
555
+ ret = {}
556
+ value.each do |k, v|
557
+ ret[k] = if v.respond_to?(:to_hash)
558
+ v.to_hash
559
+ else
560
+ v
561
+ end
562
+ end
563
+ ret
564
+ end
565
+
566
+ private
567
+
568
+ def valencode(k, v)
569
+ case k
570
+ when :bysetpos, :byyearday
571
+ v.map do |x|
572
+ ret = x[:ordyrday]
573
+ ret = x[:sign] + ret if x[:sign]
574
+ ret
575
+ end.join(",")
576
+ when :byweekno
577
+ v.map do |x|
578
+ ret = x[:ordwk]
579
+ ret = x[:sign] + ret if x[:sign]
580
+ ret
581
+ end.join(",")
582
+ when :bymonthday
583
+ v.map do |x|
584
+ ret = x[:ordmoday]
585
+ ret = x[:sign] + ret if x[:sign]
586
+ ret
587
+ end.join(",")
588
+ when :byday
589
+ v.map do |x|
590
+ ret = x[:weekday]
591
+ ret = x[:ordwk] + ret if x[:ordwk]
592
+ ret = x[:sign] + ret if x[:sign]
593
+ ret
594
+ end.join(",")
595
+ when :bymonth, :byhour, :byminute, :bysecond
596
+ v.join(",")
597
+ when :enddate
598
+ v.to_s
599
+ else
600
+ v
601
+ end
602
+ end
603
+ end
604
+ end
605
+ end
606
+ end