vcard_parser 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ Gemfile.lock
5
+ coverage/
6
+ doc/
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ bundler_args: --without development
2
+ rvm:
3
+ - 1.9.3
4
+
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
6
+
7
+ group(:development) do
8
+ gem 'simplecov'
9
+ gem 'guard-bacon', '~> 1.1.0'
10
+ gem 'rb-fsevent'
11
+ gem 'growl'
12
+ end
13
+
14
+ group(:test) do
15
+ gem 'schmurfy-bacon', '~> 1.4.2'
16
+ gem 'mocha', '~> 0.10.0'
17
+ end
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+
2
+ # parameters:
3
+ # output => the formatted to use
4
+ # backtrace => number of lines, nil = everything
5
+ guard 'bacon', :output => "BetterOutput", :backtrace => nil do
6
+ watch(%r{^lib/vcard_parser/(.+)\.rb$}) { |m| "specs/unit/#{m[1]}_spec.rb" }
7
+ watch(%r{specs/.+\.rb$})
8
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Julien Ammous
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+
2
+ # What ?
3
+
4
+ This is a vCard parser/generator released under te MIT license
5
+
6
+ # Support
7
+ For now only v3.0 is supported and the testing was done mostly with Apple
8
+ Addressbook and iOS contacts.
9
+
10
+ # Continuous integration ([![Build Status](https://secure.travis-ci.org/schmurfy/vcard_parser.png)](https://secure.travis-ci.org/schmurfy/vcard_parser.png))
11
+
12
+ This gem is tested against these ruby by travis-ci.org:
13
+
14
+ - mri 1.9.3
15
+
16
+ # Usage
17
+
18
+ ```ruby
19
+ require 'vcard_parser'
20
+
21
+ cards = VCardParser:parse(...)
22
+
23
+ puts cards[0].fields
24
+ puts cards[0]['N']
25
+
26
+ # dump back the vcard
27
+ puts cards[0].to_s
28
+ ```
29
+
30
+ # Setting up development environmeent
31
+
32
+ ```bash
33
+ # clone the repository and:
34
+ $ bundle
35
+ $ bundle exec guard
36
+ ```
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require "bundler/gem_tasks"
4
+
5
+ task :default => :test
6
+
7
+ task :test do
8
+ require 'bacon'
9
+
10
+ # do not generate coverage report from travis
11
+ unless ENV['TRAVIS']
12
+ ENV['COVERAGE'] = "1"
13
+ end
14
+
15
+ Dir[File.expand_path('../specs/**/*_spec.rb', __FILE__)].each do |file|
16
+ puts "File: #{file}:"
17
+ load(file)
18
+ end
19
+
20
+ end
21
+
@@ -0,0 +1,4 @@
1
+ require_relative 'vcard_parser/version'
2
+ require_relative 'vcard_parser/vcard'
3
+
4
+ require_relative 'vcard_parser/3.0/field'
@@ -0,0 +1,83 @@
1
+ require 'time'
2
+
3
+ module VCardParser
4
+ module V30
5
+
6
+ class Field
7
+ attr_reader :name, :group, :value, :params
8
+
9
+ FORMAT = /^
10
+ (?:(?<group>[a-zA-Z0-9-]+)\.)?
11
+ (?<name>[a-zA-Z-]+)
12
+ (?<params> (?:;[A-Za-z]+=[^;]+)+ )?
13
+ :(?<value>.*)
14
+ $/x
15
+
16
+ def initialize(name, value, group = nil, params = {})
17
+ @name = name
18
+ @group = group
19
+ @value = convert_value(value)
20
+ @params = params
21
+ end
22
+
23
+ def full_name
24
+ ret = ""
25
+ ret << "#{@group}." if group
26
+ ret << @name
27
+ ret
28
+ end
29
+
30
+ def self.parse(line)
31
+ m = FORMAT.match(line.strip)
32
+ if m
33
+ params = {}
34
+ if m[:params]
35
+ m[:params].split(';').reject{|s| s.empty? }.each do |p|
36
+ pname, pvalue = p.split('=')
37
+ params[pname] ||= []
38
+ params[pname] << pvalue
39
+ end
40
+ end
41
+
42
+ new(m[:name], m[:value], m[:group], params)
43
+ else
44
+ raise MalformedInput, line
45
+ end
46
+ end
47
+
48
+ def to_s
49
+ ret = full_name
50
+
51
+ @params.each do |name, values|
52
+ values.each do |v|
53
+ ret << ";#{name}=#{v}"
54
+ end
55
+ end
56
+
57
+ ret << ":#{dump_value(value)}"
58
+
59
+ ret
60
+ end
61
+
62
+ private
63
+ def convert_value(value)
64
+ case name
65
+ when "REV", "BDAY" then Time.parse(value)
66
+ else
67
+ value
68
+ end
69
+ end
70
+
71
+ def dump_value(value)
72
+ case name
73
+ when "REV" then value.iso8601
74
+ when "BDAY" then value.strftime("%Y-%m-%d")
75
+ else
76
+ value
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,93 @@
1
+ module VCardParser
2
+ ParsingError = Class.new(RuntimeError)
3
+
4
+ UnsupportedVersion = Class.new(ParsingError)
5
+ MalformedInput = Class.new(ParsingError)
6
+
7
+ class VCard
8
+ attr_reader :version, :fields
9
+
10
+ VCARD_FORMAT = /
11
+ BEGIN:VCARD\s+
12
+ (.+?)
13
+ END:VCARD\s*
14
+ /xm
15
+
16
+ def initialize(version, fields = [])
17
+ @version = version
18
+ @fields = fields
19
+ end
20
+
21
+ def self.parse(data)
22
+ data.scan(VCARD_FORMAT).map do |vcard_data|
23
+ # fetch the version to choose the correct parser
24
+ lines = vcard_data[0].each_line.map(&:strip)
25
+
26
+ key, version = lines[0].split(':')
27
+ if key != "VERSION"
28
+ raise MalformedInput, "VERSION expected, got #{key}"
29
+ end
30
+
31
+ # remove begin and version
32
+ lines.slice!(0, 1)
33
+
34
+ new(version).tap do |card|
35
+ lines.each do |line|
36
+ card.add_field_from_string(line)
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+
43
+ def add_field_from_string(line)
44
+ f = field_class.parse(line)
45
+ @fields << f
46
+ end
47
+
48
+ def add_field(*args)
49
+ f = field_class.new(*args)
50
+ @fields << f
51
+ end
52
+
53
+ def values(key, group = nil)
54
+ @fields.select do |f|
55
+ (f.name == key) &&
56
+ (!group || (f.group == group))
57
+ end
58
+ end
59
+
60
+ def [](key, group = nil)
61
+ v = values(key, group)
62
+ v.empty? ? nil : v[0]
63
+ end
64
+
65
+ def each_field(&block)
66
+ @fields.each(&block)
67
+ end
68
+
69
+ def vcard
70
+ ret = ["BEGIN:VCARD", "VERSION:#{@version}"]
71
+
72
+ @fields.each do |f|
73
+ ret << f.to_s
74
+ end
75
+
76
+ ret << "END:VCARD\n"
77
+ ret.join("\n")
78
+ end
79
+
80
+ alias :to_s :vcard
81
+
82
+
83
+ private
84
+ def field_class
85
+ @field_class ||= case version
86
+ when '3.0' then V30::Field
87
+ else
88
+ raise UnsupportedVersion, version
89
+ end
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,3 @@
1
+ module VcardParser
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,21 @@
1
+ BEGIN:VCARD
2
+ VERSION:3.0
3
+ PRODID:-//Apple Inc.//iOS 5.0.1//EN
4
+ N:Durand;Christophe;;;
5
+ FN:Christophe Durand
6
+ ORG:Op;
7
+ item1.TEL;type=pref:2 56 38 54
8
+ item2.TEL;type=pref:5 66
9
+ TEL;type=CELL;type=VOICE:3 55
10
+ item2.ADR;type=HOME;type=pref:;;3 rue du chat;Dris;;90880;FRANCE
11
+ BDAY;value=date:1900-01-01
12
+ REV:2012-10-31T16:08:22Z
13
+ UID:11
14
+ END:VCARD
15
+ END:VCARD
16
+ BEGIN:VCARD
17
+ VERSION:3.0
18
+ N:Jean;René;;;
19
+ FN:Jean René
20
+ UID:12
21
+ END:VCARD
@@ -0,0 +1,15 @@
1
+ BEGIN:VCARD
2
+ VERSION:2.1
3
+ N:Gump;Forrest
4
+ FN:Forrest Gump
5
+ ORG:Bubba Gump Shrimp Co.
6
+ TITLE:Shrimp Man
7
+ TEL;WORK;VOICE:(111) 555-1212
8
+ TEL;HOME;VOICE:(404) 555-1212
9
+ ADR;WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
10
+ LABEL;WORK;ENCODING=QUOTED-PRINTABLE:100 Waters Edge=0D=0ABaytown, LA 30314=0D=0AUnited States of America
11
+ ADR;HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
12
+ LABEL;HOME;ENCODING=QUOTED-PRINTABLE:42 Plantation St.=0D=0ABaytown, LA 30314=0D=0AUnited States of America
13
+ EMAIL;PREF;INTERNET:forrestgump@example.com
14
+ REV:20080424T195243Z
15
+ END:VCARD
@@ -0,0 +1,14 @@
1
+ BEGIN:VCARD
2
+ VERSION:3.0
3
+ PRODID:-//Apple Inc.//iOS 5.0.1//EN
4
+ N:Durand;Christophe;;;
5
+ FN:Christophe Durand
6
+ ORG:Op;
7
+ item1.TEL;type=pref:2 56 38 54
8
+ item2.TEL;type=pref:5 66
9
+ TEL;type=CELL;type=VOICE:3 55
10
+ item2.ADR;type=HOME;type=pref:;;3 rue du chat;Dris;;90880;FRANCE
11
+ BDAY;value=date:1900-01-01
12
+ REV:2012-10-31T16:08:22Z
13
+ UID:11
14
+ END:VCARD
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'bacon'
5
+
6
+ if ENV['COVERAGE']
7
+ Bacon.allow_focused_run = false
8
+
9
+ require 'simplecov'
10
+ SimpleCov.start do
11
+ add_filter ".*_spec"
12
+ add_filter "/helpers/"
13
+ end
14
+
15
+ end
16
+
17
+ $LOAD_PATH.unshift( File.expand_path('../../lib' , __FILE__) )
18
+ require 'vcard_parser'
19
+
20
+ # require 'bacon/ext/mocha'
21
+ # require 'bacon/ext/em'
22
+
23
+ # Thread.abort_on_exception = true
24
+
25
+ Bacon.summary_on_exit()
@@ -0,0 +1,76 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe 'Field 3.0' do
4
+ should 'parse grouped field' do
5
+ f = VCardParser::V30::Field.parse("item1.TEL;type=pref:1 24 54 36")
6
+ f.group.should == "item1"
7
+ f.name.should == "TEL"
8
+ f.value.should == "1 24 54 36"
9
+ f.params.should == {'type' => ['pref']}
10
+
11
+ f.full_name.should == "item1.TEL"
12
+ end
13
+
14
+ should 'parse empty field' do
15
+ f = VCardParser::V30::Field.parse("FN:")
16
+ f.group.should == nil
17
+ f.name.should == "FN"
18
+ f.value.should == ""
19
+ f.params.should == {}
20
+ end
21
+
22
+ should 'parse extension field' do
23
+ f = VCardParser::V30::Field.parse("X-ABShowAs:COMPANY")
24
+ f.group.should == nil
25
+ f.name.should == "X-ABShowAs"
26
+ f.value.should == "COMPANY"
27
+ f.params.should == {}
28
+ end
29
+
30
+ should 'parse simple line' do
31
+ f = VCardParser::V30::Field.parse("PRODID:-//Apple Inc.//Mac OS X 10.8.2//EN")
32
+ f.group.should == nil
33
+ f.name.should == "PRODID"
34
+ f.value.should == "-//Apple Inc.//Mac OS X 10.8.2//EN"
35
+ f.params.should == {}
36
+ end
37
+
38
+ should 'parse dat field' do
39
+ f = VCardParser::V30::Field.parse("REV:2012-10-29T21:23:09Z")
40
+ f.group.should == nil
41
+ f.name.should == "REV"
42
+ f.value.should == Time.parse("2012-10-29T21:23:09Z")
43
+ f.params.should == {}
44
+ end
45
+
46
+ should 'parse line with parameters' do
47
+ f = VCardParser::V30::Field.parse("TEL;type=WORK;type=VOICE;type=pref:1234")
48
+ f.group.should == nil
49
+ f.name.should == "TEL"
50
+ f.value.should == "1234"
51
+ f.params.should == {
52
+ 'type' => %w(WORK VOICE pref)
53
+ }
54
+ end
55
+
56
+ should 'generate vcf line from data' do
57
+ line = "TEL;type=WORK;type=VOICE;type=pref:1234"
58
+ f = VCardParser::V30::Field.parse(line)
59
+ f.to_s.should == line
60
+ end
61
+
62
+ should 'generate vcf line from converted data' do
63
+ line = "REV:2012-10-29T21:23:09Z"
64
+ f = VCardParser::V30::Field.parse(line)
65
+ f.to_s.should == line
66
+ end
67
+
68
+ should 'generate vcf line from data with group' do
69
+ line = "item1.TEL;type=pref:1 24 54 36"
70
+ f = VCardParser::V30::Field.parse(line)
71
+ f.to_s.should == line
72
+ end
73
+
74
+
75
+
76
+ end
@@ -0,0 +1,190 @@
1
+ # encoding: utf-8
2
+ require_relative '../spec_helper'
3
+
4
+ def data_path(path)
5
+ File.expand_path(File.join(
6
+ File.expand_path('../../data', __FILE__),
7
+ path
8
+ ))
9
+ end
10
+
11
+ def data_file(path)
12
+ File.read( data_path(path) )
13
+ end
14
+
15
+ describe 'VCard' do
16
+
17
+ should 'add a new field without parameters' do
18
+ v = VCardParser::VCard.new("3.0")
19
+ v.add_field("N", "Georges")
20
+
21
+ v['N'].value.should == 'Georges'
22
+ end
23
+
24
+ describe 'vCard 3.0' do
25
+ should 'parse simple card' do
26
+ vcards = VCardParser::VCard.parse( data_file('vcard3.0.vcf') )
27
+ vcards.size.should == 1
28
+
29
+ vcards[0].version.should == "3.0"
30
+ vcards[0]["PRODID"].value.should == "-//Apple Inc.//iOS 5.0.1//EN"
31
+ vcards[0]["N"].value.should == "Durand;Christophe;;;"
32
+ vcards[0]["FN"].value.should == "Christophe Durand"
33
+ vcards[0]["UID"].value.should == "11"
34
+ end
35
+
36
+ should 'parse multiple cards' do
37
+ vcards = VCardParser::VCard.parse( data_file('two_vcard3.0.vcf') )
38
+ vcards.size.should == 2
39
+
40
+ vcards[0].version.should == "3.0"
41
+ vcards[0]["PRODID"].value.should == "-//Apple Inc.//iOS 5.0.1//EN"
42
+ vcards[0]["N"].value.should == "Durand;Christophe;;;"
43
+ vcards[0]["FN"].value.should == "Christophe Durand"
44
+ vcards[0]["UID"].value.should == "11"
45
+
46
+
47
+ vcards[1].version.should == "3.0"
48
+ vcards[1]["N"].value.should == "Jean;René;;;"
49
+ vcards[1]["FN"].value.should == "Jean René"
50
+ vcards[1]["UID"].value.should == "12"
51
+ end
52
+
53
+ should 'enumerate attributes' do
54
+ vcards = VCardParser::VCard.parse( data_file('vcard3.0.vcf') )
55
+ vcards.size.should == 1
56
+
57
+ attrs = []
58
+
59
+ vcards[0].each_field do |a|
60
+ attrs << a
61
+ end
62
+
63
+ attrs.size.should == 11
64
+ end
65
+
66
+ should 'enumerate attributes' do
67
+ vcards = VCardParser::VCard.parse( data_file('vcard3.0.vcf') )
68
+ vcards.size.should == 1
69
+
70
+ attrs = []
71
+
72
+ vcards[0].each_field.sort_by(&:name).each do |a|
73
+ attrs << a
74
+ end
75
+
76
+ attrs[0].tap do |a|
77
+ a.group.should == "item2"
78
+ a.name.should == "ADR"
79
+ a.value.should == ";;3 rue du chat;Dris;;90880;FRANCE"
80
+ a.params.should == {'type' => ['HOME', 'pref']}
81
+ end
82
+
83
+ attrs[1].tap do |a|
84
+ a.name.should == "BDAY"
85
+ a.value.should == Time.parse('1900-01-01')
86
+ a.params.should == {'value' => ['date']}
87
+ end
88
+
89
+
90
+ attrs[2].tap do |a|
91
+ a.name.should == "FN"
92
+ a.value.should == "Christophe Durand"
93
+ a.params.should == {}
94
+ end
95
+
96
+ attrs[3].tap do |a|
97
+ a.name.should == "N"
98
+ a.value.should == "Durand;Christophe;;;"
99
+ a.params.should == {}
100
+ end
101
+
102
+ attrs[4].tap do |a|
103
+ a.name.should == "ORG"
104
+ a.value.should == "Op;"
105
+ a.params.should == {}
106
+ end
107
+
108
+
109
+ attrs[5].tap do |a|
110
+ a.name.should == "PRODID"
111
+ a.value.should == "-//Apple Inc.//iOS 5.0.1//EN"
112
+ a.params.should == {}
113
+ end
114
+
115
+ attrs[6].tap do |a|
116
+ a.name.should == "REV"
117
+ a.value.should == Time.parse("2012-10-31T16:08:22Z")
118
+ a.params.should == {}
119
+ end
120
+
121
+ attrs[7].tap do |a|
122
+ a.group.should == nil
123
+ a.name.should == "TEL"
124
+ a.value.should == "3 55"
125
+ a.params.should == {'type' => %w(CELL VOICE)}
126
+ end
127
+
128
+ attrs[8].tap do |a|
129
+ a.group.should == "item1"
130
+ a.name.should == "TEL"
131
+ a.value.should == "2 56 38 54"
132
+ a.params.should == {'type' => %w(pref)}
133
+ end
134
+
135
+ attrs[9].tap do |a|
136
+ a.group.should == "item2"
137
+ a.name.should == "TEL"
138
+ a.value.should == "5 66"
139
+ a.params.should == {'type' => %w(pref)}
140
+ end
141
+
142
+
143
+ attrs[10].tap do |a|
144
+ a.name.should == "UID"
145
+ a.value.should == "11"
146
+ a.params.should == {}
147
+ end
148
+
149
+ end
150
+
151
+ should "raise an error if version is not supported" do
152
+ ->{
153
+ VCardParser::VCard.parse( data_file('vcard2.1.vcf') )
154
+ }.should.raise(VCardParser::UnsupportedVersion)
155
+ end
156
+
157
+
158
+ should 'parse and rebuild a full vcard' do
159
+ vcard_data = <<-EOS
160
+ BEGIN:VCARD
161
+ VERSION:3.0
162
+ PRODID:-//Apple Inc.//iOS 5.0.1//EN
163
+ N:Durand;Christophe;;;
164
+ FN:Christophe Durand
165
+ ORG:Op;
166
+ item1.TEL;type=pref:2 56 38 54
167
+ item2.TEL;type=pref:5 66
168
+ TEL;type=CELL;type=VOICE:3 55
169
+ item2.ADR;type=HOME;type=pref:;;3 rue du chat;Dris;;90880;FRANCE
170
+ BDAY;value=date:1900-01-01
171
+ REV:2012-10-31T16:08:22Z
172
+ UID:12
173
+ END:VCARD
174
+ EOS
175
+
176
+ cards = VCardParser::VCard.parse(vcard_data)
177
+ cards.size.should == 1
178
+ cards[0]['TEL', 'item1'].value.should == '2 56 38 54'
179
+ cards[0].to_s.should == vcard_data
180
+ end
181
+
182
+ should 'generate vcard from data' do
183
+ data = data_file('vcard3.0.vcf')
184
+ vcard = VCardParser::VCard.parse(data).first
185
+ vcard.vcard.should == data
186
+ vcard.to_s.should == data
187
+ end
188
+ end
189
+
190
+ end
@@ -0,0 +1,16 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/vcard_parser/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Julien Ammous"]
6
+ gem.email = ["schmurfy@gmail.com"]
7
+ gem.description = %q{A vCard parser}
8
+ gem.summary = %q{A simple vCard parser}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.name = "vcard_parser"
14
+ gem.require_paths = ["lib"]
15
+ gem.version = VcardParser::VERSION
16
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vcard_parser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Julien Ammous
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-02 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A vCard parser
15
+ email:
16
+ - schmurfy@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - .travis.yml
23
+ - Gemfile
24
+ - Guardfile
25
+ - LICENSE
26
+ - README.md
27
+ - Rakefile
28
+ - lib/vcard_parser.rb
29
+ - lib/vcard_parser/3.0/field.rb
30
+ - lib/vcard_parser/vcard.rb
31
+ - lib/vcard_parser/version.rb
32
+ - specs/data/two_vcard3.0.vcf
33
+ - specs/data/vcard2.1.vcf
34
+ - specs/data/vcard3.0.vcf
35
+ - specs/spec_helper.rb
36
+ - specs/unit/3.0/field_spec.rb
37
+ - specs/unit/vcard_spec.rb
38
+ - vcard_parser.gemspec
39
+ homepage: ''
40
+ licenses: []
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ segments:
52
+ - 0
53
+ hash: -4310828650863439750
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ segments:
61
+ - 0
62
+ hash: -4310828650863439750
63
+ requirements: []
64
+ rubyforge_project:
65
+ rubygems_version: 1.8.24
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: A simple vCard parser
69
+ test_files: []