google-geocode 1.0.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/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright 2006 Eric Hodel, The Robot Co-op. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ 3. Neither the names of the authors nor the names of their contributors
13
+ may be used to endorse or promote products derived from this software
14
+ without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
17
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
20
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+
data/Manifest.txt ADDED
@@ -0,0 +1,7 @@
1
+ LICENSE
2
+ Manifest.txt
3
+ README
4
+ Rakefile
5
+ lib/google_geocode.rb
6
+ test/test_google_geocode.rb
7
+ test/uri_stub.rb
data/README ADDED
@@ -0,0 +1,35 @@
1
+ = google-geocode
2
+
3
+ Rubyforge Project:
4
+
5
+ http://rubyforge.org/projects/rctools
6
+
7
+ Documentation:
8
+
9
+ http://dev.robotcoop.com/Libraries/google-geocode
10
+
11
+ == About
12
+
13
+ google-geocode implements Google's Geocoding API.
14
+
15
+ == Installing google-geocode
16
+
17
+ Just install the gem:
18
+
19
+ $ sudo gem install google-geocode
20
+
21
+ == Using google-geocode
22
+
23
+ First you need a Google Maps API key. Yuo can register for one here:
24
+
25
+ http://www.google.com/apis/maps/signup.html
26
+
27
+ Then you create a GoogleGeocode object and start locating addresses:
28
+
29
+ require 'rubygems'
30
+ require 'google_geocode'
31
+
32
+ gg = GoogleGeocode.new application_id
33
+ location = gg.locate '1600 Amphitheater Pkwy, Mountain View, CA'
34
+ p location.coordinates
35
+
data/Rakefile ADDED
@@ -0,0 +1,66 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/gempackagetask'
6
+
7
+ $VERBOSE = nil
8
+
9
+ spec = Gem::Specification.new do |s|
10
+ s.name = 'google-geocode'
11
+ s.version = '1.0.0'
12
+ s.summary = 'Google Geocoder API Library'
13
+ s.description = 'Map addresses to latitude and longitude with Google\'s Geocoder.'
14
+ s.author = 'Eric Hodel'
15
+ s.email = 'eric@robotcoop.com'
16
+
17
+ s.has_rdoc = true
18
+ s.files = File.read('Manifest.txt').split($/)
19
+ s.require_path = 'lib'
20
+ end
21
+
22
+ desc 'Run tests'
23
+ task :default => [ :test ]
24
+
25
+ Rake::TestTask.new('test') do |t|
26
+ t.libs << 'test'
27
+ t.pattern = 'test/test_*.rb'
28
+ t.verbose = true
29
+ end
30
+
31
+ desc 'Update Manifest.txt'
32
+ task :update_manifest do
33
+ sh "find . -type f | sed -e 's%./%%' | egrep -v 'svn|swp|~' | egrep -v '^(doc|pkg)/' | sort > Manifest.txt"
34
+ end
35
+
36
+ desc 'Generate RDoc'
37
+ Rake::RDocTask.new :rdoc do |rd|
38
+ rd.rdoc_dir = 'doc'
39
+ rd.rdoc_files.add 'lib', 'README', 'LICENSE'
40
+ rd.main = 'README'
41
+ rd.options << '-d' if `which dot` =~ /\/dot/
42
+ rd.options << '-t Google Geocode'
43
+ end
44
+
45
+ desc 'Generate RDoc for dev.robotcoop.com'
46
+ Rake::RDocTask.new :dev_rdoc do |rd|
47
+ rd.rdoc_dir = '../../../www/trunk/dev/html/Libraries/google-geocode'
48
+ rd.rdoc_files.add 'lib', 'README', 'LICENSE'
49
+ rd.main = 'README'
50
+ rd.options << '-d' if `which dot` =~ /\/dot/
51
+ rd.options << '-t Google Geocode'
52
+ end
53
+
54
+ desc 'Build Gem'
55
+ Rake::GemPackageTask.new spec do |pkg|
56
+ pkg.need_tar = true
57
+ end
58
+
59
+ desc 'Clean up'
60
+ task :clean => [ :clobber_rdoc, :clobber_package ]
61
+
62
+ desc 'Clean up'
63
+ task :clobber => [ :clean ]
64
+
65
+ # vim: syntax=Ruby
66
+
@@ -0,0 +1,123 @@
1
+ require 'open-uri'
2
+ require 'rexml/document'
3
+
4
+ ##
5
+ # Library for looking up coordinates with Google's Geocoding API.
6
+ #
7
+ # http://www.google.com/apis/maps/documentation/#Geocoding_HTTP_Request
8
+
9
+ class GoogleGeocode
10
+
11
+ ##
12
+ # Base error class
13
+
14
+ class Error < RuntimeError; end
15
+
16
+ ##
17
+ # Raised when you try to locate an invalid address.
18
+
19
+ class AddressError < Error; end
20
+
21
+ ##
22
+ # Raised when you use an invalid key.
23
+
24
+ class KeyError < Error; end
25
+
26
+ ##
27
+ # Location struct
28
+
29
+ Location = Struct.new :address, :latitude, :longitude
30
+
31
+ ##
32
+ # Creates a new GoogleGeocode that will use Google Maps API key +key+. You
33
+ # can sign up for an API key here:
34
+ #
35
+ # http://www.google.com/apis/maps/signup.html
36
+
37
+ def initialize(key)
38
+ @key = key
39
+ @url = URI.parse 'http://maps.google.com/maps/geo'
40
+ end
41
+
42
+ ##
43
+ # Locates +address+ returning a Location struct.
44
+
45
+ def locate(address)
46
+ get :q => address
47
+ end
48
+
49
+ private
50
+
51
+ def parse_response(xml)
52
+ l = Location.new
53
+
54
+ l.address = xml.elements['/kml/Response/Placemark/address'].text
55
+
56
+ coordinates = xml.elements['/kml/Response/Placemark/Point/coordinates'].text
57
+ l.longitude, l.latitude, = coordinates.split(',').map { |v| v.to_f }
58
+
59
+ return l
60
+ end
61
+
62
+ def check_error(obj)
63
+ obj = REXML::Document.new obj.read unless REXML::Document === obj
64
+
65
+ status = obj.elements['/kml/Response/Status/code'].text.to_i
66
+ case status
67
+ when 200 # ignore, ok
68
+ when 602
69
+ raise AddressError, 'invalid address'
70
+ when 610
71
+ raise KeyError, 'invalid key'
72
+ else
73
+ raise Error, "unknown error #{status}"
74
+ end
75
+ end
76
+
77
+ def get(params)
78
+ url = make_url params
79
+
80
+ url.open do |xml|
81
+ res = REXML::Document.new xml.read
82
+
83
+ check_error res
84
+ return parse_response(res)
85
+ end
86
+ rescue OpenURI::HTTPError => e
87
+ check_error e.io
88
+ raise
89
+ end
90
+
91
+ def make_url(params)
92
+ params[:key] = @key
93
+ params[:output] = 'xml'
94
+
95
+ escaped_params = params.sort_by { |k,v| k.to_s }.map do |k,v|
96
+ "#{URI.escape k.to_s}=#{URI.escape v.to_s}"
97
+ end
98
+
99
+ url = @url.dup
100
+ url.query = escaped_params.join '&'
101
+ return url
102
+ end
103
+
104
+ end
105
+
106
+ ##
107
+ # A Location contains the following fields:
108
+ #
109
+ # +latitude+:: Latitude of the location
110
+ # +longitude+:: Longitude of the location
111
+ # +address+:: Street address of the result.
112
+
113
+ class GoogleGeocode::Location
114
+
115
+ ##
116
+ # The coordinates for this location.
117
+
118
+ def coordinates
119
+ [latitude, longitude]
120
+ end
121
+
122
+ end
123
+
@@ -0,0 +1,74 @@
1
+ require 'test/unit'
2
+ require 'test/uri_stub'
3
+
4
+ require 'google_geocode'
5
+
6
+ class TestGoogleGeocode < Test::Unit::TestCase
7
+
8
+ def setup
9
+ URI::HTTP.responses = []
10
+ URI::HTTP.uris = []
11
+
12
+ @gg = GoogleGeocode.new 'APP_ID'
13
+ end
14
+
15
+ def test_locate
16
+ URI::HTTP.responses << <<-EOF.strip
17
+ <?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://earth.google.com/kml/2.0"><Response><name>1600 Amphitheatre Parkway, Mountain View, CA</name><Status><code>200</code><request>geocode</request></Status><Placemark><address>1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA</address><AddressDetails xmlns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"><Country><CountryNameCode>US</CountryNameCode><AdministrativeArea><AdministrativeAreaName>CA</AdministrativeAreaName><SubAdministrativeArea><SubAdministrativeAreaName>Santa Clara</SubAdministrativeAreaName><Locality><LocalityName>Mountain View</LocalityName><Thoroughfare><ThoroughfareName>1600 Amphitheatre Pkwy</ThoroughfareName></Thoroughfare><PostalCode><PostalCodeNumber>94043</PostalCodeNumber></PostalCode></Locality></SubAdministrativeArea></AdministrativeArea></Country></AddressDetails><Point><coordinates>-122.083739,37.423021,0</coordinates></Point></Placemark></Response></kml>
18
+ EOF
19
+
20
+ location = GoogleGeocode::Location.new
21
+ location.address = '1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA'
22
+ location.latitude = 37.423021
23
+ location.longitude = -122.083739
24
+
25
+ assert_equal location,
26
+ @gg.locate('1600 Amphitheatre Parkway, Mountain View, CA')
27
+
28
+ assert_equal true, URI::HTTP.responses.empty?
29
+ assert_equal 1, URI::HTTP.uris.length
30
+ assert_equal 'http://maps.google.com/maps/geo?key=APP_ID&output=xml&q=1600%20Amphitheatre%20Parkway,%20Mountain%20View,%20CA',
31
+ URI::HTTP.uris.first
32
+ end
33
+
34
+ def test_locate_bad_key
35
+ URI::HTTP.responses << <<-EOF.strip
36
+ <?xml version='1.0' encoding='UTF-8'?><kml xmlns='http://earth.google.com/kml/2.0'><Response><name>1600 Amphitheater Pkwy, Mountain View, CA</name><Status><code>610</code><request>geocode</request></Status></Response></kml>
37
+ EOF
38
+
39
+ @gg.locate 'x'
40
+
41
+ rescue GoogleGeocode::KeyError => e
42
+ assert_equal 'invalid key', e.message
43
+ else
44
+ flunk 'Error expected'
45
+ end
46
+
47
+ def test_locate_bad_address
48
+ URI::HTTP.responses << <<-EOF.strip
49
+ <?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://earth.google.com/kml/2.0"><Response><name>1600</name><Status><code>602</code><request>geocode</request></Status></Response></kml>
50
+ EOF
51
+
52
+ @gg.locate 'x'
53
+
54
+ rescue GoogleGeocode::AddressError => e
55
+ assert_equal 'invalid address', e.message
56
+ else
57
+ flunk 'Error expected'
58
+ end
59
+
60
+ end
61
+
62
+ class TestGoogleGeocodeLocation < Test::Unit::TestCase
63
+
64
+ def test_coordinates
65
+ location = GoogleGeocode::Location.new
66
+ location.address = '1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA'
67
+ location.latitude = 37.423021
68
+ location.longitude = -122.083739
69
+
70
+ assert_equal [37.423021, -122.083739], location.coordinates
71
+ end
72
+
73
+ end
74
+
data/test/uri_stub.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'open-uri'
2
+
3
+ class URI::HTTP
4
+
5
+ class << self
6
+ attr_accessor :responses, :uris
7
+ end
8
+
9
+ alias original_open open
10
+
11
+ def open
12
+ self.class.uris << self.to_s
13
+ yield StringIO.new(self.class.responses.shift)
14
+ end
15
+
16
+ end
17
+
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11.15
3
+ specification_version: 1
4
+ name: google-geocode
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.0.0
7
+ date: 2006-06-12 00:00:00 -07:00
8
+ summary: Google Geocoder API Library
9
+ require_paths:
10
+ - lib
11
+ email: eric@robotcoop.com
12
+ homepage:
13
+ rubyforge_project:
14
+ description: Map addresses to latitude and longitude with Google's Geocoder.
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Eric Hodel
31
+ files:
32
+ - LICENSE
33
+ - Manifest.txt
34
+ - README
35
+ - Rakefile
36
+ - lib/google_geocode.rb
37
+ - test/test_google_geocode.rb
38
+ - test/uri_stub.rb
39
+ test_files: []
40
+
41
+ rdoc_options: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ executables: []
46
+
47
+ extensions: []
48
+
49
+ requirements: []
50
+
51
+ dependencies: []
52
+