kickboxer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +53 -0
- data/Rakefile +13 -0
- data/kickboxer.gemspec +21 -0
- data/lib/kickboxer.rb +5 -0
- data/lib/kickboxer/config.rb +19 -0
- data/lib/kickboxer/name.rb +118 -0
- data/lib/kickboxer/person.rb +67 -0
- data/lib/kickboxer/request.rb +44 -0
- data/lib/kickboxer/response.rb +49 -0
- data/lib/kickboxer/version.rb +3 -0
- data/spec/fixtures/name-deduce-email.json +14 -0
- data/spec/fixtures/name-normalize.json +26 -0
- data/spec/fixtures/name-parse.json +10 -0
- data/spec/fixtures/name-similarity.json +45 -0
- data/spec/fixtures/name-stats-ambiguous.json +64 -0
- data/spec/fixtures/name-stats-both.json +62 -0
- data/spec/fixtures/name-stats-family.json +12 -0
- data/spec/fixtures/name-stats-given.json +57 -0
- data/spec/fixtures/person-email.json +450 -0
- data/spec/fixtures/person-facebook.json +122 -0
- data/spec/fixtures/person-phone.json +410 -0
- data/spec/fixtures/person-twitter.json +231 -0
- data/spec/kickboxer/config_spec.rb +12 -0
- data/spec/kickboxer/name_spec.rb +141 -0
- data/spec/kickboxer/person_spec.rb +87 -0
- data/spec/kickboxer/request_spec.rb +24 -0
- data/spec/kickboxer/response_spec.rb +40 -0
- data/spec/spec_helper.rb +18 -0
- metadata +127 -0
@@ -0,0 +1,231 @@
|
|
1
|
+
{
|
2
|
+
"status": 200,
|
3
|
+
"contactInfo": {
|
4
|
+
"familyName": "Lorang",
|
5
|
+
"givenName": "Bart",
|
6
|
+
"fullName": "Bart Lorang",
|
7
|
+
"websites":
|
8
|
+
[
|
9
|
+
{
|
10
|
+
"url": "http://blog.fullcontact.com"
|
11
|
+
},
|
12
|
+
{
|
13
|
+
"url": "http://fullcontact.com"
|
14
|
+
}
|
15
|
+
]
|
16
|
+
},
|
17
|
+
"photos":
|
18
|
+
[
|
19
|
+
{
|
20
|
+
"typeName": "Twitter",
|
21
|
+
"type": "twitter",
|
22
|
+
"typeId": "twitter",
|
23
|
+
"url": "http://a0.twimg.com/profile_images/1364842224/Bart_Profile_1_normal.jpg"
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"url": "http://social.sxsw.com//system/badge_photos/46809/thumb/photo.jpg",
|
27
|
+
"type": "sxsw",
|
28
|
+
"typeId": "sxsw",
|
29
|
+
"typeName": "SxSW"
|
30
|
+
},
|
31
|
+
{
|
32
|
+
"typeName": "Facebook",
|
33
|
+
"type": "facebook",
|
34
|
+
"typeId": "facebook",
|
35
|
+
"url": "http://profile.ak.fbcdn.net/hprofile-ak-snc4/161274_651620441_7937905_n.jpg",
|
36
|
+
"isPrimary": true
|
37
|
+
},
|
38
|
+
{
|
39
|
+
"typeName": "Quora",
|
40
|
+
"type": "quora",
|
41
|
+
"typeId": "quora",
|
42
|
+
"url": "http://qph.cf.quoracdn.net/main-thumb-235179-50-jKTxWZQMbAl9MrGaLTDAs19WUiZoCuPW.jpeg"
|
43
|
+
},
|
44
|
+
{
|
45
|
+
"typeName": "Linkedin",
|
46
|
+
"type": "linkedin",
|
47
|
+
"typeId": "linkedin",
|
48
|
+
"url": "http://media.linkedin.com/mpr/pub/image-24YYLlk7VOVyx4vHbB2m_YZnM8tEVXNxn4NgrixwM2axoWjK24YgfwS7MnuP13NJifCJ/bart-lorang.jpg"
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"url": "http://qph.cf.quoracdn.net/main-thumb-235179-200-jKTxWZQMbAl9MrGaLTDAs19WUiZoCuPW.jpeg",
|
52
|
+
"type": "quora",
|
53
|
+
"typeId": "quora",
|
54
|
+
"typeName": "Quora"
|
55
|
+
},
|
56
|
+
{
|
57
|
+
"url": "http://media.linkedin.com/mpr/pub/image-8kD9yK95845PPSkQ3U3ryL0B2bTfOSKQ2EBfy9Si3h5FEh6_/bart-lorang.jpg",
|
58
|
+
"type": "linkedin",
|
59
|
+
"typeId": "linkedin",
|
60
|
+
"typeName": "Linkedin"
|
61
|
+
}
|
62
|
+
],
|
63
|
+
"demographics": {
|
64
|
+
"locationGeneral": "Boulder, Colorado",
|
65
|
+
"gender": "male"
|
66
|
+
},
|
67
|
+
"digitalFootprint": {
|
68
|
+
"topics":
|
69
|
+
[
|
70
|
+
{
|
71
|
+
"value": "angel investing",
|
72
|
+
"provider": "klout"
|
73
|
+
},
|
74
|
+
{
|
75
|
+
"value": "technology",
|
76
|
+
"provider": "klout"
|
77
|
+
},
|
78
|
+
{
|
79
|
+
"value": "denver broncos",
|
80
|
+
"provider": "klout"
|
81
|
+
},
|
82
|
+
{
|
83
|
+
"value": "tim tebow",
|
84
|
+
"provider": "klout"
|
85
|
+
},
|
86
|
+
{
|
87
|
+
"value": "sxsw",
|
88
|
+
"provider": "klout"
|
89
|
+
}
|
90
|
+
],
|
91
|
+
"scores":
|
92
|
+
[
|
93
|
+
{
|
94
|
+
"value": 48.41,
|
95
|
+
"provider": "klout",
|
96
|
+
"type": "general"
|
97
|
+
},
|
98
|
+
{
|
99
|
+
"value": 31.4,
|
100
|
+
"provider": "klout",
|
101
|
+
"type": "network"
|
102
|
+
},
|
103
|
+
{
|
104
|
+
"value": 978,
|
105
|
+
"provider": "klout",
|
106
|
+
"type": "reach"
|
107
|
+
},
|
108
|
+
{
|
109
|
+
"value": 21,
|
110
|
+
"provider": "klout",
|
111
|
+
"type": "amplification"
|
112
|
+
}
|
113
|
+
]
|
114
|
+
},
|
115
|
+
"socialProfiles":
|
116
|
+
[
|
117
|
+
{
|
118
|
+
"id": 5998422,
|
119
|
+
"typeName": "Twitter",
|
120
|
+
"following": 507,
|
121
|
+
"followers": 750,
|
122
|
+
"username": "lorangb",
|
123
|
+
"bio": "CEO & Co-Founder of @FullContactApp and @FullContactAPI - Tech Entrepreneur and Angel Investor.",
|
124
|
+
"type": "twitter",
|
125
|
+
"typeId": "twitter",
|
126
|
+
"url": "http://www.twitter.com/lorangb",
|
127
|
+
"rss": "http://twitter.com/statuses/user_timeline/lorangb.rss"
|
128
|
+
},
|
129
|
+
{
|
130
|
+
"type": "sxsw",
|
131
|
+
"url": "http://social.sxsw.com/users/46809",
|
132
|
+
"id": 46809,
|
133
|
+
"typeId": "sxsw",
|
134
|
+
"typeName": "SxSW"
|
135
|
+
},
|
136
|
+
{
|
137
|
+
"typeName": "Klout",
|
138
|
+
"username": "lorangb",
|
139
|
+
"type": "klout",
|
140
|
+
"typeId": "klout",
|
141
|
+
"url": "http://www.klout.com/lorangb"
|
142
|
+
},
|
143
|
+
{
|
144
|
+
"url": "http://www.myspace.com/137200880",
|
145
|
+
"type": "myspace",
|
146
|
+
"typeId": "myspace",
|
147
|
+
"typeName": "Myspace"
|
148
|
+
},
|
149
|
+
{
|
150
|
+
"url": "http://www.facebook.com/bartlorang",
|
151
|
+
"username": "bartlorang",
|
152
|
+
"type": "facebook",
|
153
|
+
"typeId": "facebook",
|
154
|
+
"typeName": "Facebook",
|
155
|
+
"id": "651620441"
|
156
|
+
},
|
157
|
+
{
|
158
|
+
"typeName": "About Me",
|
159
|
+
"username": "lorangb",
|
160
|
+
"type": "aboutme",
|
161
|
+
"typeId": "aboutme",
|
162
|
+
"url": "http://about.me/lorangb"
|
163
|
+
},
|
164
|
+
{
|
165
|
+
"typeName": "Flickr",
|
166
|
+
"id": "39267654@N00",
|
167
|
+
"rss": "http://api.flickr.com/services/feeds/photos_public.gne?id=39267654@N00&lang=en-us&format=rss_200",
|
168
|
+
"type": "flickr",
|
169
|
+
"typeId": "flickr",
|
170
|
+
"url": "http://www.flickr.com/photos/39267654@N00/"
|
171
|
+
},
|
172
|
+
{
|
173
|
+
"typeName": "Quora",
|
174
|
+
"username": "bart-lorang",
|
175
|
+
"type": "quora",
|
176
|
+
"typeId": "quora",
|
177
|
+
"url": "http://www.quora.com/bart-lorang"
|
178
|
+
},
|
179
|
+
{
|
180
|
+
"typeName": "Linkedin",
|
181
|
+
"username": "bartlorang",
|
182
|
+
"type": "linkedin",
|
183
|
+
"typeId": "linkedin",
|
184
|
+
"url": "http://www.linkedin.com/in/bartlorang"
|
185
|
+
},
|
186
|
+
{
|
187
|
+
"typeName": "Foursquare",
|
188
|
+
"username": "lorangb",
|
189
|
+
"type": "foursquare",
|
190
|
+
"typeId": "foursquare",
|
191
|
+
"url": "http://foursquare.com/lorangb"
|
192
|
+
},
|
193
|
+
{
|
194
|
+
"typeName": "Google Profile",
|
195
|
+
"username": "lorangb",
|
196
|
+
"type": "googleprofile",
|
197
|
+
"typeId": "googleprofile",
|
198
|
+
"url": "http://profiles.google.com/lorangb"
|
199
|
+
},
|
200
|
+
{
|
201
|
+
"typeName": "Youtube",
|
202
|
+
"username": "rainmaker0MakeitRain",
|
203
|
+
"type": "youtube",
|
204
|
+
"typeId": "youtube",
|
205
|
+
"url": "http://youtube.com/user/rainmaker0MakeitRain",
|
206
|
+
"rss": "http://youtube.com/rss/user/lorangb/videos.rss"
|
207
|
+
},
|
208
|
+
{
|
209
|
+
"typeName": "Plancast",
|
210
|
+
"id": "1634762",
|
211
|
+
"username": "lorangb",
|
212
|
+
"type": "plancast",
|
213
|
+
"typeId": "plancast",
|
214
|
+
"url": "http://plancast.com/user/1634762"
|
215
|
+
},
|
216
|
+
{
|
217
|
+
"typeName": "Tungle Me",
|
218
|
+
"type": "tungleme",
|
219
|
+
"typeId": "tungleme",
|
220
|
+
"url": "http://tungle.me/bartlorang"
|
221
|
+
}
|
222
|
+
],
|
223
|
+
"organizations":
|
224
|
+
[
|
225
|
+
{
|
226
|
+
"name": "FullContact",
|
227
|
+
"title": "CEO",
|
228
|
+
"isPrimary": true
|
229
|
+
}
|
230
|
+
]
|
231
|
+
}
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'kickboxer/name'
|
3
|
+
|
4
|
+
describe Kickboxer::Name do
|
5
|
+
it 'returns a normalized name' do
|
6
|
+
stub_response('name-normalize')
|
7
|
+
response = Kickboxer::Name.normalize('Mr. John (Johnny) Michael Smith Jr.')
|
8
|
+
|
9
|
+
response.status_code.should eq 200
|
10
|
+
response.status_text.should eq 'OK'
|
11
|
+
|
12
|
+
response.likelihood.should eq 0.815
|
13
|
+
response.region.should eq 'USA'
|
14
|
+
|
15
|
+
details = response.nameDetails
|
16
|
+
details.givenName.should eq 'John'
|
17
|
+
details.familyName.should eq 'Smith'
|
18
|
+
details.middleNames.should eq %w( Michael )
|
19
|
+
details.prefixes.should eq %w( Mr. )
|
20
|
+
details.suffixes.should eq %w( Jr. )
|
21
|
+
details.nicknames.should eq %w( Johnny )
|
22
|
+
details.fullName.should eq 'John Michael Smith'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'deduces real name from email' do
|
26
|
+
stub_response('name-deduce-email')
|
27
|
+
response = Kickboxer::Name.deduce(email: 'johndsmith79@gmail.com')
|
28
|
+
|
29
|
+
response.status_code.should eq 200
|
30
|
+
response.status_text.should eq 'OK'
|
31
|
+
|
32
|
+
response.likelihood.should eq 0.665
|
33
|
+
response.region.should eq 'USA'
|
34
|
+
|
35
|
+
details = response.nameDetails
|
36
|
+
details.givenName.should eq 'John'
|
37
|
+
details.familyName.should eq 'Smith'
|
38
|
+
details.middleNames.should eq %w( D. )
|
39
|
+
details.fullName.should eq 'John D. Smith'
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'calculates the similarity between two names' do
|
43
|
+
stub_response('name-similarity')
|
44
|
+
response = Kickboxer::Name.similarity('john', 'johnathan')
|
45
|
+
|
46
|
+
response.status_code.should eq 200
|
47
|
+
response.status_text.should eq 'OK'
|
48
|
+
|
49
|
+
result = response.result
|
50
|
+
sim_metrics = result.SimMetrics
|
51
|
+
|
52
|
+
jaro_winkler = sim_metrics.jaroWinkler
|
53
|
+
sprintf('%.4f', jaro_winkler.similarity).should eq '0.8889'
|
54
|
+
sprintf('%.4f', jaro_winkler.timeEstimated).should eq '0.0016'
|
55
|
+
jaro_winkler.timeActual.should eq 0
|
56
|
+
|
57
|
+
levenshtein = sim_metrics.levenshtein
|
58
|
+
sprintf('%.4f', levenshtein.similarity).should eq '0.4444'
|
59
|
+
sprintf('%.4f', levenshtein.timeEstimated).should eq '0.0065'
|
60
|
+
levenshtein.timeActual.should eq 0
|
61
|
+
|
62
|
+
second_string = result.SecondString
|
63
|
+
|
64
|
+
jaro_winkler = second_string.jaroWinkler
|
65
|
+
sprintf('%.4f', jaro_winkler.similarity).should eq '0.8889'
|
66
|
+
jaro_winkler.timeTaken.should eq "1 ms"
|
67
|
+
|
68
|
+
result.FullContact.BigramAnalysis.dice.similarity.should eq 0.5454545455
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'returns statistics for an ambiguous name' do
|
72
|
+
stub_response('name-stats-ambiguous')
|
73
|
+
response = Kickboxer::Name.stats(name: 'john')
|
74
|
+
|
75
|
+
response.status_code.should eq 200
|
76
|
+
response.status_text.should eq 'OK'
|
77
|
+
|
78
|
+
response.name.given.likelihood.should eq 0.992
|
79
|
+
response.name.given.rank.should eq 3
|
80
|
+
response.name.given.male.likelihood.should eq 0.996
|
81
|
+
response.name.given.female.likelihood.should eq 0.004
|
82
|
+
|
83
|
+
response.name.family.likelihood.should eq 0.008
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'returns statistics for a given name' do
|
87
|
+
stub_response('name-stats-given')
|
88
|
+
response = Kickboxer::Name.stats(givenName: 'john')
|
89
|
+
|
90
|
+
response.status_code.should eq 200
|
91
|
+
response.status_text.should eq 'OK'
|
92
|
+
|
93
|
+
response.name.given.should_not respond_to(:likelihood)
|
94
|
+
response.name.given.rank.should eq 3
|
95
|
+
response.name.given.male.likelihood.should eq 0.996
|
96
|
+
response.name.given.female.likelihood.should eq 0.004
|
97
|
+
|
98
|
+
response.name.should_not respond_to(:family)
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'returns statistics for a family name' do
|
102
|
+
stub_response('name-stats-family')
|
103
|
+
response = Kickboxer::Name.stats(familyName: 'smith')
|
104
|
+
|
105
|
+
response.status_code.should eq 200
|
106
|
+
response.status_text.should eq 'OK'
|
107
|
+
|
108
|
+
response.name.family.should_not respond_to(:likelihood)
|
109
|
+
response.name.family.rank.should eq 1
|
110
|
+
|
111
|
+
response.name.should_not respond_to(:given)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'returns statistics for given and family name' do
|
115
|
+
stub_response('name-stats-both')
|
116
|
+
response = Kickboxer::Name.stats(givenName: 'john', familyName: 'smith')
|
117
|
+
|
118
|
+
response.status_code.should eq 200
|
119
|
+
response.status_text.should eq 'OK'
|
120
|
+
|
121
|
+
response.name.family.should_not respond_to(:likelihood)
|
122
|
+
response.name.family.rank.should eq 1
|
123
|
+
|
124
|
+
response.name.given.should_not respond_to(:likelihood)
|
125
|
+
response.name.given.rank.should eq 3
|
126
|
+
response.name.given.male.likelihood.should eq 0.996
|
127
|
+
response.name.given.female.likelihood.should eq 0.004
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'parses full name strings into given and family names' do
|
131
|
+
stub_response('name-parse')
|
132
|
+
response = Kickboxer::Name.parse('john smith')
|
133
|
+
|
134
|
+
response.status_code.should eq 200
|
135
|
+
response.status_text.should eq 'OK'
|
136
|
+
|
137
|
+
response.result.givenName.should eq 'John'
|
138
|
+
response.result.familyName.should eq 'Smith'
|
139
|
+
response.result.likelihood.should eq 1
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'kickboxer/person'
|
3
|
+
|
4
|
+
describe Kickboxer::Person do
|
5
|
+
it 'looks up a person by email address' do
|
6
|
+
stub_response('person-email')
|
7
|
+
response = Kickboxer::Person.find_by_email('bart@fullcontact.com')
|
8
|
+
|
9
|
+
response.status_code.should eq 200
|
10
|
+
response.contactInfo.familyName.should eq 'Lorang'
|
11
|
+
response.contactInfo.givenName.should eq 'Bart'
|
12
|
+
response.contactInfo.websites.length.should eq 4
|
13
|
+
response.contactInfo.chats.length.should eq 2
|
14
|
+
response.photos.length.should eq 26
|
15
|
+
response.demographics.age.should eq '32'
|
16
|
+
response.demographics.locationGeneral.should eq 'Boulder, Colorado'
|
17
|
+
response.demographics.gender.should eq 'Male'
|
18
|
+
topics = response.digitalFootprint.topics.map{|topic| topic['value'] }
|
19
|
+
topics.should include 'entrepreneurship'
|
20
|
+
topics.should include 'tequila'
|
21
|
+
topics.should include 'tim tebow'
|
22
|
+
twitter = response.socialProfiles.detect{|p| p['type'] == 'twitter' }
|
23
|
+
twitter['url'].should eq 'http://www.twitter.com/lorangb'
|
24
|
+
organizations = response.organizations.map{|o| o['name'] }
|
25
|
+
organizations.should include 'FullContact'
|
26
|
+
organizations.should include 'Techstars'
|
27
|
+
organizations.should include 'Rainmaker Technologies'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'looks up a person by phone number' do
|
31
|
+
stub_response('person-phone')
|
32
|
+
response = Kickboxer::Person.find_by_phone_number('+13037170414')
|
33
|
+
|
34
|
+
response.status_code.should eq 200
|
35
|
+
response.contactInfo.familyName.should eq 'Lorang'
|
36
|
+
response.contactInfo.givenName.should eq 'Bart'
|
37
|
+
response.contactInfo.websites.length.should eq 5
|
38
|
+
response.contactInfo.chats.length.should eq 2
|
39
|
+
response.photos.length.should eq 24
|
40
|
+
response.demographics.age.should eq '32'
|
41
|
+
response.demographics.locationGeneral.should eq 'Denver, Colorado, United States'
|
42
|
+
response.demographics.gender.should eq 'male'
|
43
|
+
topics = response.digitalFootprint.topics.map{|topic| topic['value'] }
|
44
|
+
topics.should include 'entrepreneurship'
|
45
|
+
topics.should include 'tequila'
|
46
|
+
topics.should include 'tim tebow'
|
47
|
+
twitter = response.socialProfiles.detect{|p| p['type'] == 'twitter' }
|
48
|
+
twitter['url'].should eq 'http://www.twitter.com/lorangb'
|
49
|
+
organizations = response.organizations.map{|o| o['name'] }
|
50
|
+
organizations.should include 'FullContact'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'looks up a person by twitter username' do
|
54
|
+
stub_response('person-twitter')
|
55
|
+
response = Kickboxer::Person.find_by_twitter('lorangb')
|
56
|
+
|
57
|
+
response.status_code.should eq 200
|
58
|
+
response.contactInfo.familyName.should eq 'Lorang'
|
59
|
+
response.contactInfo.givenName.should eq 'Bart'
|
60
|
+
response.contactInfo.websites.length.should eq 2
|
61
|
+
response.photos.length.should eq 7
|
62
|
+
response.demographics.locationGeneral.should eq 'Boulder, Colorado'
|
63
|
+
response.demographics.gender.should eq 'male'
|
64
|
+
topics = response.digitalFootprint.topics.map{|topic| topic['value'] }
|
65
|
+
topics.should include 'angel investing'
|
66
|
+
topics.should include 'technology'
|
67
|
+
topics.should include 'tim tebow'
|
68
|
+
twitter = response.socialProfiles.detect{|p| p['type'] == 'twitter' }
|
69
|
+
twitter['url'].should eq 'http://www.twitter.com/lorangb'
|
70
|
+
organizations = response.organizations.map{|o| o['name'] }
|
71
|
+
organizations.should include 'FullContact'
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'looks up a person by facebook username' do
|
75
|
+
stub_response('person-facebook')
|
76
|
+
response = Kickboxer::Person.find_by_facebook('bart.lorang')
|
77
|
+
|
78
|
+
response.status_code.should eq 200
|
79
|
+
response.contactInfo.familyName.should eq 'Lorang'
|
80
|
+
response.contactInfo.givenName.should eq 'Bart'
|
81
|
+
response.contactInfo.websites.length.should eq 1
|
82
|
+
response.photos.length.should eq 3
|
83
|
+
response.demographics.gender.should eq 'male'
|
84
|
+
twitter = response.socialProfiles.detect{|p| p['type'] == 'twitter' }
|
85
|
+
twitter['url'].should eq 'http://twitter.com/lorangb'
|
86
|
+
end
|
87
|
+
end
|