geocoder 1.1.4 → 1.1.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of geocoder might be problematic. Click here for more details.
- data/CHANGELOG.rdoc +9 -0
- data/README.md +24 -10
- data/lib/geocoder/configuration.rb +1 -1
- data/lib/geocoder/lookups/base.rb +35 -16
- data/lib/geocoder/lookups/bing.rb +1 -1
- data/lib/geocoder/lookups/freegeoip.rb +1 -1
- data/lib/geocoder/lookups/geocoder_ca.rb +1 -1
- data/lib/geocoder/lookups/mapquest.rb +25 -4
- data/lib/geocoder/lookups/nominatim.rb +1 -1
- data/lib/geocoder/lookups/yahoo.rb +26 -42
- data/lib/geocoder/lookups/yandex.rb +1 -1
- data/lib/geocoder/models/mongoid.rb +1 -1
- data/lib/geocoder/query.rb +7 -1
- data/lib/geocoder/results/base.rb +8 -2
- data/lib/geocoder/results/mapquest.rb +46 -2
- data/lib/geocoder/results/yahoo.rb +9 -2
- data/lib/geocoder/stores/active_record.rb +14 -9
- data/lib/geocoder/stores/base.rb +1 -1
- data/lib/geocoder/version.rb +1 -1
- data/lib/oauth_util.rb +106 -0
- data/test/cache_test.rb +19 -0
- data/test/error_handling_test.rb +4 -0
- data/test/fixtures/mapquest_madison_square_garden.json +50 -25
- data/test/fixtures/mapquest_no_results.json +7 -1
- data/test/fixtures/yahoo_error.json +1 -0
- data/test/fixtures/yahoo_madison_square_garden.json +48 -48
- data/test/fixtures/yahoo_no_results.json +7 -7
- data/test/lookup_test.rb +1 -6
- data/test/near_test.rb +11 -0
- data/test/query_test.rb +5 -0
- data/test/result_test.rb +1 -0
- data/test/services_test.rb +43 -23
- data/test/test_helper.rb +46 -15
- metadata +8 -6
- data/test/fixtures/yahoo_v1_madison_square_garden.json +0 -46
- data/test/fixtures/yahoo_v1_no_results.json +0 -10
@@ -31,17 +31,24 @@ module Geocoder::Result
|
|
31
31
|
@data['postal']
|
32
32
|
end
|
33
33
|
|
34
|
+
def address_hash
|
35
|
+
@data['hash']
|
36
|
+
end
|
37
|
+
|
34
38
|
def self.response_attributes
|
35
39
|
%w[quality offsetlat offsetlon radius boundingbox name
|
36
40
|
line1 line2 line3 line4 cross house street xstreet unittype unit
|
41
|
+
city state statecode country countrycode postal
|
37
42
|
neighborhood county countycode
|
38
43
|
level0 level1 level2 level3 level4 level0code level1code level2code
|
39
44
|
timezone areacode uzip hash woeid woetype]
|
40
45
|
end
|
41
46
|
|
42
47
|
response_attributes.each do |a|
|
43
|
-
|
44
|
-
|
48
|
+
unless method_defined?(a)
|
49
|
+
define_method a do
|
50
|
+
@data[a]
|
51
|
+
end
|
45
52
|
end
|
46
53
|
end
|
47
54
|
end
|
@@ -102,15 +102,18 @@ module Geocoder::Store
|
|
102
102
|
options[:units] ||= (geocoder_options[:units] || Geocoder::Configuration.units)
|
103
103
|
bearing = bearing_sql(latitude, longitude, options)
|
104
104
|
distance = distance_sql(latitude, longitude, options)
|
105
|
+
|
106
|
+
b = Geocoder::Calculations.bounding_box([latitude, longitude], radius, options)
|
107
|
+
args = b + [
|
108
|
+
full_column_name(geocoder_options[:latitude]),
|
109
|
+
full_column_name(geocoder_options[:longitude])
|
110
|
+
]
|
111
|
+
bounding_box_conditions = Geocoder::Sql.within_bounding_box(*args)
|
112
|
+
|
105
113
|
if using_sqlite?
|
106
|
-
|
107
|
-
args = b + [
|
108
|
-
full_column_name(geocoder_options[:latitude]),
|
109
|
-
full_column_name(geocoder_options[:longitude])
|
110
|
-
]
|
111
|
-
conditions = Geocoder::Sql.within_bounding_box(*args)
|
114
|
+
conditions = bounding_box_conditions
|
112
115
|
else
|
113
|
-
conditions = ["#{distance} <= ?", radius]
|
116
|
+
conditions = [bounding_box_conditions + " AND #{distance} <= ?", radius]
|
114
117
|
end
|
115
118
|
{
|
116
119
|
:select => select_clause(options[:select], distance, bearing),
|
@@ -157,8 +160,10 @@ module Geocoder::Store
|
|
157
160
|
##
|
158
161
|
# Generate the SELECT clause.
|
159
162
|
#
|
160
|
-
def select_clause(columns, distance, bearing = nil)
|
161
|
-
if columns == :
|
163
|
+
def select_clause(columns, distance = nil, bearing = nil)
|
164
|
+
if columns == :id_only
|
165
|
+
return full_column_name(primary_key)
|
166
|
+
elsif columns == :geo_only
|
162
167
|
clause = ""
|
163
168
|
else
|
164
169
|
clause = (columns || full_column_name("*")) + ", "
|
data/lib/geocoder/stores/base.rb
CHANGED
@@ -60,7 +60,7 @@ module Geocoder
|
|
60
60
|
# Takes the same options hash as the near class method (scope).
|
61
61
|
#
|
62
62
|
def nearbys(radius = 20, options = {})
|
63
|
-
return [] unless geocoded?
|
63
|
+
return [] unless geocoded? # TODO: return ActiveRecord::Relation, not Array
|
64
64
|
options.merge!(:exclude => self)
|
65
65
|
self.class.near(self, radius, options)
|
66
66
|
end
|
data/lib/geocoder/version.rb
CHANGED
data/lib/oauth_util.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
# A utility for signing an url using OAuth in a way that's convenient for debugging
|
2
|
+
# Note: the standard Ruby OAuth lib is here http://github.com/mojodna/oauth
|
3
|
+
# Source: http://gist.github.com/383159
|
4
|
+
# License: http://gist.github.com/375593
|
5
|
+
# Usage: see example.rb below
|
6
|
+
|
7
|
+
require 'uri'
|
8
|
+
require 'cgi'
|
9
|
+
require 'openssl'
|
10
|
+
require 'base64'
|
11
|
+
|
12
|
+
class OauthUtil
|
13
|
+
|
14
|
+
attr_accessor :consumer_key, :consumer_secret, :token, :token_secret, :req_method,
|
15
|
+
:sig_method, :oauth_version, :callback_url, :params, :req_url, :base_str
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@consumer_key = ''
|
19
|
+
@consumer_secret = ''
|
20
|
+
@token = ''
|
21
|
+
@token_secret = ''
|
22
|
+
@req_method = 'GET'
|
23
|
+
@sig_method = 'HMAC-SHA1'
|
24
|
+
@oauth_version = '1.0'
|
25
|
+
@callback_url = ''
|
26
|
+
end
|
27
|
+
|
28
|
+
# openssl::random_bytes returns non-word chars, which need to be removed. using alt method to get length
|
29
|
+
# ref http://snippets.dzone.com/posts/show/491
|
30
|
+
def nonce
|
31
|
+
Array.new( 5 ) { rand(256) }.pack('C*').unpack('H*').first
|
32
|
+
end
|
33
|
+
|
34
|
+
def percent_encode( string )
|
35
|
+
|
36
|
+
# ref http://snippets.dzone.com/posts/show/1260
|
37
|
+
return URI.escape( string, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]") ).gsub('*', '%2A')
|
38
|
+
end
|
39
|
+
|
40
|
+
# @ref http://oauth.net/core/1.0/#rfc.section.9.2
|
41
|
+
def signature
|
42
|
+
key = percent_encode( @consumer_secret ) + '&' + percent_encode( @token_secret )
|
43
|
+
|
44
|
+
# ref: http://blog.nathanielbibler.com/post/63031273/openssl-hmac-vs-ruby-hmac-benchmarks
|
45
|
+
digest = OpenSSL::Digest::Digest.new( 'sha1' )
|
46
|
+
hmac = OpenSSL::HMAC.digest( digest, key, @base_str )
|
47
|
+
|
48
|
+
# ref http://groups.google.com/group/oauth-ruby/browse_thread/thread/9110ed8c8f3cae81
|
49
|
+
Base64.encode64( hmac ).chomp.gsub( /\n/, '' )
|
50
|
+
end
|
51
|
+
|
52
|
+
# sort (very important as it affects the signature), concat, and percent encode
|
53
|
+
# @ref http://oauth.net/core/1.0/#rfc.section.9.1.1
|
54
|
+
# @ref http://oauth.net/core/1.0/#9.2.1
|
55
|
+
# @ref http://oauth.net/core/1.0/#rfc.section.A.5.1
|
56
|
+
def query_string
|
57
|
+
pairs = []
|
58
|
+
@params.sort.each { | key, val |
|
59
|
+
pairs.push( "#{ percent_encode( key ) }=#{ percent_encode( val.to_s ) }" )
|
60
|
+
}
|
61
|
+
pairs.join '&'
|
62
|
+
end
|
63
|
+
|
64
|
+
# organize params & create signature
|
65
|
+
def sign( parsed_url )
|
66
|
+
|
67
|
+
@params = {
|
68
|
+
'oauth_consumer_key' => @consumer_key,
|
69
|
+
'oauth_nonce' => nonce,
|
70
|
+
'oauth_signature_method' => @sig_method,
|
71
|
+
'oauth_timestamp' => Time.now.to_i.to_s,
|
72
|
+
'oauth_version' => @oauth_version
|
73
|
+
}
|
74
|
+
|
75
|
+
# if url has query, merge key/values into params obj overwriting defaults
|
76
|
+
if parsed_url.query
|
77
|
+
#@params.merge! CGI.parse( parsed_url.query )
|
78
|
+
CGI.parse( parsed_url.query ).each do |k,v|
|
79
|
+
if v.is_a?(Array) && v.count == 1
|
80
|
+
@params[k] = v.first
|
81
|
+
else
|
82
|
+
@params[k] = v
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# @ref http://oauth.net/core/1.0/#rfc.section.9.1.2
|
88
|
+
@req_url = parsed_url.scheme + '://' + parsed_url.host + parsed_url.path
|
89
|
+
|
90
|
+
# create base str. make it an object attr for ez debugging
|
91
|
+
# ref http://oauth.net/core/1.0/#anchor14
|
92
|
+
@base_str = [
|
93
|
+
@req_method,
|
94
|
+
percent_encode( req_url ),
|
95
|
+
|
96
|
+
# normalization is just x-www-form-urlencoded
|
97
|
+
percent_encode( query_string )
|
98
|
+
|
99
|
+
].join( '&' )
|
100
|
+
|
101
|
+
# add signature
|
102
|
+
@params[ 'oauth_signature' ] = signature
|
103
|
+
|
104
|
+
return self
|
105
|
+
end
|
106
|
+
end
|
data/test/cache_test.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class CacheTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_second_occurrence_of_request_is_cache_hit
|
7
|
+
Geocoder::Configuration.cache = {}
|
8
|
+
Geocoder::Lookup.all_services_except_test.each do |l|
|
9
|
+
Geocoder::Configuration.lookup = l
|
10
|
+
set_api_key!(l)
|
11
|
+
results = Geocoder.search("Madison Square Garden")
|
12
|
+
assert !results.first.cache_hit,
|
13
|
+
"Lookup #{l} returned erroneously cached result."
|
14
|
+
results = Geocoder.search("Madison Square Garden")
|
15
|
+
assert results.first.cache_hit,
|
16
|
+
"Lookup #{l} did not return cached result."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/test/error_handling_test.rb
CHANGED
@@ -12,8 +12,10 @@ class ErrorHandlingTest < Test::Unit::TestCase
|
|
12
12
|
orig = $VERBOSE; $VERBOSE = nil
|
13
13
|
Geocoder::Lookup.all_services_except_test.each do |l|
|
14
14
|
Geocoder::Configuration.lookup = l
|
15
|
+
set_api_key!(l)
|
15
16
|
assert_nothing_raised { Geocoder.search("timeout") }
|
16
17
|
end
|
18
|
+
ensure
|
17
19
|
$VERBOSE = orig
|
18
20
|
end
|
19
21
|
|
@@ -21,6 +23,7 @@ class ErrorHandlingTest < Test::Unit::TestCase
|
|
21
23
|
Geocoder::Configuration.always_raise = [TimeoutError]
|
22
24
|
Geocoder::Lookup.all_services_except_test.each do |l|
|
23
25
|
lookup = Geocoder::Lookup.get(l)
|
26
|
+
set_api_key!(l)
|
24
27
|
assert_raises TimeoutError do
|
25
28
|
lookup.send(:results, Geocoder::Query.new("timeout"))
|
26
29
|
end
|
@@ -31,6 +34,7 @@ class ErrorHandlingTest < Test::Unit::TestCase
|
|
31
34
|
Geocoder::Configuration.always_raise = [SocketError]
|
32
35
|
Geocoder::Lookup.all_services_except_test.each do |l|
|
33
36
|
lookup = Geocoder::Lookup.get(l)
|
37
|
+
set_api_key!(l)
|
34
38
|
assert_raises SocketError do
|
35
39
|
lookup.send(:results, Geocoder::Query.new("socket_error"))
|
36
40
|
end
|
@@ -1,27 +1,52 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
1
|
+
{
|
2
|
+
"results": [
|
3
|
+
{
|
4
|
+
"locations": [
|
5
|
+
{
|
6
|
+
"latLng": {
|
7
|
+
"lng": -73.994637,
|
8
|
+
"lat": 40.720409
|
9
|
+
},
|
10
|
+
"adminArea4": "New York County",
|
11
|
+
"adminArea5Type": "City",
|
12
|
+
"adminArea4Type": "County",
|
13
|
+
"adminArea5": "New York",
|
14
|
+
"street": "46 West 31st Street",
|
15
|
+
"adminArea1": "US",
|
16
|
+
"adminArea3": "NY",
|
17
|
+
"type": "s",
|
18
|
+
"displayLatLng": {
|
19
|
+
"lng": -73.994637,
|
20
|
+
"lat": 40.720409
|
21
|
+
},
|
22
|
+
"linkId": 0,
|
23
|
+
"postalCode": "10001",
|
24
|
+
"sideOfStreet": "N",
|
25
|
+
"dragPoint": false,
|
26
|
+
"adminArea1Type": "Country",
|
27
|
+
"geocodeQuality": "CITY",
|
28
|
+
"geocodeQualityCode": "A5XAX",
|
29
|
+
"mapUrl": "http://www.mapquestapi.com/staticmap/v3/getmap?type=map&size=225,160&pois=purple-1,40.720409,-73.994637,0,0|¢er=40.720409,-73.994637&zoom=9&key=Gmjtd|luua2hu2nd,7x=o5-lz8lg&rand=604519389",
|
30
|
+
"adminArea3Type": "State"
|
31
|
+
}
|
32
|
+
],
|
33
|
+
"providedLocation": {
|
34
|
+
"location": "Madison Square Garden, New York, NY"
|
35
|
+
}
|
25
36
|
}
|
37
|
+
],
|
38
|
+
"options": {
|
39
|
+
"ignoreLatLngInput": false,
|
40
|
+
"maxResults": -1,
|
41
|
+
"thumbMaps": true
|
42
|
+
},
|
43
|
+
"info": {
|
44
|
+
"copyright": {
|
45
|
+
"text": "© 2012 MapQuest, Inc.",
|
46
|
+
"imageUrl": "http://api.mqcdn.com/res/mqlogo.gif",
|
47
|
+
"imageAltText": "© 2012 MapQuest, Inc."
|
48
|
+
},
|
49
|
+
"statuscode": 0,
|
50
|
+
"messages": []
|
26
51
|
}
|
27
|
-
|
52
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"bossresponse":{"responsecode":"6000","reason":"internal error"}}
|
@@ -1,52 +1,52 @@
|
|
1
1
|
{
|
2
|
-
"
|
3
|
-
|
4
|
-
"
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
2
|
+
"bossresponse": {
|
3
|
+
"responsecode": "200",
|
4
|
+
"placefinder": {
|
5
|
+
"start": "0",
|
6
|
+
"count": "1",
|
7
|
+
"request": "flags=JXTSR&location=Madison%20Square%20Garden%2C%20NY%2C%20NY&%unsafe%appid=%5B%22dj0yJmk9ZmZ5NXFrNGhNcEthJmQ9WVdrOVFUSlhPV2x1TjJVbWNHbzlORE0wT0RFME9UWXkmcz1jb25zdW1lcnNlY3JldCZ4PTAy%22%2C%20%22b57b1b98eb21f171231f5b441cba505261d6c9bb%22%5D&gflags=AC&locale=en_US",
|
8
|
+
"results": [
|
9
|
+
{
|
10
|
+
"quality": "90",
|
11
|
+
"latitude": "40.750381",
|
12
|
+
"longitude": "-73.993988",
|
13
|
+
"offsetlat": "40.750381",
|
14
|
+
"offsetlon": "-73.993988",
|
15
|
+
"radius": "400",
|
16
|
+
"boundingbox": {
|
17
|
+
"north": "40.750832",
|
18
|
+
"south": "40.749931",
|
19
|
+
"east": "-73.993393",
|
20
|
+
"west": "-73.994591"
|
21
|
+
},
|
22
|
+
"name": "Madison Square Garden",
|
23
|
+
"line1": "Madison Square Garden",
|
24
|
+
"line2": "New York, NY 10001",
|
25
|
+
"line3": "",
|
26
|
+
"line4": "United States",
|
27
|
+
"cross": "",
|
28
|
+
"house": "",
|
29
|
+
"street": "",
|
30
|
+
"xstreet": "",
|
31
|
+
"unittype": "",
|
32
|
+
"unit": "",
|
33
|
+
"postal": "10001",
|
34
|
+
"neighborhood": "Garment District|Midtown|Midtown West|Manhattan",
|
35
|
+
"city": "New York",
|
36
|
+
"county": "New York County",
|
37
|
+
"state": "New York",
|
38
|
+
"country": "United States",
|
39
|
+
"countrycode": "US",
|
40
|
+
"statecode": "NY",
|
41
|
+
"countycode": "",
|
42
|
+
"timezone": "America/New_York",
|
43
|
+
"areacode": "212",
|
44
|
+
"uzip": "10001",
|
45
|
+
"hash": "",
|
46
|
+
"woeid": "23617041",
|
47
|
+
"woetype": "20"
|
48
|
+
}
|
49
|
+
]
|
50
50
|
}
|
51
51
|
}
|
52
52
|
}
|
@@ -1,10 +1,10 @@
|
|
1
1
|
{
|
2
|
-
"
|
3
|
-
"
|
4
|
-
"
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
2
|
+
"bossresponse": {
|
3
|
+
"responsecode": "200",
|
4
|
+
"placefinder": {
|
5
|
+
"start": "0",
|
6
|
+
"count": "0",
|
7
|
+
"request": "flags=JXTSR&location=asdfasdf28394782sdfj2983&%unsafe%appid=%5B%22dj0yJmk9ZmZ5NXFrNGhNcEthJmQ9WVdrOVFUSlhPV2x1TjJVbWNHbzlORE0wT0RFME9UWXkmcz1jb25zdW1lcnNlY3JldCZ4PTAy%22%2C%20%22b57b1b98eb21f171231f5b441cba505261d6c9bb%22%5D&gflags=AC&locale=en_US"
|
8
|
+
}
|
9
9
|
}
|
10
10
|
}
|