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 CHANGED
@@ -1,12 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bizratr (0.0.5)
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::Finder.new(config)
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
 
@@ -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
- @users[connector] = likes
106
+ @likes[connector] = likes
86
107
  end
87
108
 
88
109
  def add_rating(connector, rating)
@@ -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
- def geocode(address)
15
- Geocoder.coordinates(address)
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 initialize(config)
21
- @client = Factual.new(config[:key], config[:secret])
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 initialize(config)
45
- @client = GooglePlaces::Client.new(config[:key])
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 initialize(config)
70
- @client = Foursquare2::Client.new(config)
110
+ def make_client(config)
111
+ Foursquare2::Client.new(config)
71
112
  end
72
113
 
73
114
  def search_location(location, query)
74
- if location.is_a? Array
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 initialize(config)
101
- @config = config
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 Finder
168
+ class UberClient
132
169
  def initialize(config)
133
- @connectors = config.map { |key, value|
134
- case key
135
- when :foursquare then FourSquareConnector.new(value)
136
- when :yelp then YelpConnector.new(value)
137
- when :google_places then GooglePlacesConnector.new(value)
138
- when :factual then FactualConnector.new(value)
139
- else raise "No such connector found: #{key}"
140
- end
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
- merge @connectors.map { |c|
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)
@@ -1,3 +1,3 @@
1
1
  module BizRatr
2
- VERSION = "0.0.5"
2
+ VERSION = "0.1.0"
3
3
  end
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.5
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-17 00:00:00.000000000Z
12
+ date: 2012-09-19 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: foursquare2
16
- requirement: &70115383331060 !ruby/object:Gem::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: *70115383331060
24
+ version_requirements: *70168127272320
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: yelpster
27
- requirement: &70115383329940 !ruby/object:Gem::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: *70115383329940
35
+ version_requirements: *70168127271660
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: google_places
38
- requirement: &70115383328980 !ruby/object:Gem::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: *70115383328980
46
+ version_requirements: *70168127271020
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: levenshtein
49
- requirement: &70115383327940 !ruby/object:Gem::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: *70115383327940
57
+ version_requirements: *70168127270360
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: google_places
60
- requirement: &70115383327080 !ruby/object:Gem::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: *70115383327080
68
+ version_requirements: *70168127269740
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: geocoder
71
- requirement: &70115383326020 !ruby/object:Gem::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: *70115383326020
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: &70115383325040 !ruby/object:Gem::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: *70115383325040
101
+ version_requirements: *70168127246840
91
102
  description: Get business ratings.
92
103
  email: bamuller@gmail.com
93
104
  executables: []