bizratr 0.0.5 → 0.1.0

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/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: []