kickboxer 0.0.1
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.
- 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
|