geocoder_plus 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +20 -0
- data/README +26 -0
- data/README.rdoc +19 -0
- data/lib/geocoder_plus.rb +5 -0
- data/lib/geocoders/google_v3_geocoder.rb +123 -0
- data/lib/geocoders/yahoo_place_finder_geocoder.rb +113 -0
- data/test/helper.rb +19 -0
- data/test/test_geocoder_plus.rb +7 -0
- data/test/test_google_v3_geocoder.rb +280 -0
- data/test/test_yahoo_place_finder_geocoder.rb +139 -0
- metadata +246 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Fajar A B
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
= geocoder_plus
|
2
|
+
|
3
|
+
This gem has two additional geocoders for geokit gem, Yahoo! PlaceFinder and Google V3.
|
4
|
+
Google V3 code is taken from https://github.com/tello/google-v3-geocoder.
|
5
|
+
|
6
|
+
Example:
|
7
|
+
|
8
|
+
Geokit::Geocoders::YahooPlaceFinderGeocoder.geocode('701 First Avenue Sunnyvale, California 94089')
|
9
|
+
Geokit::Geocoders::GoogleV3Geocoder.geocode('701 First Avenue Sunnyvale, California 94089')
|
10
|
+
|
11
|
+
|
12
|
+
== Contributing to geocoder_plus
|
13
|
+
|
14
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
15
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
16
|
+
* Fork the project
|
17
|
+
* Start a feature/bugfix branch
|
18
|
+
* Commit and push until you are happy with your contribution
|
19
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
20
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
21
|
+
|
22
|
+
== Copyright
|
23
|
+
|
24
|
+
Copyright (c) 2011 Fajar A B. See LICENSE.txt for
|
25
|
+
further details.
|
26
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= geocoder_plus
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Contributing to geocoder_plus
|
6
|
+
|
7
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
8
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
9
|
+
* Fork the project
|
10
|
+
* Start a feature/bugfix branch
|
11
|
+
* Commit and push until you are happy with your contribution
|
12
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2011 Fajar A B. See LICENSE.txt for
|
18
|
+
further details.
|
19
|
+
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# this code is taken from https://github.com/tello/google-v3-geocoder
|
2
|
+
|
3
|
+
module Geokit
|
4
|
+
module Geocoders
|
5
|
+
class GoogleV3Geocoder < Geocoder
|
6
|
+
private
|
7
|
+
|
8
|
+
def self.do_geocode(address, options = {})
|
9
|
+
geo_url = self.get_url(address, options)
|
10
|
+
logger.debug "Making Geocode request to: #{geo_url}"
|
11
|
+
res = self.call_geocoder_service(geo_url)
|
12
|
+
|
13
|
+
return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
|
14
|
+
json = res.body
|
15
|
+
logger.debug "Google V3 geocoding. Address: #{address}. Result: #{json}"
|
16
|
+
return self.convert_json_to_geoloc(json)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.get_url(address, options={})
|
20
|
+
bias = options[:bias] || ''
|
21
|
+
address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
|
22
|
+
return "http://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector::url_escape(address_str)}®ion=#{bias.to_s.downcase}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.convert_json_to_geoloc(json)
|
26
|
+
begin
|
27
|
+
data = Yajl::Parser.parse(json)
|
28
|
+
rescue
|
29
|
+
logger.error "Could not parse JSON from Google: #{json}"
|
30
|
+
return GeoLoc.new
|
31
|
+
end
|
32
|
+
|
33
|
+
if data['status'] != "OK"
|
34
|
+
if data['status' ] == 'OVER_QUERY_LIMIT'
|
35
|
+
raise Geokit::TooManyQueriesError "Google returned OVER_QUERY_LIMIT: #{json}"
|
36
|
+
elsif data['status'] == 'ZERO_RESULTS'
|
37
|
+
logger.info "Found no results from google v3"
|
38
|
+
return GeoLoc.new
|
39
|
+
end
|
40
|
+
logger.error "Got an error from google, response: #{json}"
|
41
|
+
# Otherwise, we don't know what to do
|
42
|
+
return GeoLoc.new
|
43
|
+
end
|
44
|
+
|
45
|
+
begin
|
46
|
+
results = data['results']
|
47
|
+
geoloc = nil
|
48
|
+
results.each do |result|
|
49
|
+
extracted_geoloc = self.extract_location(result)
|
50
|
+
if geoloc.nil?
|
51
|
+
geoloc = extracted_geoloc
|
52
|
+
else
|
53
|
+
geoloc.all.push(extracted_geoloc)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
rescue Exception => e
|
57
|
+
logger.error "Encountered unexpected exception during google geocoding: #{e.inspect}"
|
58
|
+
return GeoLoc.new
|
59
|
+
end
|
60
|
+
|
61
|
+
return geoloc
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.extract_location(result)
|
65
|
+
res = GeoLoc.new
|
66
|
+
res.provider = 'google_v3'
|
67
|
+
|
68
|
+
res.lat = result['geometry']['location']['lat']
|
69
|
+
res.lng = result['geometry']['location']['lng']
|
70
|
+
|
71
|
+
res.full_address = result['formatted_address']
|
72
|
+
|
73
|
+
street_number = nil
|
74
|
+
street_name = nil
|
75
|
+
|
76
|
+
result['address_components'].each do |component|
|
77
|
+
types = component['types']
|
78
|
+
|
79
|
+
if types.include?('street_number')
|
80
|
+
street_number = component['long_name']
|
81
|
+
end
|
82
|
+
|
83
|
+
if types.include?('route')
|
84
|
+
street_name = component['long_name']
|
85
|
+
end
|
86
|
+
|
87
|
+
if types.include?('country')
|
88
|
+
res.country = component['long_name']
|
89
|
+
res.country_code = component['short_name']
|
90
|
+
end
|
91
|
+
|
92
|
+
if types.include?('administrative_area_level_1')
|
93
|
+
res.state = component['short_name']
|
94
|
+
end
|
95
|
+
|
96
|
+
if types.include?('postal_code')
|
97
|
+
res.zip = component['long_name']
|
98
|
+
end
|
99
|
+
|
100
|
+
if types.include?('locality')
|
101
|
+
res.city = component['long_name']
|
102
|
+
end
|
103
|
+
|
104
|
+
if types.include?('postal_code')
|
105
|
+
res.zip = component['long_name']
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
res.street_address = [street_number, street_name].reject{|x| x.nil?}.join(" ")
|
110
|
+
|
111
|
+
# Set the bounds from the viewport
|
112
|
+
bounds = result['geometry']['viewport']
|
113
|
+
res.suggested_bounds = Bounds.normalize(
|
114
|
+
[bounds['southwest']['lat'], bounds['southwest']['lng']],
|
115
|
+
[bounds['northeast']['lat'], bounds['northeast']['lng']]
|
116
|
+
)
|
117
|
+
|
118
|
+
res.success = true
|
119
|
+
return res
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Geokit
|
2
|
+
module Geocoders
|
3
|
+
class YahooPlaceFinderGeocoder < Geocoder
|
4
|
+
private
|
5
|
+
|
6
|
+
def self.get_url(address, options={})
|
7
|
+
if (options[:reverse])
|
8
|
+
latlng=LatLng.normalize(address)
|
9
|
+
yql = "select * from geo.placefinder where text='#{latlng}' and gflags='R'"
|
10
|
+
else
|
11
|
+
address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
|
12
|
+
yql = "select * from geo.placefinder where text='#{address}'"
|
13
|
+
end
|
14
|
+
return "http://query.yahooapis.com/v1/public/yql?q=#{Geokit::Inflector::url_escape(yql)}&format=json"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.do_reverse_geocode(latlng)
|
18
|
+
res = self.call_geocoder_service(self.get_url(latlng, :reverse => true))
|
19
|
+
logger.debug "Yahoo PlaceFinder reverse-geocoding. LL: #{latlng}. Result: #{res}"
|
20
|
+
return self.parse_body(Yajl::Parser.parse(res.body))
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.do_geocode(address, options={})
|
24
|
+
address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
|
25
|
+
res = self.call_geocoder_service(self.get_url(address, options))
|
26
|
+
return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
|
27
|
+
logger.debug "Yahoo PlaceFinder geocoding. Address: #{address}. Result: #{res}"
|
28
|
+
|
29
|
+
return self.parse_body(Yajl::Parser.parse(res.body))
|
30
|
+
rescue
|
31
|
+
logger.info "Caught an error during Yahoo PlaceFinder geocoding call: "+$!
|
32
|
+
return GeoLoc.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.parse_body(body)
|
36
|
+
count = body['query']['count']
|
37
|
+
if (count == 1)
|
38
|
+
return extract_place(body['query']['results']['Result'])
|
39
|
+
elsif (count > 1)
|
40
|
+
results = body['query']['results']['Result']
|
41
|
+
geoloc = nil
|
42
|
+
results.each do |r|
|
43
|
+
extracted_geoloc = extract_place(r)
|
44
|
+
if geoloc.nil?
|
45
|
+
# first time through, geoloc is still nil, so we make it the geoloc we just extracted
|
46
|
+
geoloc = extracted_geoloc
|
47
|
+
else
|
48
|
+
# second (and subsequent) iterations, we push additional
|
49
|
+
# geoloc onto "geoloc.all"
|
50
|
+
geoloc.all.push(extracted_geoloc)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
return geoloc
|
54
|
+
else
|
55
|
+
return GeoLoc.new
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.extract_place(result)
|
60
|
+
geoloc = GeoLoc.new
|
61
|
+
|
62
|
+
# basics
|
63
|
+
geoloc.lat = result['latitude']
|
64
|
+
geoloc.lng = result['longitude']
|
65
|
+
geoloc.country_code = result['countrycode']
|
66
|
+
geoloc.provider = 'Yahoo! PlaceFinder'
|
67
|
+
|
68
|
+
# extended -- false if not not available
|
69
|
+
geoloc.street_address = result['line1']
|
70
|
+
geoloc.city = result['city']
|
71
|
+
# geoloc.neighborhood = result['neighborhood']
|
72
|
+
# geoloc.county = result['county']
|
73
|
+
geoloc.zip = result['postal']
|
74
|
+
geoloc.country = result['country']
|
75
|
+
# geoloc.quality = result['quality']
|
76
|
+
# geoloc.woeid = result['woeid']
|
77
|
+
# geoloc.woetype = result['woetype']
|
78
|
+
if geoloc.is_us?
|
79
|
+
geoloc.state = result['statecode']
|
80
|
+
else
|
81
|
+
geoloc.state = result['state']
|
82
|
+
end
|
83
|
+
case result['quality'].to_i
|
84
|
+
when 9,10 then geoloc.precision = 'country'
|
85
|
+
when 19..30 then geoloc.precision = 'state'
|
86
|
+
when 39,40 then geoloc.precision = 'city'
|
87
|
+
when 49,50 then geoloc.precision = 'neighborhood'
|
88
|
+
when 59,60,64 then geoloc.precision = 'zip'
|
89
|
+
when 74,75 then geoloc.precision = 'zip+4'
|
90
|
+
when 70..72 then geoloc.precision = 'street'
|
91
|
+
when 80..87 then geoloc.precision = 'address'
|
92
|
+
when 62,63,90,99 then geoloc.precision = 'building'
|
93
|
+
else 'unknown'
|
94
|
+
end
|
95
|
+
|
96
|
+
geoloc.accuracy = %w{unknown country state state city zip zip+4 street address building}.index(geoloc.precision)
|
97
|
+
# geoloc.full_address = "#{geoloc.street_address}, #{result['line2']}, #{geoloc.country}" if (geoloc.street_address && result['line2'])
|
98
|
+
|
99
|
+
# google returns a set of suggested boundaries for the geocoded result
|
100
|
+
# if suggested_bounds = doc.elements['//LatLonBox']
|
101
|
+
# res.suggested_bounds = Bounds.normalize(
|
102
|
+
# [suggested_bounds.attributes['south'], suggested_bounds.attributes['west']],
|
103
|
+
# [suggested_bounds.attributes['north'], suggested_bounds.attributes['east']])
|
104
|
+
# end
|
105
|
+
|
106
|
+
geoloc.success = true
|
107
|
+
|
108
|
+
return geoloc
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
require 'mocha'
|
13
|
+
|
14
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
15
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
16
|
+
require 'geocoder_plus'
|
17
|
+
|
18
|
+
class Test::Unit::TestCase
|
19
|
+
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
# this code is taken from https://github.com/tello/google-v3-geocoder
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
class GoogleV3GeocoderTest < Test::Unit::TestCase
|
6
|
+
include Geokit
|
7
|
+
|
8
|
+
GOOD_JSON = <<-JSON
|
9
|
+
{
|
10
|
+
"status": "OK",
|
11
|
+
"results": [ {
|
12
|
+
"types": [ "street_address" ],
|
13
|
+
"formatted_address": "1288 E Hillsdale Blvd, Foster City, CA 94404, USA",
|
14
|
+
"address_components": [ {
|
15
|
+
"long_name": "1288",
|
16
|
+
"short_name": "1288",
|
17
|
+
"types": [ "street_number" ]
|
18
|
+
}, {
|
19
|
+
"long_name": "E Hillsdale Blvd",
|
20
|
+
"short_name": "E Hillsdale Blvd",
|
21
|
+
"types": [ "route" ]
|
22
|
+
}, {
|
23
|
+
"long_name": "Foster City",
|
24
|
+
"short_name": "Foster City",
|
25
|
+
"types": [ "locality", "political" ]
|
26
|
+
}, {
|
27
|
+
"long_name": "San Mateo",
|
28
|
+
"short_name": "San Mateo",
|
29
|
+
"types": [ "administrative_area_level_3", "political" ]
|
30
|
+
}, {
|
31
|
+
"long_name": "San Mateo",
|
32
|
+
"short_name": "San Mateo",
|
33
|
+
"types": [ "administrative_area_level_2", "political" ]
|
34
|
+
}, {
|
35
|
+
"long_name": "California",
|
36
|
+
"short_name": "CA",
|
37
|
+
"types": [ "administrative_area_level_1", "political" ]
|
38
|
+
}, {
|
39
|
+
"long_name": "United States",
|
40
|
+
"short_name": "US",
|
41
|
+
"types": [ "country", "political" ]
|
42
|
+
}, {
|
43
|
+
"long_name": "94404",
|
44
|
+
"short_name": "94404",
|
45
|
+
"types": [ "postal_code" ]
|
46
|
+
} ],
|
47
|
+
"geometry": {
|
48
|
+
"location": {
|
49
|
+
"lat": 37.5684570,
|
50
|
+
"lng": -122.2660670
|
51
|
+
},
|
52
|
+
"location_type": "ROOFTOP",
|
53
|
+
"viewport": {
|
54
|
+
"southwest": {
|
55
|
+
"lat": 37.5653094,
|
56
|
+
"lng": -122.2692146
|
57
|
+
},
|
58
|
+
"northeast": {
|
59
|
+
"lat": 37.5716046,
|
60
|
+
"lng": -122.2629194
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
} ]
|
65
|
+
}
|
66
|
+
JSON
|
67
|
+
|
68
|
+
def test_get_url_adds_bias_if_set
|
69
|
+
bias = 'thefreakingus'
|
70
|
+
result = Geokit::Geocoders::GoogleV3Geocoder.send :get_url, 'address', :bias => bias
|
71
|
+
assert_match /®ion=#{bias}/, result
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_get_url_escapes_address
|
75
|
+
address = '123 hotel street'
|
76
|
+
result = Geokit::Geocoders::GoogleV3Geocoder.send :get_url, address
|
77
|
+
assert_match /&address=#{Regexp.escape(Geokit::Inflector::url_escape(address))}/, result
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_convert_json_to_geoloc_extracts_result_from_json
|
81
|
+
result = Geokit::Geocoders::GoogleV3Geocoder.send :convert_json_to_geoloc, GOOD_JSON
|
82
|
+
assert result.success
|
83
|
+
assert_equal 1, result.all.size
|
84
|
+
assert_equal '1288 E Hillsdale Blvd, Foster City, CA 94404, USA', result.full_address
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_convert_json_to_geoloc_handles_empty_result_set
|
88
|
+
empty_json = '{"status": "ZERO_RESULTS","results": [ ]}'
|
89
|
+
result = Geokit::Geocoders::GoogleV3Geocoder.send :convert_json_to_geoloc, empty_json
|
90
|
+
assert !result.success
|
91
|
+
assert_equal 1, result.all.size
|
92
|
+
assert_nil result.lat
|
93
|
+
assert_nil result.lng
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_convert_json_to_geoloc_calls_extract_location
|
97
|
+
expected_geoloc = GeoLoc.new
|
98
|
+
expected_geoloc.city = "SOME City"
|
99
|
+
Geokit::Geocoders::GoogleV3Geocoder.expects(:extract_location).returns expected_geoloc
|
100
|
+
|
101
|
+
result = Geokit::Geocoders::GoogleV3Geocoder.send :convert_json_to_geoloc, GOOD_JSON
|
102
|
+
assert_equal result, expected_geoloc
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_convert_json_to_handles_multiple_results
|
106
|
+
address1 = 'add1'
|
107
|
+
address2 = 'add2'
|
108
|
+
|
109
|
+
input_data = {
|
110
|
+
"status" => "OK",
|
111
|
+
"results" =>
|
112
|
+
[
|
113
|
+
{
|
114
|
+
"types" => [ "street_address" ],
|
115
|
+
"formatted_address" => address1,
|
116
|
+
"address_components" => [],
|
117
|
+
"geometry" => {
|
118
|
+
"location"=> {
|
119
|
+
"lat"=> 35.58032,
|
120
|
+
"lng"=> -122.2660670
|
121
|
+
},
|
122
|
+
"location_type"=> "ROOFTOP",
|
123
|
+
"viewport"=> {
|
124
|
+
"southwest"=> {
|
125
|
+
"lat"=> 37.5653094,
|
126
|
+
"lng"=> -122.2692146,
|
127
|
+
},
|
128
|
+
"northeast"=> {
|
129
|
+
"lat"=> 37.5716046,
|
130
|
+
"lng"=> -122.2629194
|
131
|
+
}
|
132
|
+
},
|
133
|
+
},
|
134
|
+
},
|
135
|
+
{
|
136
|
+
"types" => [ "street_address" ],
|
137
|
+
"formatted_address" => address2,
|
138
|
+
"address_components" => [],
|
139
|
+
"geometry" => {
|
140
|
+
"location"=> {
|
141
|
+
"lat"=> 35.58032,
|
142
|
+
"lng"=> -122.2660670
|
143
|
+
},
|
144
|
+
"location_type"=> "ROOFTOP",
|
145
|
+
"viewport"=> {
|
146
|
+
"southwest"=> {
|
147
|
+
"lat"=> 37.5653094,
|
148
|
+
"lng"=> -122.2692146,
|
149
|
+
},
|
150
|
+
"northeast"=> {
|
151
|
+
"lat"=> 37.5716046,
|
152
|
+
"lng"=> -122.2629194
|
153
|
+
}
|
154
|
+
},
|
155
|
+
},
|
156
|
+
}
|
157
|
+
]
|
158
|
+
}
|
159
|
+
result = Geokit::Geocoders::GoogleV3Geocoder.send :convert_json_to_geoloc, Yajl::Encoder.encode(input_data)
|
160
|
+
assert result.success
|
161
|
+
assert_equal 2, result.all.size
|
162
|
+
assert_equal address1, result.all[0].full_address
|
163
|
+
assert_equal address2, result.all[1].full_address
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_extract_location_extracts_result_from_json
|
167
|
+
data = Yajl::Parser.parse(GOOD_JSON)['results'][0]
|
168
|
+
result = Geokit::Geocoders::GoogleV3Geocoder.send :extract_location, data
|
169
|
+
assert_equal 'Foster City', result.city
|
170
|
+
assert_equal 'CA', result.state
|
171
|
+
assert_equal '94404', result.zip
|
172
|
+
assert_equal 'United States', result.country
|
173
|
+
assert_equal 'US', result.country_code
|
174
|
+
assert_equal '1288 E Hillsdale Blvd', result.street_address
|
175
|
+
assert_equal '1288 E Hillsdale Blvd, Foster City, CA 94404, USA', result.full_address
|
176
|
+
assert_equal 37.5653094, result.suggested_bounds.sw.lat
|
177
|
+
assert_equal -122.2692146, result.suggested_bounds.sw.lng
|
178
|
+
assert_equal 37.5716046, result.suggested_bounds.ne.lat
|
179
|
+
assert_equal -122.2629194, result.suggested_bounds.ne.lng
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_extract_joins_street_address_with_no_number
|
183
|
+
route_name = 'Foo'
|
184
|
+
data =
|
185
|
+
{
|
186
|
+
"types" => [ "street_address" ],
|
187
|
+
"formatted_address" => 'address1',
|
188
|
+
"address_components" => [
|
189
|
+
{'types' => ['route'], 'long_name' => route_name, 'short_name' => route_name}
|
190
|
+
],
|
191
|
+
"geometry" => {
|
192
|
+
"location"=> {
|
193
|
+
"lat"=> 35.58032,
|
194
|
+
"lng"=> -122.2660670
|
195
|
+
},
|
196
|
+
"location_type"=> "ROOFTOP",
|
197
|
+
"viewport"=> {
|
198
|
+
"southwest"=> {
|
199
|
+
"lat"=> 37.5653094,
|
200
|
+
"lng"=> -122.2692146,
|
201
|
+
},
|
202
|
+
"northeast"=> {
|
203
|
+
"lat"=> 37.5716046,
|
204
|
+
"lng"=> -122.2629194
|
205
|
+
}
|
206
|
+
},
|
207
|
+
},
|
208
|
+
}
|
209
|
+
|
210
|
+
result = Geokit::Geocoders::GoogleV3Geocoder.send :extract_location, data
|
211
|
+
assert_equal route_name, result.street_address
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_extract_joins_street_address_with_no_route
|
215
|
+
number = '358'
|
216
|
+
data =
|
217
|
+
{
|
218
|
+
"types" => [ "street_address" ],
|
219
|
+
"formatted_address" => 'address1',
|
220
|
+
"address_components" => [
|
221
|
+
{'types' => ['street_number'], 'long_name' => number, 'short_name' => number},
|
222
|
+
],
|
223
|
+
"geometry" => {
|
224
|
+
"location"=> {
|
225
|
+
"lat"=> 35.58032,
|
226
|
+
"lng"=> -122.2660670
|
227
|
+
},
|
228
|
+
"location_type"=> "ROOFTOP",
|
229
|
+
"viewport"=> {
|
230
|
+
"southwest"=> {
|
231
|
+
"lat"=> 37.5653094,
|
232
|
+
"lng"=> -122.2692146,
|
233
|
+
},
|
234
|
+
"northeast"=> {
|
235
|
+
"lat"=> 37.5716046,
|
236
|
+
"lng"=> -122.2629194
|
237
|
+
}
|
238
|
+
},
|
239
|
+
},
|
240
|
+
}
|
241
|
+
|
242
|
+
result = Geokit::Geocoders::GoogleV3Geocoder.send :extract_location, data
|
243
|
+
assert_equal number, result.street_address
|
244
|
+
end
|
245
|
+
|
246
|
+
def test_extract_joins_street_address_with_number_and_route
|
247
|
+
route_name = 'Foo'
|
248
|
+
number = '3854'
|
249
|
+
data =
|
250
|
+
{
|
251
|
+
"types" => [ "street_address" ],
|
252
|
+
"formatted_address" => 'address1',
|
253
|
+
"address_components" => [
|
254
|
+
{'types' => ['route'], 'long_name' => route_name, 'short_name' => route_name},
|
255
|
+
{'types' => ['street_number'], 'long_name' => number, 'short_name' => number}
|
256
|
+
],
|
257
|
+
"geometry" => {
|
258
|
+
"location"=> {
|
259
|
+
"lat"=> 35.58032,
|
260
|
+
"lng"=> -122.2660670
|
261
|
+
},
|
262
|
+
"location_type"=> "ROOFTOP",
|
263
|
+
"viewport"=> {
|
264
|
+
"southwest"=> {
|
265
|
+
"lat"=> 37.5653094,
|
266
|
+
"lng"=> -122.2692146,
|
267
|
+
},
|
268
|
+
"northeast"=> {
|
269
|
+
"lat"=> 37.5716046,
|
270
|
+
"lng"=> -122.2629194
|
271
|
+
}
|
272
|
+
},
|
273
|
+
},
|
274
|
+
}
|
275
|
+
|
276
|
+
result = Geokit::Geocoders::GoogleV3Geocoder.send :extract_location, data
|
277
|
+
assert_equal number + ' ' + route_name, result.street_address
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestYahooPlaceFinderGeocoder < Test::Unit::TestCase
|
4
|
+
|
5
|
+
# default is true
|
6
|
+
MOCK = false
|
7
|
+
|
8
|
+
US_FULL_ADDRESS=<<-EOF.strip
|
9
|
+
{"query":{"count":1,"created":"2011-04-03T01:20:47Z","lang":"en-US","results":{"Result":{"quality":"87","latitude":"37.792418","longitude":"-122.393913","offsetlat":"37.792332","offsetlon":"-122.394027","radius":"500","name":null,"line1":"100 Spear St","line2":"San Francisco, CA 94105-1578","line3":null,"line4":"United States","house":"100","street":"Spear St","xstreet":null,"unittype":null,"unit":null,"postal":"94105-1578","neighborhood":null,"city":"San Francisco","county":"San Francisco County","state":"California","country":"United States","countrycode":"US","statecode":"CA","countycode":null,"uzip":"94105","hash":"0FA06819B5F53E75","woeid":"12797156","woetype":"11"}}}}
|
10
|
+
EOF
|
11
|
+
|
12
|
+
US_CITY=<<-EOF.strip
|
13
|
+
{"query":{"count":1,"created":"2011-04-04T15:10:42Z","lang":"en-US","results":{"Result":{"quality":"40","latitude":"37.777125","longitude":"-122.419644","offsetlat":"37.777125","offsetlon":"-122.419644","radius":"10700","name":null,"line1":null,"line2":"San Francisco, CA","line3":null,"line4":"United States","house":null,"street":null,"xstreet":null,"unittype":null,"unit":null,"postal":null,"neighborhood":null,"city":"San Francisco","county":"San Francisco County","state":"California","country":"United States","countrycode":"US","statecode":"CA","countycode":null,"uzip":"94102","hash":null,"woeid":"2487956","woetype":"7"}}}}
|
14
|
+
EOF
|
15
|
+
|
16
|
+
context "given a US full address" do
|
17
|
+
setup do
|
18
|
+
full_address = '100 Spear St, San Francisco, CA, 94105-1522, US'
|
19
|
+
if MOCK
|
20
|
+
response = Typhoeus::Response.new(@success_response.merge(:body => US_FULL_ADDRESS))
|
21
|
+
Geokit::Geocoders::YahooPlaceFinderGeocoder.expects(:make_request).with('get', :params => {:q => "select * from geo.placefinder where text='#{full_address}'", :format => 'json'}).returns(response)
|
22
|
+
end
|
23
|
+
@pf = Geokit::Geocoders::YahooPlaceFinderGeocoder.geocode(full_address)
|
24
|
+
end
|
25
|
+
|
26
|
+
should "return correct geo location" do
|
27
|
+
do_full_address_assertions(@pf)
|
28
|
+
assert @pf.is_us?
|
29
|
+
end
|
30
|
+
|
31
|
+
should "have 'address' accuracy" do
|
32
|
+
assert_equal 'address', @pf.precision
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "given a US city" do
|
37
|
+
setup do
|
38
|
+
city = 'San Francisco, CA'
|
39
|
+
if MOCK
|
40
|
+
response = Typhoeus::Response.new(@success_response.merge(:body => US_CITY))
|
41
|
+
Geokit::Geocoders::YahooPlaceFinderGeocoder.expects(:make_request).with('get', :params => {:q => "select * from geo.placefinder where text='#{city}'", :format => 'json'}).returns(response)
|
42
|
+
end
|
43
|
+
@pf = Geokit::Geocoders::YahooPlaceFinderGeocoder.geocode(city)
|
44
|
+
end
|
45
|
+
|
46
|
+
should "return correct geo location" do
|
47
|
+
do_city_assertions(@pf)
|
48
|
+
assert @pf.is_us?
|
49
|
+
end
|
50
|
+
|
51
|
+
should "have 'address' accuracy" do
|
52
|
+
assert_equal 'city', @pf.precision
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "given a non-US street" do
|
57
|
+
setup do
|
58
|
+
full_address = 'Jalan Gandaria Tengah, Jakarta 12140, Indonesia'
|
59
|
+
if MOCK
|
60
|
+
response = Typhoeus::Response.new(@success_response.merge(:body => US_FULL_ADDRESS))
|
61
|
+
Geokit::Geocoders::YahooPlaceFinderGeocoder.expects(:make_request).with('get', :params => {:q => "select * from geo.placefinder where text='#{full_address}'", :format => 'json'}).returns(response)
|
62
|
+
end
|
63
|
+
@pf = Geokit::Geocoders::YahooPlaceFinderGeocoder.geocode(full_address)
|
64
|
+
end
|
65
|
+
|
66
|
+
should "return correct geo location" do
|
67
|
+
do_non_us_street_assertions(@pf)
|
68
|
+
end
|
69
|
+
|
70
|
+
should "have 'address' accuracy" do
|
71
|
+
assert_equal 'street', @pf.precision
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "given a non-US city" do
|
76
|
+
setup do
|
77
|
+
city = 'Jakarta, Indonesia'
|
78
|
+
if MOCK
|
79
|
+
response = Typhoeus::Response.new(@success_response.merge(:body => US_CITY))
|
80
|
+
Geokit::Geocoders::YahooPlaceFinderGeocoder.expects(:make_request).with('get', :params => {:q => "select * from geo.placefinder where text='#{city}'", :format => 'json'}).returns(response)
|
81
|
+
end
|
82
|
+
@pf = Geokit::Geocoders::YahooPlaceFinderGeocoder.geocode(city)
|
83
|
+
end
|
84
|
+
|
85
|
+
should "return correct geo location" do
|
86
|
+
do_non_us_city_assertions(@pf)
|
87
|
+
end
|
88
|
+
|
89
|
+
should "have 'address' accuracy" do
|
90
|
+
assert_equal 'city', @pf.precision
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# next two methods do the assertions for both address-level and city-level lookups
|
101
|
+
def do_full_address_assertions(resp)
|
102
|
+
assert_equal "CA", resp.state
|
103
|
+
assert_equal "San Francisco", resp.city
|
104
|
+
assert_equal "37.792418,-122.393913", resp.ll
|
105
|
+
assert resp.is_us?
|
106
|
+
assert_equal "100 Spear St, San Francisco, CA, 94105-1578, US", resp.full_address
|
107
|
+
assert_equal "Yahoo! PlaceFinder", resp.provider
|
108
|
+
end
|
109
|
+
|
110
|
+
def do_city_assertions(resp)
|
111
|
+
assert_equal "CA", resp.state
|
112
|
+
assert_equal "San Francisco", resp.city
|
113
|
+
assert_equal "37.777125,-122.419644", resp.ll
|
114
|
+
assert resp.is_us?
|
115
|
+
assert_equal "San Francisco, CA, US", resp.full_address
|
116
|
+
assert_nil resp.street_address
|
117
|
+
assert_equal "Yahoo! PlaceFinder", resp.provider
|
118
|
+
end
|
119
|
+
|
120
|
+
def do_non_us_street_assertions(resp)
|
121
|
+
assert_equal "D K I Jakarta", resp.state
|
122
|
+
assert_equal "Kebayoran Baru", resp.city
|
123
|
+
assert_equal "-6.246406,106.789707", resp.ll
|
124
|
+
assert_equal false, resp.is_us?
|
125
|
+
assert_equal "Jalan Gandaria Tengah 3, Kebayoran Baru, D K I Jakarta, 12140, ID", resp.full_address
|
126
|
+
assert_equal "Yahoo! PlaceFinder", resp.provider
|
127
|
+
end
|
128
|
+
|
129
|
+
def do_non_us_city_assertions(resp)
|
130
|
+
assert_equal "DKI Jakarta", resp.state
|
131
|
+
assert_equal "Jakarta", resp.city
|
132
|
+
assert_equal "-6.17144,106.82782", resp.ll
|
133
|
+
assert_equal false, resp.is_us?
|
134
|
+
assert_equal "Jakarta, DKI Jakarta, ID", resp.full_address
|
135
|
+
assert_nil resp.street_address
|
136
|
+
assert_equal "Yahoo! PlaceFinder", resp.provider
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
metadata
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: geocoder_plus
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Fajar A B
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-04-06 00:00:00 +07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
hash: 3
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 5
|
31
|
+
- 0
|
32
|
+
version: 1.5.0
|
33
|
+
version_requirements: *id001
|
34
|
+
name: geokit
|
35
|
+
prerelease: false
|
36
|
+
type: :runtime
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 59
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
- 8
|
47
|
+
- 2
|
48
|
+
version: 0.8.2
|
49
|
+
version_requirements: *id002
|
50
|
+
name: yajl-ruby
|
51
|
+
prerelease: false
|
52
|
+
type: :runtime
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
version_requirements: *id003
|
64
|
+
name: shoulda
|
65
|
+
prerelease: false
|
66
|
+
type: :development
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
version_requirements: *id004
|
78
|
+
name: mocha
|
79
|
+
prerelease: false
|
80
|
+
type: :development
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
hash: 23
|
88
|
+
segments:
|
89
|
+
- 1
|
90
|
+
- 0
|
91
|
+
- 0
|
92
|
+
version: 1.0.0
|
93
|
+
version_requirements: *id005
|
94
|
+
name: bundler
|
95
|
+
prerelease: false
|
96
|
+
type: :development
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
hash: 7
|
104
|
+
segments:
|
105
|
+
- 1
|
106
|
+
- 5
|
107
|
+
- 2
|
108
|
+
version: 1.5.2
|
109
|
+
version_requirements: *id006
|
110
|
+
name: jeweler
|
111
|
+
prerelease: false
|
112
|
+
type: :development
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
hash: 3
|
120
|
+
segments:
|
121
|
+
- 0
|
122
|
+
version: "0"
|
123
|
+
version_requirements: *id007
|
124
|
+
name: rcov
|
125
|
+
prerelease: false
|
126
|
+
type: :development
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
hash: 3
|
134
|
+
segments:
|
135
|
+
- 1
|
136
|
+
- 5
|
137
|
+
- 0
|
138
|
+
version: 1.5.0
|
139
|
+
version_requirements: *id008
|
140
|
+
name: geokit
|
141
|
+
prerelease: false
|
142
|
+
type: :runtime
|
143
|
+
- !ruby/object:Gem::Dependency
|
144
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
hash: 59
|
150
|
+
segments:
|
151
|
+
- 0
|
152
|
+
- 8
|
153
|
+
- 2
|
154
|
+
version: 0.8.2
|
155
|
+
version_requirements: *id009
|
156
|
+
name: yajl-ruby
|
157
|
+
prerelease: false
|
158
|
+
type: :runtime
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ">"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
hash: 3
|
166
|
+
segments:
|
167
|
+
- 0
|
168
|
+
version: "0"
|
169
|
+
version_requirements: *id010
|
170
|
+
name: shoulda
|
171
|
+
prerelease: false
|
172
|
+
type: :development
|
173
|
+
- !ruby/object:Gem::Dependency
|
174
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
175
|
+
none: false
|
176
|
+
requirements:
|
177
|
+
- - ">"
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
hash: 3
|
180
|
+
segments:
|
181
|
+
- 0
|
182
|
+
version: "0"
|
183
|
+
version_requirements: *id011
|
184
|
+
name: mocha
|
185
|
+
prerelease: false
|
186
|
+
type: :development
|
187
|
+
description: This gem consists two additional geocoders for geokit, Yahoo! PlaceFinder and Google V3
|
188
|
+
email: fajar.ab@gmail.com
|
189
|
+
executables: []
|
190
|
+
|
191
|
+
extensions: []
|
192
|
+
|
193
|
+
extra_rdoc_files:
|
194
|
+
- LICENSE.txt
|
195
|
+
- README
|
196
|
+
- README.rdoc
|
197
|
+
files:
|
198
|
+
- lib/geocoder_plus.rb
|
199
|
+
- lib/geocoders/google_v3_geocoder.rb
|
200
|
+
- lib/geocoders/yahoo_place_finder_geocoder.rb
|
201
|
+
- LICENSE.txt
|
202
|
+
- README
|
203
|
+
- README.rdoc
|
204
|
+
- test/helper.rb
|
205
|
+
- test/test_geocoder_plus.rb
|
206
|
+
- test/test_google_v3_geocoder.rb
|
207
|
+
- test/test_yahoo_place_finder_geocoder.rb
|
208
|
+
has_rdoc: true
|
209
|
+
homepage: http://github.com/fajarb/geocoder_plus
|
210
|
+
licenses:
|
211
|
+
- MIT
|
212
|
+
post_install_message:
|
213
|
+
rdoc_options: []
|
214
|
+
|
215
|
+
require_paths:
|
216
|
+
- lib
|
217
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
218
|
+
none: false
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
hash: 3
|
223
|
+
segments:
|
224
|
+
- 0
|
225
|
+
version: "0"
|
226
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
227
|
+
none: false
|
228
|
+
requirements:
|
229
|
+
- - ">="
|
230
|
+
- !ruby/object:Gem::Version
|
231
|
+
hash: 3
|
232
|
+
segments:
|
233
|
+
- 0
|
234
|
+
version: "0"
|
235
|
+
requirements: []
|
236
|
+
|
237
|
+
rubyforge_project:
|
238
|
+
rubygems_version: 1.6.1
|
239
|
+
signing_key:
|
240
|
+
specification_version: 3
|
241
|
+
summary: Additional geocoders for geokit gem
|
242
|
+
test_files:
|
243
|
+
- test/helper.rb
|
244
|
+
- test/test_geocoder_plus.rb
|
245
|
+
- test/test_google_v3_geocoder.rb
|
246
|
+
- test/test_yahoo_place_finder_geocoder.rb
|