vcard 0.1.1 → 0.2.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.
Files changed (49) hide show
  1. data/.gitignore +15 -5
  2. data/Gemfile +3 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +17 -0
  5. data/Rakefile +4 -52
  6. data/{LICENSE → VPIM-LICENSE.txt} +2 -2
  7. data/lib/vcard.rb +304 -28
  8. data/lib/vcard/attachment.rb +10 -12
  9. data/lib/vcard/bnf.rb +66 -0
  10. data/lib/vcard/dirinfo.rb +24 -26
  11. data/lib/vcard/enumerator.rb +5 -7
  12. data/lib/vcard/errors.rb +23 -0
  13. data/lib/vcard/field.rb +56 -58
  14. data/lib/vcard/vcard.rb +210 -240
  15. data/lib/vcard/version.rb +3 -0
  16. data/test/field_test.rb +55 -55
  17. data/test/fixtures/bday_decode.vcard +3 -0
  18. data/test/fixtures/bday_decode_2.vcard +6 -0
  19. data/test/fixtures/empty_tel.vcard +3 -0
  20. data/test/fixtures/ex1.vcard +7 -0
  21. data/test/fixtures/ex2.vcard +9 -0
  22. data/test/fixtures/ex3.vcard +30 -0
  23. data/test/fixtures/ex_21.vcard +16 -0
  24. data/test/fixtures/ex_21_case0.vcard +15 -0
  25. data/test/fixtures/ex_apple1.vcard +13 -0
  26. data/test/fixtures/ex_attach.vcard +16 -0
  27. data/test/fixtures/ex_bdays.vcard +8 -0
  28. data/test/fixtures/ex_encode_1.vcard +10 -0
  29. data/test/fixtures/ex_ical_1.vcal +47 -0
  30. data/test/fixtures/gmail.vcard +27 -0
  31. data/test/fixtures/highrise.vcard +41 -0
  32. data/test/fixtures/multiple_occurences_of_type.vcard +17 -0
  33. data/test/fixtures/nickname0.vcard +2 -0
  34. data/test/fixtures/nickname1.vcard +3 -0
  35. data/test/fixtures/nickname2.vcard +3 -0
  36. data/test/fixtures/nickname3.vcard +3 -0
  37. data/test/fixtures/nickname4.vcard +4 -0
  38. data/test/fixtures/nickname5.vcard +5 -0
  39. data/test/fixtures/slash_in_field_name.vcard +3 -0
  40. data/test/fixtures/tst1.vcard +9 -0
  41. data/test/fixtures/url_decode.vcard +4 -0
  42. data/test/test_helper.rb +34 -6
  43. data/test/vcard_test.rb +87 -577
  44. data/vcard.gemspec +19 -0
  45. metadata +88 -43
  46. data/.document +0 -5
  47. data/README.rdoc +0 -7
  48. data/VERSION +0 -1
  49. data/lib/vcard/rfc2425.rb +0 -367
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'vcard/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "vcard"
8
+ gem.version = Vcard::VERSION
9
+ gem.authors = ["Kuba Kuźma"]
10
+ gem.email = ["kuba@jah.pl"]
11
+ gem.description = %q{Vcard extracted from Vpim}
12
+ gem.summary = %q{Vcard extracted from Vpim}
13
+ gem.homepage = "http://github.com/qoobaa/vcard"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
metadata CHANGED
@@ -1,73 +1,118 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: vcard
3
- version: !ruby/object:Gem::Version
4
- version: 0.1.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
5
6
  platform: ruby
6
- authors:
7
- - "Jakub Ku\xC5\xBAma"
7
+ authors:
8
+ - Kuba Kuźma
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
-
12
- date: 2009-10-20 00:00:00 +02:00
13
- default_executable:
12
+ date: 2012-11-26 00:00:00.000000000 Z
14
13
  dependencies: []
15
-
16
- description:
17
- email: qoobaa@gmail.com
14
+ description: Vcard extracted from Vpim
15
+ email:
16
+ - kuba@jah.pl
18
17
  executables: []
19
-
20
18
  extensions: []
21
-
22
- extra_rdoc_files:
23
- - LICENSE
24
- - README.rdoc
25
- files:
26
- - .document
19
+ extra_rdoc_files: []
20
+ files:
27
21
  - .gitignore
28
- - LICENSE
29
- - README.rdoc
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
30
25
  - Rakefile
31
- - VERSION
26
+ - VPIM-LICENSE.txt
32
27
  - lib/vcard.rb
33
28
  - lib/vcard/attachment.rb
29
+ - lib/vcard/bnf.rb
34
30
  - lib/vcard/dirinfo.rb
35
31
  - lib/vcard/enumerator.rb
32
+ - lib/vcard/errors.rb
36
33
  - lib/vcard/field.rb
37
- - lib/vcard/rfc2425.rb
38
34
  - lib/vcard/vcard.rb
35
+ - lib/vcard/version.rb
39
36
  - test/field_test.rb
37
+ - test/fixtures/bday_decode.vcard
38
+ - test/fixtures/bday_decode_2.vcard
39
+ - test/fixtures/empty_tel.vcard
40
+ - test/fixtures/ex1.vcard
41
+ - test/fixtures/ex2.vcard
42
+ - test/fixtures/ex3.vcard
43
+ - test/fixtures/ex_21.vcard
44
+ - test/fixtures/ex_21_case0.vcard
45
+ - test/fixtures/ex_apple1.vcard
46
+ - test/fixtures/ex_attach.vcard
47
+ - test/fixtures/ex_bdays.vcard
48
+ - test/fixtures/ex_encode_1.vcard
49
+ - test/fixtures/ex_ical_1.vcal
50
+ - test/fixtures/gmail.vcard
51
+ - test/fixtures/highrise.vcard
52
+ - test/fixtures/multiple_occurences_of_type.vcard
53
+ - test/fixtures/nickname0.vcard
54
+ - test/fixtures/nickname1.vcard
55
+ - test/fixtures/nickname2.vcard
56
+ - test/fixtures/nickname3.vcard
57
+ - test/fixtures/nickname4.vcard
58
+ - test/fixtures/nickname5.vcard
59
+ - test/fixtures/slash_in_field_name.vcard
60
+ - test/fixtures/tst1.vcard
61
+ - test/fixtures/url_decode.vcard
40
62
  - test/test_helper.rb
41
63
  - test/vcard_test.rb
42
- has_rdoc: true
64
+ - vcard.gemspec
43
65
  homepage: http://github.com/qoobaa/vcard
44
66
  licenses: []
45
-
46
67
  post_install_message:
47
- rdoc_options:
48
- - --charset=UTF-8
49
- require_paths:
68
+ rdoc_options: []
69
+ require_paths:
50
70
  - lib
51
- required_ruby_version: !ruby/object:Gem::Requirement
52
- requirements:
53
- - - ">="
54
- - !ruby/object:Gem::Version
55
- version: "0"
56
- version:
57
- required_rubygems_version: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: "0"
62
- version:
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
63
83
  requirements: []
64
-
65
84
  rubyforge_project:
66
- rubygems_version: 1.3.5
85
+ rubygems_version: 1.8.24
67
86
  signing_key:
68
87
  specification_version: 3
69
- summary: Vcard support extracted from Vpim (Ruby 1.9.1 compatible)
70
- test_files:
88
+ summary: Vcard extracted from Vpim
89
+ test_files:
71
90
  - test/field_test.rb
91
+ - test/fixtures/bday_decode.vcard
92
+ - test/fixtures/bday_decode_2.vcard
93
+ - test/fixtures/empty_tel.vcard
94
+ - test/fixtures/ex1.vcard
95
+ - test/fixtures/ex2.vcard
96
+ - test/fixtures/ex3.vcard
97
+ - test/fixtures/ex_21.vcard
98
+ - test/fixtures/ex_21_case0.vcard
99
+ - test/fixtures/ex_apple1.vcard
100
+ - test/fixtures/ex_attach.vcard
101
+ - test/fixtures/ex_bdays.vcard
102
+ - test/fixtures/ex_encode_1.vcard
103
+ - test/fixtures/ex_ical_1.vcal
104
+ - test/fixtures/gmail.vcard
105
+ - test/fixtures/highrise.vcard
106
+ - test/fixtures/multiple_occurences_of_type.vcard
107
+ - test/fixtures/nickname0.vcard
108
+ - test/fixtures/nickname1.vcard
109
+ - test/fixtures/nickname2.vcard
110
+ - test/fixtures/nickname3.vcard
111
+ - test/fixtures/nickname4.vcard
112
+ - test/fixtures/nickname5.vcard
113
+ - test/fixtures/slash_in_field_name.vcard
114
+ - test/fixtures/tst1.vcard
115
+ - test/fixtures/url_decode.vcard
72
116
  - test/test_helper.rb
73
117
  - test/vcard_test.rb
118
+ has_rdoc:
data/.document DELETED
@@ -1,5 +0,0 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
@@ -1,7 +0,0 @@
1
- = vcard
2
-
3
- Description goes here.
4
-
5
- == Copyright
6
-
7
- Copyright (c) 2009 Jakub Kuźma. See LICENSE for details.
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.1.1
@@ -1,367 +0,0 @@
1
- =begin
2
- Copyright (C) 2008 Sam Roberts
3
-
4
- This library is free software; you can redistribute it and/or modify it
5
- under the same terms as the ruby language itself, see the file COPYING for
6
- details.
7
- =end
8
-
9
- require "date"
10
-
11
- module Vpim
12
- # Contains regular expression strings for the EBNF of RFC 2425.
13
- module Bnf #:nodoc:
14
-
15
- # 1*(ALPHA / DIGIT / "-")
16
- # Note: I think I can add A-Z here, and get rid of the "i" matches elsewhere.
17
- # Note: added '_' to allowed because its produced by Notes (X-LOTUS-CHILD_UID:)
18
- # Note: added '/' to allowed because its produced by KAddressBook (X-messaging/xmpp-All:)
19
- # Note: added ' ' to allowed because its produced by highrisehq.com (X-GOOGLE TALK:)
20
- NAME = '[-a-z0-9_/][-a-z0-9_/ ]*'
21
-
22
- # <"> <Any character except CTLs, DQUOTE> <">
23
- QSTR = '"([^"]*)"'
24
-
25
- # *<Any character except CTLs, DQUOTE, ";", ":", ",">
26
- PTEXT = '([^";:,]+)'
27
-
28
- # param-value = ptext / quoted-string
29
- PVALUE = "(?:#{QSTR}|#{PTEXT})"
30
-
31
- # param = name "=" param-value *("," param-value)
32
- # Note: v2.1 allows a type or encoding param-value to appear without the type=
33
- # or the encoding=. This is hideous, but we try and support it, if there
34
- # is no "=", then $2 will be "", and we will treat it as a v2.1 param.
35
- PARAM = ";(#{NAME})(=?)((?:#{PVALUE})?(?:,#{PVALUE})*)"
36
-
37
- # V3.0: contentline = [group "."] name *(";" param) ":" value
38
- # V2.1: contentline = *( group "." ) name *(";" param) ":" value
39
- #
40
- # We accept the V2.1 syntax for backwards compatibility.
41
- #LINE = "((?:#{NAME}\\.)*)?(#{NAME})([^:]*)\:(.*)"
42
- LINE = "^((?:#{NAME}\\.)*)?(#{NAME})((?:#{PARAM})*):(.*)$"
43
-
44
- # date = date-fullyear ["-"] date-month ["-"] date-mday
45
- # date-fullyear = 4 DIGIT
46
- # date-month = 2 DIGIT
47
- # date-mday = 2 DIGIT
48
- DATE = '(\d\d\d\d)-?(\d\d)-?(\d\d)'
49
-
50
- # time = time-hour [":"] time-minute [":"] time-second [time-secfrac] [time-zone]
51
- # time-hour = 2 DIGIT
52
- # time-minute = 2 DIGIT
53
- # time-second = 2 DIGIT
54
- # time-secfrac = "," 1*DIGIT
55
- # time-zone = "Z" / time-numzone
56
- # time-numzone = sign time-hour [":"] time-minute
57
- TIME = '(\d\d):?(\d\d):?(\d\d)(\.\d+)?(Z|[-+]\d\d:?\d\d)?'
58
-
59
- # integer = (["+"] / "-") 1*DIGIT
60
- INTEGER = '[-+]?\d+'
61
-
62
- # QSAFE-CHAR = WSP / %x21 / %x23-7E / NON-US-ASCII
63
- # ; Any character except CTLs and DQUOTE
64
- QSAFECHAR = '[ \t\x21\x23-\x7e\x80-\xff]'
65
-
66
- # SAFE-CHAR = WSP / %x21 / %x23-2B / %x2D-39 / %x3C-7E / NON-US-ASCII
67
- # ; Any character except CTLs, DQUOTE, ";", ":", ","
68
- SAFECHAR = '[ \t\x21\x23-\x2b\x2d-\x39\x3c-\x7e\x80-\xff]'
69
- end
70
- end
71
-
72
- module Vpim
73
- # Split on \r\n or \n to get the lines, unfold continued lines (they
74
- # start with ' ' or \t), and return the array of unfolded lines.
75
- #
76
- # This also supports the (invalid) encoding convention of allowing empty
77
- # lines to be inserted for readability - it does this by dropping zero-length
78
- # lines.
79
- def Vpim.unfold(card) #:nodoc:
80
- unfolded = []
81
-
82
- card.lines do |line|
83
- line.chomp!
84
- # If it's a continuation line, add it to the last.
85
- # If it's an empty line, drop it from the input.
86
- if( line =~ /^[ \t]/ )
87
- unfolded[-1] << line[1, line.size-1]
88
- elsif( line =~ /^$/ )
89
- else
90
- unfolded << line
91
- end
92
- end
93
-
94
- unfolded
95
- end
96
-
97
- # Convert a +sep+-seperated list of values into an array of values.
98
- def Vpim.decode_list(value, sep = ',') # :nodoc:
99
- list = []
100
-
101
- value.split(sep).each do |item|
102
- item.chomp!(sep)
103
- list << yield(item)
104
- end
105
- list
106
- end
107
-
108
- # Convert a RFC 2425 date into an array of [year, month, day].
109
- def Vpim.decode_date(v) # :nodoc:
110
- unless v =~ %r{^\s*#{Bnf::DATE}\s*$}
111
- raise Vpim::InvalidEncodingError, "date not valid (#{v})"
112
- end
113
- [$1.to_i, $2.to_i, $3.to_i]
114
- end
115
-
116
- # Convert a RFC 2425 date into a Date object.
117
- def self.decode_date_to_date(v)
118
- Date.new(*decode_date(v))
119
- end
120
-
121
- # Note in the following the RFC2425 allows yyyy-mm-ddThh:mm:ss, but RFC2445
122
- # does not. I choose to encode to the subset that is valid for both.
123
-
124
- # Encode a Date object as "yyyymmdd".
125
- def Vpim.encode_date(d) # :nodoc:
126
- "%0.4d%0.2d%0.2d" % [ d.year, d.mon, d.day ]
127
- end
128
-
129
- # Encode a Date object as "yyyymmdd".
130
- def Vpim.encode_time(d) # :nodoc:
131
- "%0.4d%0.2d%0.2d" % [ d.year, d.mon, d.day ]
132
- end
133
-
134
- # Encode a Time or DateTime object as "yyyymmddThhmmss"
135
- def Vpim.encode_date_time(d) # :nodoc:
136
- "%0.4d%0.2d%0.2dT%0.2d%0.2d%0.2d" % [ d.year, d.mon, d.day, d.hour, d.min, d.sec ]
137
- end
138
-
139
- # Convert a RFC 2425 time into an array of [hour,min,sec,secfrac,timezone]
140
- def Vpim.decode_time(v) # :nodoc:
141
- unless match = %r{^\s*#{Bnf::TIME}\s*$}.match(v)
142
- raise Vpim::InvalidEncodingError, "time '#{v}' not valid"
143
- end
144
- hour, min, sec, secfrac, tz = match.to_a[1..5]
145
-
146
- [hour.to_i, min.to_i, sec.to_i, secfrac ? secfrac.to_f : 0, tz]
147
- end
148
-
149
- def self.array_datetime_to_time(dtarray) #:nodoc:
150
- # We get [ year, month, day, hour, min, sec, usec, tz ]
151
- begin
152
- tz = (dtarray.pop == "Z") ? :gm : :local
153
- Time.send(tz, *dtarray)
154
- rescue ArgumentError => e
155
- raise Vpim::InvalidEncodingError, "#{tz} #{e} (#{dtarray.join(', ')})"
156
- end
157
- end
158
-
159
- # Convert a RFC 2425 time into an array of Time objects.
160
- def Vpim.decode_time_to_time(v) # :nodoc:
161
- array_datetime_to_time(decode_date_time(v))
162
- end
163
-
164
- # Convert a RFC 2425 date-time into an array of [year,mon,day,hour,min,sec,secfrac,timezone]
165
- def Vpim.decode_date_time(v) # :nodoc:
166
- unless match = %r{^\s*#{Bnf::DATE}T#{Bnf::TIME}\s*$}.match(v)
167
- raise Vpim::InvalidEncodingError, "date-time '#{v}' not valid"
168
- end
169
- year, month, day, hour, min, sec, secfrac, tz = match.to_a[1..8]
170
-
171
- [
172
- # date
173
- year.to_i, month.to_i, day.to_i,
174
- # time
175
- hour.to_i, min.to_i, sec.to_i, secfrac ? secfrac.to_f : 0, tz
176
- ]
177
- end
178
-
179
- def Vpim.decode_date_time_to_datetime(v) #:nodoc:
180
- year, month, day, hour, min, sec, secfrac, tz = Vpim.decode_date_time(v)
181
- # TODO - DateTime understands timezones, so we could decode tz and use it.
182
- DateTime.civil(year, month, day, hour, min, sec, 0)
183
- end
184
-
185
- # Vpim.decode_boolean
186
- #
187
- # float
188
- #
189
- # float_list
190
- =begin
191
- =end
192
-
193
- # Convert an RFC2425 INTEGER value into an Integer
194
- def Vpim.decode_integer(v) # :nodoc:
195
- unless match = %r{\s*#{Bnf::INTEGER}\s*}.match(v)
196
- raise Vpim::InvalidEncodingError, "integer not valid (#{v})"
197
- end
198
- v.to_i
199
- end
200
-
201
- #
202
- # integer_list
203
-
204
- # Convert a RFC2425 date-list into an array of dates.
205
- def Vpim.decode_date_list(v) # :nodoc:
206
- Vpim.decode_list(v) do |date|
207
- date.strip!
208
- if date.length > 0
209
- Vpim.decode_date(date)
210
- end
211
- end.compact
212
- end
213
-
214
- # Convert a RFC 2425 time-list into an array of times.
215
- def Vpim.decode_time_list(v) # :nodoc:
216
- Vpim.decode_list(v) do |time|
217
- time.strip!
218
- if time.length > 0
219
- Vpim.decode_time(time)
220
- end
221
- end.compact
222
- end
223
-
224
- # Convert a RFC 2425 date-time-list into an array of date-times.
225
- def Vpim.decode_date_time_list(v) # :nodoc:
226
- Vpim.decode_list(v) do |datetime|
227
- datetime.strip!
228
- if datetime.length > 0
229
- Vpim.decode_date_time(datetime)
230
- end
231
- end.compact
232
- end
233
-
234
- # Convert RFC 2425 text into a String.
235
- # \\ -> \
236
- # \n -> NL
237
- # \N -> NL
238
- # \, -> ,
239
- # \; -> ;
240
- #
241
- # I've seen double-quote escaped by iCal.app. Hmm. Ok, if you aren't supposed
242
- # to escape anything but the above, everything else is ambiguous, so I'll
243
- # just support it.
244
- def Vpim.decode_text(v) # :nodoc:
245
- # FIXME - I think this should trim leading and trailing space
246
- v.gsub(/\\(.)/) do
247
- case $1
248
- when 'n', 'N'
249
- "\n"
250
- else
251
- $1
252
- end
253
- end
254
- end
255
-
256
- def Vpim.encode_text(v) #:nodoc:
257
- v.to_str.gsub(/([\\,;\n])/) { $1 == "\n" ? "\\n" : "\\"+$1 }
258
- end
259
-
260
- # v is an Array of String, or just a single String
261
- def Vpim.encode_text_list(v, sep = ",") #:nodoc:
262
- begin
263
- v.to_ary.map{ |t| Vpim.encode_text(t) }.join(sep)
264
- rescue
265
- Vpim.encode_text(v)
266
- end
267
- end
268
-
269
- # Convert a +sep+-seperated list of TEXT values into an array of values.
270
- def Vpim.decode_text_list(value, sep = ',') # :nodoc:
271
- # Need to do in two stages, as best I can find.
272
- list = value.scan(/([^#{sep}\\]*(?:\\.[^#{sep}\\]*)*)#{sep}/).map do |v|
273
- Vpim.decode_text(v.first)
274
- end
275
- if value.match(/([^#{sep}\\]*(?:\\.[^#{sep}\\]*)*)$/)
276
- list << $1
277
- end
278
- list
279
- end
280
-
281
- # param-value = paramtext / quoted-string
282
- # paramtext = *SAFE-CHAR
283
- # quoted-string = DQUOTE *QSAFE-CHAR DQUOTE
284
- def Vpim.encode_paramtext(value)
285
- case value
286
- when %r{\A#{Bnf::SAFECHAR}*\z}
287
- value
288
- else
289
- raise Vpim::Unencodable, "paramtext #{value.inspect}"
290
- end
291
- end
292
-
293
- def Vpim.encode_paramvalue(value)
294
- case value
295
- when %r{\A#{Bnf::SAFECHAR}*\z}
296
- value
297
- when %r{\A#{Bnf::QSAFECHAR}*\z}
298
- '"' + value + '"'
299
- else
300
- raise Vpim::Unencodable, "param-value #{value.inspect}"
301
- end
302
- end
303
-
304
-
305
- # Unfold the lines in +card+, then return an array of one Field object per
306
- # line.
307
- def Vpim.decode(card) #:nodoc:
308
- content = Vpim.unfold(card).collect { |line| DirectoryInfo::Field.decode(line) }
309
- end
310
-
311
-
312
- # Expand an array of fields into its syntactic entities. Each entity is a sequence
313
- # of fields where the sequences is delimited by a BEGIN/END field. Since
314
- # BEGIN/END delimited entities can be nested, we build a tree. Each entry in
315
- # the array is either a Field or an array of entries (where each entry is
316
- # either a Field, or an array of entries...).
317
- def Vpim.expand(src) #:nodoc:
318
- # output array to expand the src to
319
- dst = []
320
- # stack used to track our nesting level, as we see begin/end we start a
321
- # new/finish the current entity, and push/pop that entity from the stack
322
- current = [ dst ]
323
-
324
- for f in src
325
- if f.name? 'BEGIN'
326
- e = [ f ]
327
-
328
- current.last.push(e)
329
- current.push(e)
330
-
331
- elsif f.name? 'END'
332
- current.last.push(f)
333
-
334
- unless current.last.first.value? current.last.last.value
335
- raise "BEGIN/END mismatch (#{current.last.first.value} != #{current.last.last.value})"
336
- end
337
-
338
- current.pop
339
-
340
- else
341
- current.last.push(f)
342
- end
343
- end
344
-
345
- dst
346
- end
347
-
348
- # Split an array into an array of all the fields at the outer level, and
349
- # an array of all the inner arrays of fields. Return the array [outer,
350
- # inner].
351
- def Vpim.outer_inner(fields) #:nodoc:
352
- # TODO - use Enumerable#partition
353
- # seperate into the outer-level fields, and the arrays of component
354
- # fields
355
- outer = []
356
- inner = []
357
- fields.each do |line|
358
- case line
359
- when Array; inner << line
360
- else; outer << line
361
- end
362
- end
363
- return outer, inner
364
- end
365
-
366
- end
367
-