bizratr 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/Gemfile +4 -0
- data/Gemfile.lock +44 -0
- data/LICENSE +674 -0
- data/README.rdoc +30 -0
- data/Rakefile +14 -0
- data/docs/BizRatr/Business.html +981 -0
- data/docs/BizRatr/Connector.html +283 -0
- data/docs/BizRatr/Finder.html +348 -0
- data/docs/BizRatr/FourSquareConnector.html +294 -0
- data/docs/BizRatr/GooglePlacesConnector.html +293 -0
- data/docs/BizRatr/YelpConnector.html +299 -0
- data/docs/BizRatr.html +186 -0
- data/docs/README_rdoc.html +146 -0
- data/docs/created.rid +6 -0
- data/docs/index.html +128 -0
- data/docs/lib/bizratr/business_rb.html +52 -0
- data/docs/lib/bizratr/connector_rb.html +60 -0
- data/docs/lib/bizratr/version_rb.html +52 -0
- data/docs/lib/bizratr_rb.html +58 -0
- data/docs/rdoc.css +706 -0
- data/lib/bizratr/business.rb +102 -0
- data/lib/bizratr/connector.rb +144 -0
- data/lib/bizratr/version.rb +3 -0
- data/lib/bizratr.rb +4 -0
- metadata +134 -0
@@ -0,0 +1,102 @@
|
|
1
|
+
module BizRatr
|
2
|
+
class Business
|
3
|
+
attr_accessor :name, :phone, :address, :state, :country, :zip, :twitter, :ids, :checkins, :users, :likes, :ratings, :review_counts, :coords, :city
|
4
|
+
|
5
|
+
def initialize(lat, lon, name)
|
6
|
+
@ids = {}
|
7
|
+
@checkins = {}
|
8
|
+
@users = {}
|
9
|
+
@likes = {}
|
10
|
+
@ratings = {}
|
11
|
+
@review_counts = {}
|
12
|
+
@coords = [lat, lon]
|
13
|
+
@name = name
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
attrs = [:name, :phone, :address, :state, :country, :zip, :twitter, :ids, :checkins, :users, :likes, :ratings, :review_counts, :coords, :city]
|
18
|
+
args = attrs.map { |k| "#{k.to_s}=#{send(k)}" }.join(", ")
|
19
|
+
"<Business [#{args}]>"
|
20
|
+
end
|
21
|
+
|
22
|
+
def rating
|
23
|
+
@ratings.values.inject(:+) / @ratings.length
|
24
|
+
end
|
25
|
+
|
26
|
+
def merge(other)
|
27
|
+
@ids = @ids.merge(other.ids)
|
28
|
+
@phone ||= other.phone
|
29
|
+
@address ||= other.address
|
30
|
+
@state ||= other.state
|
31
|
+
@country ||= other.country
|
32
|
+
@zip ||= other.zip
|
33
|
+
@twitter ||= other.twitter
|
34
|
+
@city ||= other.city
|
35
|
+
@checkins = @checkins.merge(other.checkins)
|
36
|
+
@users = @users.merge(other.users)
|
37
|
+
@likes = @likes.merge(other.likes)
|
38
|
+
@ratings = @ratings.merge(other.ratings)
|
39
|
+
@review_counts = @review_counts.merge(other.review_counts)
|
40
|
+
@coords[0] = (@coords[0].to_f + other.coords[0].to_f) / 2.0
|
41
|
+
@coords[1] = (@coords[1].to_f + other.coords[1].to_f) / 2.0
|
42
|
+
return self
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_id(connector, id)
|
46
|
+
@ids[connector] = id
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_checkins(connector, checkins)
|
50
|
+
@checkins[connector] = checkins
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_users(connector, users)
|
54
|
+
@users[connector] = users
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_likes(connector, likes)
|
58
|
+
@users[connector] = likes
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_rating(connector, rating)
|
62
|
+
@ratings[connector] = rating
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_review_counts(connector, counts)
|
66
|
+
@review_counts[connector] = counts
|
67
|
+
end
|
68
|
+
|
69
|
+
def any_equal_ids?(other)
|
70
|
+
@ids.each { |k,v|
|
71
|
+
return true if other.ids[k] == v
|
72
|
+
}
|
73
|
+
false
|
74
|
+
end
|
75
|
+
|
76
|
+
def distance_to(other)
|
77
|
+
rpd = 0.017453293 # PI/180
|
78
|
+
dlat = other.coords[0] - @coords[0]
|
79
|
+
dlon = other.coords[1] - @coords[1]
|
80
|
+
dlon_rad = dlon * rpd
|
81
|
+
dlat_rad = dlat * rpd
|
82
|
+
lat1_rad = @coords[0] * rpd
|
83
|
+
lon1_rad = @coords[1] * rpd
|
84
|
+
lat2_rad = other.coords[0] * rpd
|
85
|
+
lon2_rad = other.coords[1] * rpd
|
86
|
+
a = (Math.sin(dlat_rad/2))**2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * (Math.sin(dlon_rad/2))**2
|
87
|
+
2 * Math.atan2( Math.sqrt(a), Math.sqrt(1-a)) * 3956 # 3956 is the radius of the great circle in miles
|
88
|
+
end
|
89
|
+
|
90
|
+
def name_distance_to(other)
|
91
|
+
Levenshtein::normalized_distance(@name, other.name)
|
92
|
+
end
|
93
|
+
|
94
|
+
def ==(other)
|
95
|
+
return false if other.nil?
|
96
|
+
return true if any_equal_ids?(other)
|
97
|
+
return true if @phone == other.phone and not @phone.nil?
|
98
|
+
return true if distance_to(other) < 0.3 and name_distance_to(other) < 0.4
|
99
|
+
false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'foursquare2'
|
2
|
+
require 'yelpster'
|
3
|
+
require 'levenshtein'
|
4
|
+
require 'google_places'
|
5
|
+
require 'geocoder'
|
6
|
+
|
7
|
+
module BizRatr
|
8
|
+
class Connector
|
9
|
+
def search_location(location, query)
|
10
|
+
raise "Not implemented"
|
11
|
+
end
|
12
|
+
|
13
|
+
def geocode(address)
|
14
|
+
Geocoder.coordinates(address)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class GooglePlacesConnector < Connector
|
19
|
+
def initialize(config)
|
20
|
+
@client = GooglePlaces::Client.new(config[:key])
|
21
|
+
end
|
22
|
+
|
23
|
+
def search_location(location, query)
|
24
|
+
location = geocode(location) if location.is_a? String
|
25
|
+
results = @client.spots(location[0], location[1], :name => query)
|
26
|
+
results.map { |item| make_business(item) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def make_business(item)
|
30
|
+
b = Business.new(item.lat, item.lng, item.name)
|
31
|
+
b.add_id(:google_places, item.id)
|
32
|
+
b.phone = item.formatted_phone_number
|
33
|
+
b.city = item.city || item.vicinity.split(',').last
|
34
|
+
b.country = item.country
|
35
|
+
b.zip = item.postal_code
|
36
|
+
b.address = item.vicinity.split(',').first
|
37
|
+
b.add_rating(:google_places, item.rating)
|
38
|
+
b
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class FourSquareConnector < Connector
|
43
|
+
def initialize(config)
|
44
|
+
@client = Foursquare2::Client.new(config)
|
45
|
+
end
|
46
|
+
|
47
|
+
def search_location(location, query)
|
48
|
+
if location.is_a? Array
|
49
|
+
results = @client.search_venues(:ll => location.join(","), :query => query)
|
50
|
+
else
|
51
|
+
results = @client.search_venues(:near => location, :query => query)
|
52
|
+
end
|
53
|
+
results['groups'].first['items'].map { |item| make_business(item) }
|
54
|
+
end
|
55
|
+
|
56
|
+
def make_business(item)
|
57
|
+
b = Business.new(item['location']['lat'], item['location']['lng'], item['name'])
|
58
|
+
b.add_id(:foursquare, item['id'])
|
59
|
+
b.phone = item['contact'].fetch('phone', nil)
|
60
|
+
b.twitter = item['contact'].fetch('twitter', nil)
|
61
|
+
b.state = item['location']['state']
|
62
|
+
b.city = item['location']['city']
|
63
|
+
b.country = item['location']['cc']
|
64
|
+
b.address = item['location']['address']
|
65
|
+
b.add_checkins(:foursquare, item['stats']['checkinsCount'])
|
66
|
+
b.add_users(:foursquare, item['stats']['usersCount'])
|
67
|
+
b
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class YelpConnector < Connector
|
72
|
+
def initialize(config)
|
73
|
+
@config = config
|
74
|
+
@client = Yelp::Client.new
|
75
|
+
end
|
76
|
+
|
77
|
+
def search_location(location, query)
|
78
|
+
# while yelp does support searching by address, it does so much more shittily w/o lat/lon
|
79
|
+
location = geocode(location) if location.is_a? String
|
80
|
+
config = { :term => query, :latitude => location.first, :longitude => location.last }
|
81
|
+
result = @client.search Yelp::V2::Search::Request::GeoPoint.new(config.merge(@config))
|
82
|
+
result['businesses'].map { |item|
|
83
|
+
make_business(item)
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
def make_business(item)
|
88
|
+
b = Business.new(item['location']['coordinate']['latitude'], item['location']['coordinate']['longitude'], item['name'])
|
89
|
+
b.add_id(:yelp, item['id'])
|
90
|
+
b.state = item['location']['state_code']
|
91
|
+
b.zip = item['location']['postal_code']
|
92
|
+
b.country = item['location']['country_code']
|
93
|
+
b.city = item['location']['city']
|
94
|
+
b.address = item['location']['address'].first
|
95
|
+
b.phone = item['phone']
|
96
|
+
b.add_rating(:yelp, item['rating'])
|
97
|
+
b.add_review_counts(:yelp, item['review_count'])
|
98
|
+
b
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Finder
|
103
|
+
def initialize(config)
|
104
|
+
@connectors = config.map { |key, value|
|
105
|
+
case key
|
106
|
+
when :foursquare then FourSquareConnector.new(value)
|
107
|
+
when :yelp then YelpConnector.new(value)
|
108
|
+
when :google_places then GooglePlacesConnector.new(value)
|
109
|
+
else raise "No such connector found: #{key}"
|
110
|
+
end
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
# Search for a business (or business category) near lat/lon coordinates. The
|
115
|
+
# location parameter should be either an address string or an array consisting of
|
116
|
+
# [ lat, lon ].
|
117
|
+
def search_location(location, query)
|
118
|
+
merge @connectors.map { |c|
|
119
|
+
c.search_location(location, query)
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
def merge(lists)
|
125
|
+
lists.inject([]) { |o,t| merge_lists(o, t) }
|
126
|
+
end
|
127
|
+
|
128
|
+
def merge_lists(one, two)
|
129
|
+
one.map { |first|
|
130
|
+
result = first
|
131
|
+
two.map! { |second|
|
132
|
+
if first == second
|
133
|
+
result = first.merge(second)
|
134
|
+
nil
|
135
|
+
else
|
136
|
+
second
|
137
|
+
end
|
138
|
+
}
|
139
|
+
result
|
140
|
+
} + two.select { |s| not s.nil? }
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
data/lib/bizratr.rb
ADDED
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bizratr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Brian Muller
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-17 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: foursquare2
|
16
|
+
requirement: &70329591509040 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70329591509040
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: yelpster
|
27
|
+
requirement: &70329591508340 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70329591508340
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: google_places
|
38
|
+
requirement: &70329591507700 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70329591507700
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: levenshtein
|
49
|
+
requirement: &70329591507040 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70329591507040
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: google_places
|
60
|
+
requirement: &70329591506420 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70329591506420
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: geocoder
|
71
|
+
requirement: &70329591505820 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70329591505820
|
80
|
+
description: Get business ratings.
|
81
|
+
email: bamuller@gmail.com
|
82
|
+
executables: []
|
83
|
+
extensions: []
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- lib/bizratr/business.rb
|
87
|
+
- lib/bizratr/connector.rb
|
88
|
+
- lib/bizratr/version.rb
|
89
|
+
- lib/bizratr.rb
|
90
|
+
- Gemfile
|
91
|
+
- Gemfile.lock
|
92
|
+
- LICENSE
|
93
|
+
- Rakefile
|
94
|
+
- README.rdoc
|
95
|
+
- docs/BizRatr/Business.html
|
96
|
+
- docs/BizRatr/Connector.html
|
97
|
+
- docs/BizRatr/Finder.html
|
98
|
+
- docs/BizRatr/FourSquareConnector.html
|
99
|
+
- docs/BizRatr/GooglePlacesConnector.html
|
100
|
+
- docs/BizRatr/YelpConnector.html
|
101
|
+
- docs/BizRatr.html
|
102
|
+
- docs/created.rid
|
103
|
+
- docs/index.html
|
104
|
+
- docs/lib/bizratr/business_rb.html
|
105
|
+
- docs/lib/bizratr/connector_rb.html
|
106
|
+
- docs/lib/bizratr/version_rb.html
|
107
|
+
- docs/lib/bizratr_rb.html
|
108
|
+
- docs/rdoc.css
|
109
|
+
- docs/README_rdoc.html
|
110
|
+
homepage: https://github.com/bmuller/bizratr
|
111
|
+
licenses: []
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: 1.9.0
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
requirements: []
|
129
|
+
rubyforge_project: bizratr
|
130
|
+
rubygems_version: 1.8.17
|
131
|
+
signing_key:
|
132
|
+
specification_version: 3
|
133
|
+
summary: Get business ratings.
|
134
|
+
test_files: []
|