vcardigan 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module VCardigan
2
+ EncodingError = Class.new(StandardError)
3
+ end
@@ -0,0 +1,17 @@
1
+ module VCardigan
2
+
3
+ class NameProperty < Property
4
+
5
+ def setup
6
+ @values = ['', '', '', '', '']
7
+ end
8
+
9
+ private
10
+
11
+ def add_value(value, idx)
12
+ @values[idx] = value if value
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,222 @@
1
+ module VCardigan
2
+
3
+ class Property
4
+
5
+ APPLE_LABEL = /_\$!<(.*?)>!\$_/
6
+
7
+ attr_accessor :group
8
+ attr_reader :name
9
+ attr_reader :params
10
+ attr_reader :values
11
+
12
+ def initialize(vcard, name, *args)
13
+ @vcard = vcard
14
+ @params = {}
15
+ @values = []
16
+ @group = nil
17
+
18
+ setup if respond_to? :setup
19
+
20
+ # Determine whether this property name has a group
21
+ name_parts = name.to_s.split('.', 2)
22
+
23
+ # If it has a group, set it
24
+ if name_parts.length > 1
25
+ @group = name_parts.first
26
+ end
27
+
28
+ # Set the name
29
+ @name = name_parts.last.downcase
30
+
31
+ # Build out the values/params from the passed arguments
32
+ valueIdx = 0
33
+ args.each do |arg|
34
+ if arg.is_a? Hash
35
+ arg.each do |param, value|
36
+ param = param_name(param.to_s.downcase, value)
37
+ value = param_value(param, value)
38
+ add_param(param, value)
39
+ end
40
+ else
41
+ value = parse_value(arg.to_s)
42
+ add_value(value, valueIdx)
43
+ valueIdx += 1
44
+ end
45
+ end
46
+ end
47
+
48
+ def self.create(vcard, name, *args)
49
+ name = name.to_s.downcase
50
+ classname = ''
51
+
52
+ case name
53
+ when 'n'
54
+ className = 'NameProperty'
55
+ else
56
+ className = 'Property'
57
+ end
58
+
59
+ cls = Module.const_get('VCardigan').const_get(className)
60
+ cls.new(vcard, name, *args)
61
+ end
62
+
63
+ def self.parse(vcard, data)
64
+ # Gather the parts
65
+ data = data.strip
66
+ parts = data.split(':', 2)
67
+ values = parts.last.split(';')
68
+ params = parts.first.split(';')
69
+ name = params.shift
70
+
71
+ # Create argument array
72
+ args = [vcard, name]
73
+
74
+ # Add values to array
75
+ args.concat(values)
76
+
77
+ # Add params to array
78
+ params.each do |param|
79
+ keyval = param.split('=')
80
+ hash = Hash[keyval.first, keyval.last]
81
+ args.push(hash)
82
+ end
83
+
84
+ # Instantiate a new class with the argument array
85
+ self.create(*args)
86
+ end
87
+
88
+ def value(idx = 0)
89
+ @values[idx]
90
+ end
91
+
92
+ def param(name)
93
+ name ? @params[name.to_s.downcase] : nil
94
+ end
95
+
96
+ def to_s
97
+ # Name/Group
98
+ name = @name.upcase
99
+ property = @group ? "#{@group}.#{name}" : name.upcase
100
+
101
+ # Params
102
+ @params.each do |param, value|
103
+ str = param_to_s(param, value)
104
+ property << ';' << str if str
105
+ end
106
+
107
+ # Split with colon
108
+ property << ':'
109
+
110
+ # Values
111
+ @values.each_with_index do |value, idx|
112
+ property << ';' unless idx === 0
113
+ property << value
114
+ end
115
+
116
+ line_fold(property)
117
+ end
118
+
119
+ private
120
+
121
+ def version
122
+ @vcard.version
123
+ end
124
+
125
+ def v3?
126
+ version == '3.0'
127
+ end
128
+
129
+ def v4?
130
+ version == '4.0'
131
+ end
132
+
133
+ def param_name(name, value)
134
+ case name
135
+ when 'type'
136
+ if value == 'pref'
137
+ name = 'preferred'
138
+ end
139
+ when 'pref'
140
+ name = 'preferred'
141
+ end
142
+ name
143
+ end
144
+
145
+ def param_value(name, value)
146
+ case name
147
+ when 'preferred'
148
+ value = value.to_s
149
+ number = value.to_i
150
+ if number > 0
151
+ value = number
152
+ else
153
+ value = nil if value.downcase == 'false' or value == '0'
154
+ value = 1 if value
155
+ end
156
+ end
157
+ value
158
+ end
159
+
160
+ def parse_value(value)
161
+ # Parse Apple labels
162
+ match = value.match(APPLE_LABEL)
163
+ if match
164
+ value = match[1]
165
+ end
166
+ value
167
+ end
168
+
169
+ def add_value(value, idx)
170
+ @values.push(value)
171
+ end
172
+
173
+ def add_param(name, value)
174
+ name = name.to_s.downcase
175
+ if @params[name]
176
+ # Create array of param values if we have an existing param name
177
+ # present in the hash
178
+ unless @params[name].is_a? Array
179
+ @params[name] = [@params[name]]
180
+ end
181
+ @params[name].push(value)
182
+ else
183
+ # Default is to just set the param to the value
184
+ @params[name] = value
185
+ end
186
+ end
187
+
188
+ def param_to_s(name, value)
189
+ case name
190
+ when 'preferred'
191
+ if !value or value === 0
192
+ return nil
193
+ end
194
+ name = v3? ? 'type' : 'pref'
195
+ value = v3? ? 'pref' : value.is_a?(Numeric) ? value : 1
196
+ else
197
+ end
198
+ value = value.to_s
199
+ name.upcase << '=' << value unless value.empty?
200
+ end
201
+
202
+ def line_fold(string)
203
+ chars = @vcard.chars
204
+ if chars == 0
205
+ out = string
206
+ else
207
+ out = ''
208
+ while string.length > 0
209
+ if string.length >= chars
210
+ amount = out.empty? ? chars : chars - 1
211
+ out += "#{string.slice!(0, amount)}\n "
212
+ else
213
+ out += string.slice!(0, string.length)
214
+ end
215
+ end
216
+ end
217
+ out
218
+ end
219
+
220
+ end
221
+
222
+ end
@@ -0,0 +1,165 @@
1
+ module VCardigan
2
+
3
+ class VCard
4
+
5
+ VCARD_PATTERN = /BEGIN:VCARD\s+(.*?)VERSION:(.+?)\s+(.+?)END:VCARD/m;
6
+
7
+ attr_accessor :version
8
+ attr_accessor :chars
9
+
10
+ def initialize(options = {})
11
+ # Backwards compatibility
12
+ if options.is_a? String
13
+ options = { :version => options }
14
+ end
15
+
16
+ # Default options
17
+ @version = options[:version] || '4.0'
18
+ @chars = options[:chars] || 75
19
+
20
+ @fields = {}
21
+ @groups = {}
22
+ @group = nil
23
+ end
24
+
25
+ def parse(data)
26
+ match = VCARD_PATTERN.match(data)
27
+ if match
28
+ # Set version number
29
+ @version = match[2]
30
+ lines = "#{match[1].strip}#{match[3].strip}"
31
+
32
+ # Add the parsed properties to this vCard
33
+ lines.each_line do |line|
34
+ property = VCardigan::Property.parse(self, line)
35
+ add_prop(property)
36
+ end
37
+ end
38
+ self
39
+ end
40
+
41
+ def [](group)
42
+ @group = group
43
+ self
44
+ end
45
+
46
+ def method_missing(method, *args)
47
+ if args.empty?
48
+ # Return the field property/properties when no arguments are passed
49
+ field(method)
50
+ else
51
+ # Add property to vCard
52
+ add(method, *args)
53
+ end
54
+ end
55
+
56
+ def add(name, *args)
57
+ if @group
58
+ # If there's a group, add it to the name
59
+ name = "#{@group}.#{name}"
60
+
61
+ # Reset group to nil
62
+ @group = nil
63
+ end
64
+
65
+ # Build the property and add it to the vCard
66
+ property = build_prop(name, *args)
67
+ add_prop(property)
68
+ end
69
+
70
+ def field(name)
71
+ name = name.to_s.downcase
72
+ if @group and @fields[name]
73
+ # Finds all items that match the prop type in the group
74
+ fields = @fields[name].find_all do |prop|
75
+ prop.group == @group.to_s
76
+ end
77
+
78
+ # Reset the group to nil and return the fields
79
+ @group = nil
80
+ fields
81
+ else
82
+ @fields[name]
83
+ end
84
+ end
85
+
86
+ def group(name)
87
+ @groups[name]
88
+ end
89
+
90
+ def to_s
91
+ # Raise errors if invalid
92
+ validate
93
+
94
+ # Start vCard
95
+ vcard = build_prop(:begin, 'VCARD').to_s << "\n"
96
+
97
+ # Add version
98
+ vcard << build_prop(:version, @version).to_s << "\n"
99
+
100
+ # Add the properties
101
+ @fields.each do |field, properties|
102
+ properties.each do |property|
103
+ vcard << property.to_s << "\n"
104
+ end
105
+ end
106
+
107
+ # END
108
+ vcard << build_prop(:end, 'VCARD').to_s << "\n"
109
+
110
+ # Return vCard
111
+ return vcard
112
+ end
113
+
114
+ # Aliases ##########
115
+
116
+ def name(*args)
117
+ n(*args)
118
+ end
119
+
120
+ def fullname(*args)
121
+ fn(*args)
122
+ end
123
+
124
+ # Private ##########
125
+ private
126
+
127
+ def build_prop(name, *args)
128
+ VCardigan::Property.create(self, name, *args)
129
+ end
130
+
131
+ def add_prop(property)
132
+ name = property.name
133
+ group = property.group
134
+
135
+ # Create a field on the fields hash, if not already present, to house
136
+ # the property
137
+ unless @fields.has_key? name
138
+ @fields[name] = []
139
+ end
140
+
141
+ # Add the property to the field array
142
+ @fields[name].push(property)
143
+
144
+ if group
145
+ # Add a field on the groups hash, if not already present, to house the
146
+ # group properties
147
+ unless @groups.has_key? group
148
+ @groups[group] = []
149
+ end
150
+
151
+ # Add the property to the groups array
152
+ @groups[group].push(property)
153
+ end
154
+ end
155
+
156
+ def validate
157
+ unless @fields['fn']
158
+ raise VCardigan::EncodingError,
159
+ "vCards must include an FN field"
160
+ end
161
+ end
162
+
163
+ end
164
+
165
+ end
@@ -0,0 +1,5 @@
1
+ module VCardigan
2
+
3
+ VERSION = '0.0.2'
4
+
5
+ end
data/lib/vcardigan.rb ADDED
@@ -0,0 +1,21 @@
1
+ require_relative 'vcardigan/version'
2
+ require_relative 'vcardigan/vcard'
3
+ require_relative 'vcardigan/property'
4
+ require_relative 'vcardigan/properties/name_property'
5
+ require_relative 'vcardigan/errors'
6
+
7
+ module VCardigan
8
+
9
+ class << self
10
+
11
+ def create(*args)
12
+ VCardigan::VCard.new(*args)
13
+ end
14
+
15
+ def parse(*args)
16
+ VCardigan::VCard.new.parse(*args)
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,122 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe VCardigan::Property do
4
+
5
+ describe '#init' do
6
+ let(:vcard) { VCardigan.create }
7
+
8
+ context 'without a group' do
9
+ let(:name) { :email }
10
+ let(:value) { 'joe@strummer.com' }
11
+ let(:params) { { :type => 'uri' } }
12
+ let(:prop) { VCardigan::Property.create(vcard, name, value, params) }
13
+
14
+ it 'should set the name' do
15
+ prop.name.should == name.to_s.downcase
16
+ end
17
+
18
+ it 'should set the value' do
19
+ prop.values.first.should == value
20
+ end
21
+ end
22
+ end
23
+
24
+ describe '#values' do
25
+ let(:vcard) { VCardigan.create }
26
+ let(:name) { :email }
27
+ let(:value) { 'joe@strummer.com' }
28
+ let(:prop) { VCardigan::Property.create(vcard, name, value) }
29
+
30
+ it 'should return the values array' do
31
+ prop.values.should == prop.instance_variable_get(:@values)
32
+ end
33
+ end
34
+
35
+ describe '#value' do
36
+ let(:vcard) { VCardigan.create }
37
+ let(:name) { :n }
38
+ let(:value1) { 'Strummer' }
39
+ let(:value2) { 'Joe' }
40
+ let(:prop) { VCardigan::Property.create(vcard, name, value1, value2) }
41
+
42
+ context 'without an index' do
43
+ it 'should return the first item from the values array' do
44
+ prop.value.should == prop.instance_variable_get(:@values).first
45
+ end
46
+ end
47
+
48
+ context 'with an index' do
49
+ it 'should return the item corresponding to the index' do
50
+ prop.value(1).should == prop.instance_variable_get(:@values)[1]
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#params' do
56
+ let(:vcard) { VCardigan.create }
57
+ let(:name) { :email }
58
+ let(:value) { 'joe@strummer.com' }
59
+ let(:params) { { :type => 'uri' } }
60
+ let(:prop) { VCardigan::Property.create(vcard, name, value, params) }
61
+
62
+ it 'should return the params array' do
63
+ prop.params.should == prop.instance_variable_get(:@params)
64
+ end
65
+ end
66
+
67
+ describe '#param' do
68
+ let(:vcard) { VCardigan.create }
69
+ let(:name) { :email }
70
+ let(:value) { 'joe@strummer.com' }
71
+ let(:params) { { :type => 'uri' } }
72
+ let(:prop) { VCardigan::Property.create(vcard, name, value, params) }
73
+
74
+ context 'with a param that exists' do
75
+ it 'should return the param' do
76
+ prop.param(:type).should == params[:type]
77
+ end
78
+ end
79
+
80
+ context 'with a param that does not exist' do
81
+ it 'should return nil' do
82
+ prop.param(:random).should == nil
83
+ end
84
+ end
85
+ end
86
+
87
+ describe '#to_s' do
88
+ let(:vcard) { VCardigan.create }
89
+ let(:name) { :email }
90
+ let(:group) { :item1 }
91
+ let(:value) { 'joe@strummer.com' }
92
+ let(:params) { { :type => 'uri' } }
93
+ let(:prop) { VCardigan::Property.create(vcard, "#{group}.#{name}", value, params) }
94
+
95
+ it 'should return the property vCard formatted' do
96
+ prop.to_s.should == "#{group}.#{name.upcase};TYPE=#{params[:type]}:#{value}"
97
+ end
98
+ end
99
+
100
+ describe '#parse' do
101
+ let(:vcard) { VCardigan.create }
102
+ let(:name) { :email }
103
+ let(:group) { :item1 }
104
+ let(:value) { 'joe@strummer.com' }
105
+ let(:params) { { :type => 'uri' } }
106
+ let(:string) { "#{group}.#{name.upcase};TYPE=#{params[:type]}:#{value}" }
107
+ let(:prop) { VCardigan::Property.parse(vcard, string) }
108
+
109
+ it 'should set the group' do
110
+ prop.group.should == group.to_s.downcase
111
+ end
112
+
113
+ it 'should set the name' do
114
+ prop.name.should == name.to_s.downcase
115
+ end
116
+
117
+ it 'should set the values' do
118
+ prop.values.should == [value]
119
+ end
120
+ end
121
+
122
+ end
@@ -0,0 +1,250 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe VCardigan::VCard do
4
+
5
+ describe '#init' do
6
+ context 'no options' do
7
+ let(:vcard) { VCardigan.create }
8
+
9
+ it 'should set default version' do
10
+ vcard.version.should == '4.0'
11
+ end
12
+
13
+ it 'should set default line char limit' do
14
+ vcard.chars.should == 75
15
+ end
16
+ end
17
+
18
+ context 'version number for args (backward compat)' do
19
+ let(:version) { '3.0' }
20
+ let(:vcard) { VCardigan.create(version) }
21
+
22
+ it 'should set version' do
23
+ vcard.version.should == version
24
+ end
25
+ end
26
+
27
+ context 'passed options args' do
28
+ let(:version) { '3.0' }
29
+ let(:chars) { 100 }
30
+ let(:vcard) { VCardigan.create(:version => version, :chars => chars) }
31
+
32
+ it 'should set version' do
33
+ vcard.version.should == version
34
+ end
35
+
36
+ it 'should set line char limit' do
37
+ vcard.chars.should == chars
38
+ end
39
+ end
40
+ end
41
+
42
+ describe '#[]' do
43
+ let(:group) { :item1 }
44
+ let(:vcard) { VCardigan.create }
45
+
46
+ before do
47
+ vcard[group]
48
+ end
49
+
50
+ it 'should return vcard' do
51
+ vcard.should be_an_instance_of(VCardigan::VCard)
52
+ end
53
+
54
+ it 'should set group' do
55
+ vcard.instance_variable_get(:@group).should == group
56
+ end
57
+ end
58
+
59
+ describe '#add' do
60
+ let(:name) { :email }
61
+ let(:value) { 'joe@strummer.com' }
62
+ let(:vcard) { VCardigan.create }
63
+ let(:fields) { vcard.instance_variable_get(:@fields) }
64
+
65
+ context 'with no group' do
66
+ before do
67
+ vcard.add(name, value)
68
+ end
69
+
70
+ it 'should add field name (as string) to fields hash' do
71
+ fields.should have_key(name.to_s)
72
+ end
73
+
74
+ it 'should create array on field name' do
75
+ fields[name.to_s].should be_an_instance_of(Array)
76
+ end
77
+
78
+ it 'should have single item in array' do
79
+ fields[name.to_s].length.should == 1
80
+ end
81
+
82
+ it 'should add property to field name array' do
83
+ fields[name.to_s].first.should be_an_instance_of(VCardigan::Property)
84
+ end
85
+ end
86
+
87
+ context 'with group' do
88
+ let(:group) { :item1 }
89
+ let(:groups) { vcard.instance_variable_get(:@groups) }
90
+
91
+ before do
92
+ vcard[group].add(name, value)
93
+ end
94
+
95
+ it 'should add group name (as string) to groups hash' do
96
+ groups.should have_key(group.to_s)
97
+ end
98
+
99
+ it 'should create array on group name' do
100
+ groups[group.to_s].should be_an_instance_of(Array)
101
+ end
102
+
103
+ it 'should have single item in array' do
104
+ groups[group.to_s].length.should == 1
105
+ end
106
+
107
+ it 'should add property group name array' do
108
+ groups[group.to_s].first.should be_an_instance_of(VCardigan::Property)
109
+ end
110
+ end
111
+ end
112
+
113
+ describe '#method_missing' do
114
+ let(:vcard) { VCardigan.create }
115
+
116
+ context 'with args' do
117
+ let(:name) { :email }
118
+ let(:email) { 'joe@strummer.com' }
119
+ let(:params) { { :type => 'uri' } }
120
+
121
+ it 'should call #add' do
122
+ vcard.should_receive(:add).with(name, email, params)
123
+ vcard.send(name, email, params)
124
+ end
125
+ end
126
+
127
+ context 'without args' do
128
+ let(:name) { :email }
129
+
130
+ it 'should call #field' do
131
+ vcard.should_receive(:field).with(name)
132
+ vcard.send(name)
133
+ end
134
+ end
135
+ end
136
+
137
+ describe '#field' do
138
+ let(:vcard) { VCardigan.create }
139
+ let(:fields) { vcard.instance_variable_get(:@fields) }
140
+ let(:name) { :email }
141
+ let(:value) { 'joe@strummer.com' }
142
+
143
+ context 'no group' do
144
+ before do
145
+ vcard.send(name, value)
146
+ end
147
+
148
+ it 'should return field name array' do
149
+ vcard.field(name).should == fields[name.to_s]
150
+ end
151
+
152
+ it 'should have correct property in array' do
153
+ vcard.field(name).first.value.should == value
154
+ end
155
+ end
156
+
157
+ context 'with group' do
158
+ let(:group) { :item1 }
159
+ let(:value2) { 'joestrummer@strummer.com' }
160
+
161
+ before do
162
+ vcard.send(name, value)
163
+ vcard[group].send(name, value2)
164
+ end
165
+
166
+ it 'should return field name array with props within group' do
167
+ vcard[group].field(name).should == fields[name.to_s].find_all do |prop|
168
+ prop.group == group.to_s
169
+ end
170
+ end
171
+
172
+ it 'should have correct property in array' do
173
+ vcard[group].field(name).first.value.should == value2
174
+ end
175
+ end
176
+ end
177
+
178
+ describe 'Aliases' do
179
+ let(:vcard) { VCardigan.create }
180
+
181
+ context '#name' do
182
+ it 'should call method_missing with method n' do
183
+ vcard.should_receive(:method_missing).with(:n)
184
+ vcard.name
185
+ end
186
+ end
187
+
188
+ context '#fullname' do
189
+ it 'should call method_missing with method fn' do
190
+ vcard.should_receive(:method_missing).with(:fn)
191
+ vcard.fullname
192
+ end
193
+ end
194
+ end
195
+
196
+ describe '#to_s' do
197
+ let(:vcard) { VCardigan.create }
198
+
199
+ context 'with no FN' do
200
+ it 'should raise an error' do
201
+ expect { vcard.to_s }.to raise_error(VCardigan::EncodingError)
202
+ end
203
+ end
204
+
205
+ context 'with an FN and N' do
206
+ before do
207
+ vcard.name('Strummer', 'Joe')
208
+ vcard.fullname('Joe Strummer')
209
+ end
210
+
211
+ it 'should have BEGIN on first line' do
212
+ vcard.to_s.split("\n").first.should == 'BEGIN:VCARD'
213
+ end
214
+
215
+ it 'should proceed with VERSION' do
216
+ vcard.to_s.split("\n")[1].should == 'VERSION:4.0'
217
+ end
218
+
219
+ it 'should include the N field' do
220
+ vcard.to_s.split("\n")[2].should == 'N:Strummer;Joe;;;'
221
+ end
222
+
223
+ it 'should include the FN field' do
224
+ vcard.to_s.split("\n")[3].should == 'FN:Joe Strummer'
225
+ end
226
+
227
+ it 'should end with END' do
228
+ vcard.to_s.split("\n").last.should == 'END:VCARD'
229
+ end
230
+ end
231
+ end
232
+
233
+ describe '#parse' do
234
+ context 'valid 4.0 vCard' do
235
+ let(:data) { File.read(File.dirname(__FILE__) + '/../helpers/joe.vcf') }
236
+ let(:vcard) { VCardigan.parse(data) }
237
+ let(:fields) { vcard.instance_variable_get(:@fields) }
238
+
239
+ it 'should set the version' do
240
+ vcard.version.should == '4.0'
241
+ end
242
+
243
+ it 'should add the properties to the fields array' do
244
+ fields.should have_key('n')
245
+ fields.should have_key('fn')
246
+ end
247
+ end
248
+ end
249
+
250
+ end
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + '/../lib/vcardigan'
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vcardigan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matt Morgan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.0'
30
+ description: vCardigan is a ruby library for building and parsing vCards that supports
31
+ both v3.0 and v4.0.
32
+ email: matt@mlmorg.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - lib/vcardigan/errors.rb
38
+ - lib/vcardigan/properties/name_property.rb
39
+ - lib/vcardigan/property.rb
40
+ - lib/vcardigan/vcard.rb
41
+ - lib/vcardigan/version.rb
42
+ - lib/vcardigan.rb
43
+ - spec/examples/property_spec.rb
44
+ - spec/examples/vcard_spec.rb
45
+ - spec/spec_helper.rb
46
+ homepage: http://github.com/brewster/vcardigan
47
+ licenses:
48
+ - MIT
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ requirements: []
66
+ rubyforge_project:
67
+ rubygems_version: 1.8.24
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: Ruby vCard Builder/Parser
71
+ test_files:
72
+ - spec/examples/property_spec.rb
73
+ - spec/examples/vcard_spec.rb
74
+ - spec/spec_helper.rb