bizratr 0.0.5 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +5 -1
- data/README.rdoc +7 -3
- data/lib/bizratr/business.rb +25 -4
- data/lib/bizratr/connector.rb +80 -32
- data/lib/bizratr/version.rb +1 -1
- metadata +27 -16
data/Gemfile.lock
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
bizratr (0.0
|
4
|
+
bizratr (0.1.0)
|
5
5
|
factual-api
|
6
6
|
foursquare2
|
7
7
|
geocoder
|
8
8
|
google_places
|
9
9
|
google_places
|
10
|
+
koala
|
10
11
|
levenshtein
|
11
12
|
yelpster
|
12
13
|
|
@@ -32,6 +33,9 @@ GEM
|
|
32
33
|
multi_json (~> 1.0)
|
33
34
|
multi_xml
|
34
35
|
json (1.7.5)
|
36
|
+
koala (1.5.0)
|
37
|
+
faraday (~> 0.7)
|
38
|
+
multi_json (~> 1.3)
|
35
39
|
levenshtein (0.2.2)
|
36
40
|
multi_json (1.3.6)
|
37
41
|
multi_xml (0.5.1)
|
data/README.rdoc
CHANGED
@@ -1,20 +1,23 @@
|
|
1
1
|
= BizRatr
|
2
|
-
This gem pulls in business data from a variety of sources and synthesizes a singular view of the business. Right now Yelp, Factual, Google Places, and Foursquare are used as sources. Bizratr will collapse all of the matching sources into a singular view of each matching business.
|
2
|
+
This gem pulls in business data from a variety of sources and synthesizes a singular view of the business. Right now Facebook, Yelp, Factual, Google Places, and Foursquare are used as sources. Bizratr will collapse all of the matching sources into a singular view of each matching business.
|
3
3
|
|
4
4
|
>> require 'bizratr'
|
5
5
|
>> config = {
|
6
6
|
:foursquare => { :client_id => 'anid', :client_secret => 'asecret' },
|
7
7
|
:yelp => { :consumer_key => 'akey', :consumer_secret => 'asecret', :token => 'atoken', :token_secret => 'atokensecret' },
|
8
8
|
:google_places => { :key => "akey" },
|
9
|
-
:factual => { :key => 'akey', :secret => 'asecret' }
|
9
|
+
:factual => { :key => 'akey', :secret => 'asecret' },
|
10
|
+
:facebook => { :key => 'akey', :secret => 'asecret' }
|
10
11
|
}
|
11
|
-
>> finder = BizRatr::
|
12
|
+
>> finder = BizRatr::UberClient.new(config)
|
12
13
|
>> matches = finder.search_location([40.729401, -73.996061], 'third rail coffee')
|
13
14
|
>> puts matches.first.rating
|
14
15
|
=> 4.55
|
15
16
|
>> matches = finder.search_location("240 Sullivan St., New York, NY 10012", 'third rail coffee')
|
16
17
|
>> puts matches.first.rating
|
17
18
|
=> 4.55
|
19
|
+
>> puts matches.first.website_likes
|
20
|
+
=> {"share_count"=>75, "like_count"=>10, "comment_count"=>9, "click_count"=>6}
|
18
21
|
|
19
22
|
|
20
23
|
In this example, the average of the ratings from any of the sources (normalized to a 5 point scale) is used as the rating. Each result has address information, rating information, "like" information, and other relevant info.
|
@@ -25,6 +28,7 @@ You only need to specify the config options for the services you actually want t
|
|
25
28
|
* Google places: https://code.google.com/apis/console/b/0/
|
26
29
|
* Foursquare: https://foursquare.com/oauth/
|
27
30
|
* Factual: https://www.factual.com/api-keys/request
|
31
|
+
* Facebook: https://developers.facebook.com/apps
|
28
32
|
|
29
33
|
See http://findingscience.com/bizratr for more information.
|
30
34
|
|
data/lib/bizratr/business.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
1
3
|
module BizRatr
|
2
4
|
class Business
|
3
|
-
attr_accessor :name, :phone, :address, :state, :country, :zip, :twitter, :ids, :checkins, :users, :likes, :ratings, :review_counts, :coords, :city, :categories
|
5
|
+
attr_accessor :name, :phone, :address, :state, :country, :zip, :twitter, :ids, :checkins, :users, :likes, :ratings, :review_counts, :coords, :city, :categories, :website
|
4
6
|
|
5
|
-
def initialize(lat, lon, name)
|
7
|
+
def initialize(uberclient, lat, lon, name)
|
6
8
|
@ids = {}
|
7
9
|
@checkins = {}
|
8
10
|
@users = {}
|
@@ -12,10 +14,11 @@ module BizRatr
|
|
12
14
|
@categories = {}
|
13
15
|
@coords = [lat, lon]
|
14
16
|
@name = name
|
17
|
+
@uberclient = uberclient
|
15
18
|
end
|
16
19
|
|
17
20
|
def to_s
|
18
|
-
attrs = [:name, :phone, :address, :state, :country, :zip, :twitter, :ids, :checkins, :users, :likes, :ratings, :review_counts, :coords, :city, :categories]
|
21
|
+
attrs = [:name, :phone, :address, :state, :country, :zip, :twitter, :ids, :checkins, :users, :likes, :ratings, :review_counts, :coords, :city, :categories, :website]
|
19
22
|
args = attrs.map { |k| "#{k.to_s}=#{send(k)}" }.join(", ")
|
20
23
|
"<Business [#{args}]>"
|
21
24
|
end
|
@@ -28,6 +31,23 @@ module BizRatr
|
|
28
31
|
@users.values.inject { |a,b| a+b } || 0
|
29
32
|
end
|
30
33
|
|
34
|
+
# Get all of the website like information from Facebook. If there's no website, or an issue, return {} - otherwise
|
35
|
+
# you'll get something of the form {"share_count"=>75, "like_count"=>10, "comment_count"=>9, "click_count"=>6}
|
36
|
+
def website_likes
|
37
|
+
fb = @uberclient.get_connector(:facebook)
|
38
|
+
return {} if fb.nil? or @website.nil?
|
39
|
+
# normalize URL first
|
40
|
+
begin
|
41
|
+
uri = URI(@website)
|
42
|
+
uri.query = nil
|
43
|
+
uri.path = ''
|
44
|
+
results = fb.get_url_likes(uri.to_s)
|
45
|
+
(results.length > 0) ? results.first : {}
|
46
|
+
rescue
|
47
|
+
{}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
31
51
|
def total_reviews
|
32
52
|
@review_counts.values.inject { |a,b| a+b } || 0
|
33
53
|
end
|
@@ -49,6 +69,7 @@ module BizRatr
|
|
49
69
|
@zip ||= other.zip
|
50
70
|
@twitter ||= other.twitter
|
51
71
|
@city ||= other.city
|
72
|
+
@website ||= other.website
|
52
73
|
@checkins = @checkins.merge(other.checkins)
|
53
74
|
@users = @users.merge(other.users)
|
54
75
|
@likes = @likes.merge(other.likes)
|
@@ -82,7 +103,7 @@ module BizRatr
|
|
82
103
|
end
|
83
104
|
|
84
105
|
def add_likes(connector, likes)
|
85
|
-
@
|
106
|
+
@likes[connector] = likes
|
86
107
|
end
|
87
108
|
|
88
109
|
def add_rating(connector, rating)
|
data/lib/bizratr/connector.rb
CHANGED
@@ -4,34 +4,74 @@ require 'levenshtein'
|
|
4
4
|
require 'google_places'
|
5
5
|
require 'geocoder'
|
6
6
|
require 'factual'
|
7
|
+
require 'koala'
|
7
8
|
|
8
9
|
module BizRatr
|
9
10
|
class Connector
|
11
|
+
def initialize(uberclient, config)
|
12
|
+
@uberclient = uberclient
|
13
|
+
@config = config
|
14
|
+
@client = make_client(@config)
|
15
|
+
end
|
16
|
+
|
17
|
+
def make_client(config)
|
18
|
+
raise "Not implemented"
|
19
|
+
end
|
20
|
+
|
10
21
|
def search_location(location, query)
|
11
22
|
raise "Not implemented"
|
12
23
|
end
|
24
|
+
end
|
13
25
|
|
14
|
-
|
15
|
-
|
26
|
+
class FacebookConnector < Connector
|
27
|
+
def make_client(config)
|
28
|
+
oauth = Koala::Facebook::OAuth.new(config[:key], config[:secret])
|
29
|
+
Koala::Facebook::API.new(oauth.get_app_access_token)
|
30
|
+
end
|
31
|
+
|
32
|
+
def search_location(location, query)
|
33
|
+
results = @client.search(query, { :type => 'place', :center => location.join(','), :distance => 1000 })
|
34
|
+
results.map { |item|
|
35
|
+
make_business(@client.get_object(item['id']))
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def make_business(item)
|
40
|
+
b = Business.new(@uberclient, item['location']['latitude'], item['location']['longitude'], item['name'])
|
41
|
+
b.add_id(:facebook, item['id'])
|
42
|
+
b.city = item['location']['city']
|
43
|
+
b.country = item['location']['country']
|
44
|
+
b.phone = item['phone'] unless item['phone'] == "nope"
|
45
|
+
b.zip = item['location']['zip']
|
46
|
+
b.website = item['website'].split(' ').first
|
47
|
+
b.address = item['location']['street']
|
48
|
+
b.add_categories(:facebook, [item['category']])
|
49
|
+
b.add_checkins(:facebook, item['checkins'] + item['were_here_count'])
|
50
|
+
b.add_likes(:facebook, item['likes'])
|
51
|
+
b
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_url_likes(url)
|
55
|
+
@client.fql_query("SELECT share_count, like_count, comment_count, click_count FROM link_stat WHERE url='#{url}'")
|
16
56
|
end
|
17
57
|
end
|
18
58
|
|
19
59
|
class FactualConnector < Connector
|
20
|
-
def
|
21
|
-
|
60
|
+
def make_client(config)
|
61
|
+
Factual.new(config[:key], config[:secret])
|
22
62
|
end
|
23
63
|
|
24
64
|
def search_location(location, query)
|
25
|
-
location = geocode(location) if location.is_a? String
|
26
65
|
results = @client.table("places").filters("name" => query).geo("$circle" => { "$center" => location, "$meters" => 1000 })
|
27
66
|
results.map { |item| make_business(item) }
|
28
67
|
end
|
29
68
|
|
30
69
|
def make_business(item)
|
31
|
-
b = Business.new(item['latitude'], item['longitude'], item['name'])
|
70
|
+
b = Business.new(@uberclient, item['latitude'], item['longitude'], item['name'])
|
32
71
|
b.add_id(:factual, item['factual_id'])
|
33
72
|
b.add_categories(:factual, item['category'].split(",").map(&:strip))
|
34
73
|
b.phone = item['tel'].gsub(/[\ ()-]*/, '')
|
74
|
+
b.website = item['website']
|
35
75
|
b.city = item['locality']
|
36
76
|
b.country = item['country']
|
37
77
|
b.zip = item['postcode']
|
@@ -41,46 +81,43 @@ module BizRatr
|
|
41
81
|
end
|
42
82
|
|
43
83
|
class GooglePlacesConnector < Connector
|
44
|
-
def
|
45
|
-
|
84
|
+
def make_client(config)
|
85
|
+
GooglePlaces::Client.new(config[:key])
|
46
86
|
end
|
47
87
|
|
48
88
|
def search_location(location, query)
|
49
|
-
location = geocode(location) if location.is_a? String
|
50
89
|
results = @client.spots(location[0], location[1], :name => query)
|
51
90
|
results.map { |item| make_business(item) }
|
52
91
|
end
|
53
92
|
|
54
93
|
def make_business(item)
|
55
|
-
b = Business.new(item.lat, item.lng, item.name)
|
94
|
+
b = Business.new(@uberclient, item.lat, item.lng, item.name)
|
56
95
|
b.add_id(:google_places, item.id)
|
57
96
|
b.add_categories(:google_places, item.types)
|
58
97
|
b.phone = (item.formatted_phone_number || "").gsub(/[\ ()-]*/, '')
|
59
98
|
b.city = item.city || item.vicinity.split(',').last
|
60
99
|
b.country = item.country
|
100
|
+
b.website = item.website
|
61
101
|
b.zip = item.postal_code
|
62
102
|
b.address = item.vicinity.split(',').first
|
63
103
|
b.add_rating(:google_places, item.rating)
|
104
|
+
b.add_review_counts(:google_places, item.reviews.length)
|
64
105
|
b
|
65
106
|
end
|
66
107
|
end
|
67
108
|
|
68
109
|
class FourSquareConnector < Connector
|
69
|
-
def
|
70
|
-
|
110
|
+
def make_client(config)
|
111
|
+
Foursquare2::Client.new(config)
|
71
112
|
end
|
72
113
|
|
73
114
|
def search_location(location, query)
|
74
|
-
|
75
|
-
results = @client.search_venues(:ll => location.join(","), :query => query)
|
76
|
-
else
|
77
|
-
results = @client.search_venues(:near => location, :query => query)
|
78
|
-
end
|
115
|
+
results = @client.search_venues(:ll => location.join(","), :query => query)
|
79
116
|
results['groups'].first['items'].map { |item| make_business(item) }
|
80
117
|
end
|
81
118
|
|
82
119
|
def make_business(item)
|
83
|
-
b = Business.new(item['location']['lat'], item['location']['lng'], item['name'])
|
120
|
+
b = Business.new(@uberclient, item['location']['lat'], item['location']['lng'], item['name'])
|
84
121
|
b.add_id(:foursquare, item['id'])
|
85
122
|
categories = item.categories.map { |c| [ c.name ] + c.parents }.flatten
|
86
123
|
b.add_categories(:foursquare, categories)
|
@@ -91,15 +128,15 @@ module BizRatr
|
|
91
128
|
b.country = item['location']['cc']
|
92
129
|
b.address = item['location']['address']
|
93
130
|
b.add_checkins(:foursquare, item['stats']['checkinsCount'])
|
131
|
+
b.website = item['url']
|
94
132
|
b.add_users(:foursquare, item['stats']['usersCount'])
|
95
133
|
b
|
96
134
|
end
|
97
135
|
end
|
98
136
|
|
99
137
|
class YelpConnector < Connector
|
100
|
-
def
|
101
|
-
|
102
|
-
@client = Yelp::Client.new
|
138
|
+
def make_client(config)
|
139
|
+
Yelp::Client.new
|
103
140
|
end
|
104
141
|
|
105
142
|
def search_location(location, query)
|
@@ -113,7 +150,7 @@ module BizRatr
|
|
113
150
|
end
|
114
151
|
|
115
152
|
def make_business(item)
|
116
|
-
b = Business.new(item['location']['coordinate']['latitude'], item['location']['coordinate']['longitude'], item['name'])
|
153
|
+
b = Business.new(@uberclient, item['location']['coordinate']['latitude'], item['location']['coordinate']['longitude'], item['name'])
|
117
154
|
b.add_id(:yelp, item['id'])
|
118
155
|
b.add_categories(:yelp, item['categories'].map(&:first))
|
119
156
|
b.state = item['location']['state_code']
|
@@ -128,16 +165,18 @@ module BizRatr
|
|
128
165
|
end
|
129
166
|
end
|
130
167
|
|
131
|
-
class
|
168
|
+
class UberClient
|
132
169
|
def initialize(config)
|
133
|
-
@connectors =
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
170
|
+
@connectors = {}
|
171
|
+
config.each { |key, value|
|
172
|
+
@connectors[key] = case key
|
173
|
+
when :foursquare then FourSquareConnector.new(self, value)
|
174
|
+
when :yelp then YelpConnector.new(self, value)
|
175
|
+
when :google_places then GooglePlacesConnector.new(self, value)
|
176
|
+
when :factual then FactualConnector.new(self, value)
|
177
|
+
when :facebook then FacebookConnector.new(self, value)
|
178
|
+
else raise "No such connector found: #{key}"
|
179
|
+
end
|
141
180
|
}
|
142
181
|
end
|
143
182
|
|
@@ -145,11 +184,20 @@ module BizRatr
|
|
145
184
|
# location parameter should be either an address string or an array consisting of
|
146
185
|
# [ lat, lon ].
|
147
186
|
def search_location(location, query)
|
148
|
-
|
187
|
+
location = geocode(location) if location.is_a? String
|
188
|
+
merge @connectors.values.map { |c|
|
149
189
|
c.search_location(location, query)
|
150
190
|
}
|
151
191
|
end
|
152
192
|
|
193
|
+
def geocode(address)
|
194
|
+
Geocoder.coordinates(address)
|
195
|
+
end
|
196
|
+
|
197
|
+
def get_connector(key)
|
198
|
+
@connectors.fetch(key, nil)
|
199
|
+
end
|
200
|
+
|
153
201
|
# Search a location (just like search_location) but only return the best
|
154
202
|
# matching business (based on name).
|
155
203
|
def search_location_strictly(location, name)
|
data/lib/bizratr/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bizratr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-19 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: foursquare2
|
16
|
-
requirement: &
|
16
|
+
requirement: &70168127272320 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70168127272320
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: yelpster
|
27
|
-
requirement: &
|
27
|
+
requirement: &70168127271660 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70168127271660
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: google_places
|
38
|
-
requirement: &
|
38
|
+
requirement: &70168127271020 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70168127271020
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: levenshtein
|
49
|
-
requirement: &
|
49
|
+
requirement: &70168127270360 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70168127270360
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: google_places
|
60
|
-
requirement: &
|
60
|
+
requirement: &70168127269740 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70168127269740
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: geocoder
|
71
|
-
requirement: &
|
71
|
+
requirement: &70168127269100 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,21 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70168127269100
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: koala
|
82
|
+
requirement: &70168127268520 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :runtime
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70168127268520
|
80
91
|
- !ruby/object:Gem::Dependency
|
81
92
|
name: factual-api
|
82
|
-
requirement: &
|
93
|
+
requirement: &70168127246840 !ruby/object:Gem::Requirement
|
83
94
|
none: false
|
84
95
|
requirements:
|
85
96
|
- - ! '>='
|
@@ -87,7 +98,7 @@ dependencies:
|
|
87
98
|
version: '0'
|
88
99
|
type: :runtime
|
89
100
|
prerelease: false
|
90
|
-
version_requirements: *
|
101
|
+
version_requirements: *70168127246840
|
91
102
|
description: Get business ratings.
|
92
103
|
email: bamuller@gmail.com
|
93
104
|
executables: []
|