geocoda 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/README.txt +36 -0
- data/lib/geocoda/client.rb +81 -0
- data/lib/geocoda/response.rb +173 -0
- data/lib/geocoda.rb +46 -0
- metadata +71 -0
data/README.txt
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
== DESCRIPTION:
|
2
|
+
|
3
|
+
Used to interact with Googles Geocoding API
|
4
|
+
|
5
|
+
|
6
|
+
== REQUIREMENTS:
|
7
|
+
|
8
|
+
patron
|
9
|
+
json
|
10
|
+
|
11
|
+
|
12
|
+
== INSTALL:
|
13
|
+
|
14
|
+
$ gem build geocoda.gemspec
|
15
|
+
$ sudo gem install geocoda-x.x.x.gem
|
16
|
+
|
17
|
+
|
18
|
+
== USAGE:
|
19
|
+
|
20
|
+
Geocoda.search('123 My St, MyCity, NY')
|
21
|
+
# returns an array of addresses or throws an exception
|
22
|
+
|
23
|
+
Geocoda.first('123 My St, MyCity, NY')
|
24
|
+
# returns a single address or throws an exception
|
25
|
+
|
26
|
+
See Geocoda::Response.check_status for errors thrown depending on the results
|
27
|
+
Errors in the HTTP call throw a Geocoda::ConnectionError
|
28
|
+
|
29
|
+
Your google API key is required. You may set this in one of two ways.
|
30
|
+
|
31
|
+
1. Set the class variable with Geocoda::Client.key = 'xxxxxx'
|
32
|
+
$ Geocoda.search('My Address') # uses default key
|
33
|
+
|
34
|
+
2. Send the key with your searches
|
35
|
+
$ Geocoda.search('My Address', key) # uses defined key
|
36
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Geocoda
|
2
|
+
|
3
|
+
class Client
|
4
|
+
|
5
|
+
##
|
6
|
+
# Returns the default key
|
7
|
+
def self.key
|
8
|
+
@key ||= raise(MapKeyError, 'Missing Key: Geocoda::Client.key=(key)')
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# Sets the default key
|
13
|
+
def self.key=(key)
|
14
|
+
@key = key
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Initialize the Client
|
19
|
+
#
|
20
|
+
# If the key is passed it will be used in place of the default key
|
21
|
+
def initialize(key=nil)
|
22
|
+
@key ||= self.class.key
|
23
|
+
@http = Patron::Session.new
|
24
|
+
@http.base_url = 'http://maps.google.com/maps/geo'
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Search for addresses that match a string
|
29
|
+
#
|
30
|
+
# @param [String] Address required for search
|
31
|
+
# @return [Array<Address>] An array of addresses
|
32
|
+
# @raise [StandardError] on errors
|
33
|
+
def search(address)
|
34
|
+
begin
|
35
|
+
response = @http.get(hash_to_string(:q => address))
|
36
|
+
rescue StandardError => e
|
37
|
+
raise(ConnectionError, e.message)
|
38
|
+
end
|
39
|
+
unless response.status == 200
|
40
|
+
raise(ConnectionError, "Response Code: #{response.status}")
|
41
|
+
end
|
42
|
+
Response.new(response.body).addresses
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Search for the first address that matches a string
|
47
|
+
#
|
48
|
+
# @see Geocoda::Client#search
|
49
|
+
# @param [String] Address required for search
|
50
|
+
# @return [Address] An address object
|
51
|
+
# @raise [StandardError] on errors
|
52
|
+
def first(address)
|
53
|
+
search.first
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
##
|
59
|
+
# Set the default parameters to use in searches
|
60
|
+
def default_params
|
61
|
+
{:key => @key, :gl => 'US', :output => 'json'}
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Convert a hash into a query parameter
|
66
|
+
#
|
67
|
+
# Example:
|
68
|
+
# {:q => 'my address', :output => 'json'}
|
69
|
+
# ?q=my%20address&output=json
|
70
|
+
#
|
71
|
+
# @return [String]
|
72
|
+
def hash_to_string(hash)
|
73
|
+
output = default_params.update(hash).map do |key, value|
|
74
|
+
"#{key}=#{@http.escape(value.to_s)}"
|
75
|
+
end.join("&")
|
76
|
+
"?#{output}"
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
module Geocoda
|
2
|
+
|
3
|
+
class Response
|
4
|
+
attr_reader :json
|
5
|
+
|
6
|
+
##
|
7
|
+
# Initialize the response and check for errors in the Status code
|
8
|
+
#
|
9
|
+
# @see check_status
|
10
|
+
# @raise [StandardError]
|
11
|
+
def initialize(json)
|
12
|
+
@json = json
|
13
|
+
@hash = JSON.parse(json)
|
14
|
+
check_status
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Return an array of addresses that matched the search
|
19
|
+
#
|
20
|
+
# @return [Array<Address>]
|
21
|
+
def addresses
|
22
|
+
@addresses ||= @hash["Placemark"].map {|place| Address.new(place)}
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Check the status returned by Google and throw exception on
|
27
|
+
# results that are not 200
|
28
|
+
#
|
29
|
+
# @raise [StandardError]
|
30
|
+
def check_status
|
31
|
+
case @hash["Status"]["code"]
|
32
|
+
when 200 then
|
33
|
+
true
|
34
|
+
when 500
|
35
|
+
raise ServerError, "Unknown server error"
|
36
|
+
when 601
|
37
|
+
raise MissingAddressError, "Missing address"
|
38
|
+
when 602
|
39
|
+
raise UnknownAddressError, "Unknown address"
|
40
|
+
when 603
|
41
|
+
raise UnavailableAddressError, "Unavailable address"
|
42
|
+
when 610
|
43
|
+
raise InvalidMapKeyError, "Invalid map key"
|
44
|
+
when 620
|
45
|
+
raise TooManyQueriesError, "Too many queries for map key"
|
46
|
+
else
|
47
|
+
raise UnknownError, "Unknown error: #{@hash['code']}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
class Address
|
54
|
+
##
|
55
|
+
# Initialize class
|
56
|
+
#
|
57
|
+
# set @hash to the json parsed hash
|
58
|
+
def initialize(hash)
|
59
|
+
@hash = hash
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Address
|
64
|
+
#
|
65
|
+
# @return [String] address
|
66
|
+
def address
|
67
|
+
@address ||= @hash["address"]
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Street
|
72
|
+
#
|
73
|
+
# @return [String] street
|
74
|
+
def street
|
75
|
+
@street ||= @hash["AddressDetails"]["Country"]["AdministrativeArea"]\
|
76
|
+
["Locality"]["Thoroughfare"]["ThoroughfareName"] rescue nil
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# City
|
81
|
+
#
|
82
|
+
# @return [String] city
|
83
|
+
def city
|
84
|
+
@city ||= @hash["AddressDetails"]["Country"]["AdministrativeArea"]\
|
85
|
+
["Locality"]["LocalityName"] rescue nil
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# State
|
90
|
+
#
|
91
|
+
# @return [String] state
|
92
|
+
def state
|
93
|
+
@state ||= @hash["AddressDetails"]["Country"]["AdministrativeArea"]\
|
94
|
+
["AdministrativeAreaName"] rescue nil
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# Zipcode
|
99
|
+
#
|
100
|
+
# @return [String] zipcode
|
101
|
+
def zipcode
|
102
|
+
@zipcode ||= @hash["AddressDetails"]["Country"]["AdministrativeArea"]\
|
103
|
+
["Locality"]["PostalCode"]["PostalCodeNumber"] rescue nil
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Country
|
108
|
+
#
|
109
|
+
# @return [String] country
|
110
|
+
def country
|
111
|
+
@country ||= @hash["AddressDetails"]["Country"]["CountryNameCode"]\
|
112
|
+
rescue nil
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Accuracy
|
117
|
+
#
|
118
|
+
# Convert Googles Accuracy integer into a word describing how accurate
|
119
|
+
# the match is
|
120
|
+
#
|
121
|
+
# @see accuracy_map
|
122
|
+
# @return [String] accuracy
|
123
|
+
def accuracy
|
124
|
+
@accuracy ||= accuracy_map[@hash["AddressDetails"]["Accuracy"].to_i]\
|
125
|
+
rescue nil
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Coordinates
|
130
|
+
#
|
131
|
+
# An array of coordinates in the form of [lat, lng, elevation]
|
132
|
+
#
|
133
|
+
# @return [<Array>] lat, lng, elevation
|
134
|
+
def coordinates
|
135
|
+
@coordinates ||= [lat, lng, elevation]
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Lat
|
140
|
+
#
|
141
|
+
# @return [Float] latitude
|
142
|
+
def lat
|
143
|
+
@lat ||= @hash["Point"]["coordinates"][0].to_f rescue nil
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# Lng
|
148
|
+
#
|
149
|
+
# @return [Float] longitude
|
150
|
+
def lng
|
151
|
+
@lng ||= @hash["Point"]["coordinates"][1].to_f rescue nil
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# Elevation
|
156
|
+
#
|
157
|
+
# @return [Float] elevation
|
158
|
+
def elevation
|
159
|
+
@elevation ||= @hash["Point"]["coordinates"][2].to_f rescue nil
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
##
|
165
|
+
# Map Googles code to a user friendly word
|
166
|
+
#
|
167
|
+
# @return [String]
|
168
|
+
def accuracy_map
|
169
|
+
%w{ unknown country state county city zip zip+4 street address }
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
end
|
data/lib/geocoda.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'patron'
|
2
|
+
require 'json'
|
3
|
+
module Geocoda
|
4
|
+
|
5
|
+
class Error < StandardError; end
|
6
|
+
class ServerError < Error; end
|
7
|
+
class AddressError < Error; end
|
8
|
+
class MissingAddressError < AddressError; end
|
9
|
+
class UnknownAddressError < AddressError; end
|
10
|
+
class UnavailableAddressError < AddressError; end
|
11
|
+
class MapKeyError < Error; end
|
12
|
+
class InvalidMapKeyError < MapKeyError; end
|
13
|
+
class TooManyQueriesError < MapKeyError; end
|
14
|
+
class UnknownError < Error; end
|
15
|
+
class ConnectionError < Error; end
|
16
|
+
|
17
|
+
##
|
18
|
+
# The current version of the application
|
19
|
+
def self.version
|
20
|
+
"0.0.3"
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Search for addresses that match a string
|
25
|
+
#
|
26
|
+
# @see Geocoda::Client#search
|
27
|
+
def self.search(address,key=nil)
|
28
|
+
Client.new(key).search(address)
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Search for the first address that matches a string
|
33
|
+
#
|
34
|
+
# @see Geocoda::Client#first
|
35
|
+
def self.first(address,key=nil)
|
36
|
+
search(address,key).first
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
require File.join(
|
42
|
+
File.expand_path(File.dirname(__FILE__)), 'geocoda', 'client'
|
43
|
+
)
|
44
|
+
require File.join(
|
45
|
+
File.expand_path(File.dirname(__FILE__)), 'geocoda', 'response'
|
46
|
+
)
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: geocoda
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dusty Doris
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-09-19 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: &70110201151060 !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: *70110201151060
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: patron
|
27
|
+
requirement: &70110201150500 !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: *70110201150500
|
36
|
+
description:
|
37
|
+
email: github@dusty.name
|
38
|
+
executables: []
|
39
|
+
extensions: []
|
40
|
+
extra_rdoc_files:
|
41
|
+
- README.txt
|
42
|
+
files:
|
43
|
+
- README.txt
|
44
|
+
- lib/geocoda.rb
|
45
|
+
- lib/geocoda/client.rb
|
46
|
+
- lib/geocoda/response.rb
|
47
|
+
homepage: https://github.com/dusty/geocoda
|
48
|
+
licenses: []
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project: none
|
67
|
+
rubygems_version: 1.8.10
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: Interface to Google's Geocoder API
|
71
|
+
test_files: []
|