GUI-graticule 0.2.7.2

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.
Files changed (74) hide show
  1. data/CHANGELOG.txt +46 -0
  2. data/LICENSE.txt +30 -0
  3. data/Manifest.txt +73 -0
  4. data/README.txt +29 -0
  5. data/Rakefile +86 -0
  6. data/bin/geocode +5 -0
  7. data/init.rb +2 -0
  8. data/lib/graticule.rb +26 -0
  9. data/lib/graticule/cli.rb +64 -0
  10. data/lib/graticule/distance.rb +29 -0
  11. data/lib/graticule/distance/haversine.rb +40 -0
  12. data/lib/graticule/distance/spherical.rb +52 -0
  13. data/lib/graticule/distance/vincenty.rb +76 -0
  14. data/lib/graticule/geocoder.rb +21 -0
  15. data/lib/graticule/geocoder/base.rb +138 -0
  16. data/lib/graticule/geocoder/bogus.rb +15 -0
  17. data/lib/graticule/geocoder/geocoder_ca.rb +54 -0
  18. data/lib/graticule/geocoder/geocoder_us.rb +49 -0
  19. data/lib/graticule/geocoder/google.rb +122 -0
  20. data/lib/graticule/geocoder/host_ip.rb +41 -0
  21. data/lib/graticule/geocoder/local_search_maps.rb +45 -0
  22. data/lib/graticule/geocoder/map_quest.rb +111 -0
  23. data/lib/graticule/geocoder/meta_carta.rb +33 -0
  24. data/lib/graticule/geocoder/multi.rb +80 -0
  25. data/lib/graticule/geocoder/postcode_anywhere.rb +63 -0
  26. data/lib/graticule/geocoder/rest.rb +18 -0
  27. data/lib/graticule/geocoder/yahoo.rb +102 -0
  28. data/lib/graticule/location.rb +488 -0
  29. data/lib/graticule/version.rb +9 -0
  30. data/site/index.html +114 -0
  31. data/site/plugin.html +82 -0
  32. data/site/stylesheets/style.css +73 -0
  33. data/test/config.yml.default +36 -0
  34. data/test/fixtures/responses/geocoder_us/success.xml +18 -0
  35. data/test/fixtures/responses/geocoder_us/unknown.xml +1 -0
  36. data/test/fixtures/responses/google/badkey.xml +1 -0
  37. data/test/fixtures/responses/google/limit.xml +10 -0
  38. data/test/fixtures/responses/google/missing_address.xml +1 -0
  39. data/test/fixtures/responses/google/only_coordinates.xml +1 -0
  40. data/test/fixtures/responses/google/partial.xml +1 -0
  41. data/test/fixtures/responses/google/server_error.xml +10 -0
  42. data/test/fixtures/responses/google/success.xml +1 -0
  43. data/test/fixtures/responses/google/unavailable.xml +1 -0
  44. data/test/fixtures/responses/google/unknown_address.xml +1 -0
  45. data/test/fixtures/responses/host_ip/private.txt +4 -0
  46. data/test/fixtures/responses/host_ip/success.txt +4 -0
  47. data/test/fixtures/responses/host_ip/unknown.txt +4 -0
  48. data/test/fixtures/responses/local_search_maps/empty.txt +1 -0
  49. data/test/fixtures/responses/local_search_maps/not_found.txt +1 -0
  50. data/test/fixtures/responses/local_search_maps/success.txt +1 -0
  51. data/test/fixtures/responses/meta_carta/bad_address.xml +17 -0
  52. data/test/fixtures/responses/meta_carta/multiple.xml +33 -0
  53. data/test/fixtures/responses/meta_carta/success.xml +31 -0
  54. data/test/fixtures/responses/postcode_anywhere/badkey.xml +9 -0
  55. data/test/fixtures/responses/postcode_anywhere/canada.xml +16 -0
  56. data/test/fixtures/responses/postcode_anywhere/empty.xml +16 -0
  57. data/test/fixtures/responses/postcode_anywhere/success.xml +16 -0
  58. data/test/fixtures/responses/postcode_anywhere/uk.xml +18 -0
  59. data/test/fixtures/responses/yahoo/success.xml +3 -0
  60. data/test/fixtures/responses/yahoo/unknown_address.xml +6 -0
  61. data/test/mocks/uri.rb +52 -0
  62. data/test/test_helper.rb +32 -0
  63. data/test/unit/graticule/distance_test.rb +58 -0
  64. data/test/unit/graticule/geocoder/geocoder_us_test.rb +43 -0
  65. data/test/unit/graticule/geocoder/google_test.rb +126 -0
  66. data/test/unit/graticule/geocoder/host_ip_test.rb +40 -0
  67. data/test/unit/graticule/geocoder/local_search_maps_test.rb +30 -0
  68. data/test/unit/graticule/geocoder/meta_carta_test.rb +44 -0
  69. data/test/unit/graticule/geocoder/multi_test.rb +43 -0
  70. data/test/unit/graticule/geocoder/postcode_anywhere_test.rb +50 -0
  71. data/test/unit/graticule/geocoder/yahoo_test.rb +58 -0
  72. data/test/unit/graticule/geocoder_test.rb +27 -0
  73. data/test/unit/graticule/location_test.rb +66 -0
  74. metadata +158 -0
@@ -0,0 +1,52 @@
1
+ module Graticule
2
+ module Distance
3
+
4
+ #
5
+ # The Spherical Law of Cosines is the simplist though least accurate distance
6
+ # formula (earth isn't a perfect sphere).
7
+ #
8
+ class Spherical < DistanceFormula
9
+
10
+ # Calculate the distance between two Locations using the Spherical formula
11
+ #
12
+ # Graticule::Distance::Spherical.distance(
13
+ # Graticule::Location.new(:latitude => 42.7654, :longitude => -86.1085),
14
+ # Graticule::Location.new(:latitude => 41.849838, :longitude => -87.648193)
15
+ # )
16
+ # #=> 101.061720831853
17
+ #
18
+ def self.distance(from, to, units = :miles)
19
+ from_longitude = deg2rad(from.longitude)
20
+ from_latitude = deg2rad(from.latitude)
21
+ to_longitude = deg2rad(to.longitude)
22
+ to_latitude = deg2rad(to.latitude)
23
+
24
+ Math.acos(
25
+ Math.sin(from_latitude) *
26
+ Math.sin(to_latitude) +
27
+
28
+ Math.cos(from_latitude) *
29
+ Math.cos(to_latitude) *
30
+ Math.cos(to_longitude - from_longitude)
31
+ ) * EARTH_RADIUS[units.to_sym]
32
+ end
33
+
34
+ def self.to_sql(options)
35
+ options = {
36
+ :units => :miles,
37
+ :latitude_column => 'latitude',
38
+ :longitude_column => 'longitude'
39
+ }.merge(options)
40
+ %{(ACOS(
41
+ SIN(RADIANS(#{options[:latitude]})) *
42
+ SIN(RADIANS(#{options[:latitude_column]})) +
43
+ COS(RADIANS(#{options[:latitude]})) *
44
+ COS(RADIANS(#{options[:latitude_column]})) *
45
+ COS(RADIANS(#{options[:longitude_column]}) - RADIANS(#{options[:longitude]}))
46
+ ) * #{Graticule::Distance::EARTH_RADIUS[options[:units].to_sym]})
47
+ }.gsub("\n", '').squeeze(" ")
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,76 @@
1
+ module Graticule
2
+ module Distance
3
+
4
+ #
5
+ # The Vincenty Formula uses an ellipsoidal model of the earth, which is very accurate.
6
+ #
7
+ # Thanks to Chris Veness (http://www.movable-type.co.uk/scripts/LatLongVincenty.html)
8
+ # for distance formulas.
9
+ #
10
+ class Vincenty < DistanceFormula
11
+
12
+ # Calculate the distance between two Locations using the Vincenty formula
13
+ #
14
+ # Graticule::Distance::Vincenty.distance(
15
+ # Graticule::Location.new(:latitude => 42.7654, :longitude => -86.1085),
16
+ # Graticule::Location.new(:latitude => 41.849838, :longitude => -87.648193)
17
+ # )
18
+ # #=> 101.070118000159
19
+ #
20
+ def self.distance(from, to, units = :miles)
21
+ from_longitude = deg2rad(from.longitude)
22
+ from_latitude = deg2rad(from.latitude)
23
+ to_longitude = deg2rad(to.longitude)
24
+ to_latitude = deg2rad(to.latitude)
25
+
26
+ earth_major_axis_radius = EARTH_MAJOR_AXIS_RADIUS[units.to_sym]
27
+ earth_minor_axis_radius = EARTH_MINOR_AXIS_RADIUS[units.to_sym]
28
+
29
+ f = (earth_major_axis_radius - earth_minor_axis_radius) / earth_major_axis_radius
30
+
31
+ l = to_longitude - from_longitude
32
+ u1 = atan((1-f) * tan(from_latitude))
33
+ u2 = atan((1-f) * tan(to_latitude))
34
+ sin_u1 = sin(u1)
35
+ cos_u1 = cos(u1)
36
+ sin_u2 = sin(u2)
37
+ cos_u2 = cos(u2)
38
+
39
+ lambda = l
40
+ lambda_p = 2 * PI
41
+ iteration_limit = 20
42
+ while (lambda-lambda_p).abs > 1e-12 && (iteration_limit -= 1) > 0
43
+ sin_lambda = sin(lambda)
44
+ cos_lambda = cos(lambda)
45
+ sin_sigma = sqrt((cos_u2*sin_lambda) * (cos_u2*sin_lambda) +
46
+ (cos_u1*sin_u2-sin_u1*cos_u2*cos_lambda) * (cos_u1*sin_u2-sin_u1*cos_u2*cos_lambda))
47
+ return 0 if sin_sigma == 0 # co-incident points
48
+ cos_sigma = sin_u1*sin_u2 + cos_u1*cos_u2*cos_lambda
49
+ sigma = atan2(sin_sigma, cos_sigma)
50
+ sin_alpha = cos_u1 * cos_u2 * sin_lambda / sin_sigma
51
+ cosSqAlpha = 1 - sin_alpha*sin_alpha
52
+ cos2SigmaM = cos_sigma - 2*sin_u1*sin_u2/cosSqAlpha
53
+
54
+ cos2SigmaM = 0 if cos2SigmaM.nan? # equatorial line: cosSqAlpha=0 (§6)
55
+
56
+ c = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha))
57
+ lambda_p = lambda
58
+ lambda = l + (1-c) * f * sin_alpha *
59
+ (sigma + c*sin_sigma*(cos2SigmaM+c*cos_sigma*(-1+2*cos2SigmaM*cos2SigmaM)))
60
+ end
61
+ # formula failed to converge (happens on antipodal points)
62
+ # We'll call Haversine formula instead.
63
+ return Haversine.distance(from, to, units) if iteration_limit == 0
64
+
65
+ uSq = cosSqAlpha * (earth_major_axis_radius**2 - earth_minor_axis_radius**2) / (earth_minor_axis_radius**2)
66
+ a = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)))
67
+ b = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)))
68
+ delta_sigma = b*sin_sigma*(cos2SigmaM+b/4*(cos_sigma*(-1+2*cos2SigmaM*cos2SigmaM)-
69
+ b/6*cos2SigmaM*(-3+4*sin_sigma*sin_sigma)*(-3+4*cos2SigmaM*cos2SigmaM)))
70
+
71
+ earth_minor_axis_radius * a * (sigma-delta_sigma)
72
+ end
73
+
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,21 @@
1
+
2
+ module Graticule
3
+
4
+ # Get a geocoder for the given service
5
+ #
6
+ # geocoder = Graticule.service(:google).new "api_key"
7
+ #
8
+ # See the documentation for your specific geocoder for more information
9
+ #
10
+ def self.service(name)
11
+ Geocoder.const_get name.to_s.camelize
12
+ end
13
+
14
+ # Base error class
15
+ class Error < RuntimeError; end
16
+ class CredentialsError < Error; end
17
+
18
+ # Raised when you try to locate an invalid address.
19
+ class AddressError < Error; end
20
+
21
+ end
@@ -0,0 +1,138 @@
1
+ require 'open-uri'
2
+ require "cgi"
3
+
4
+ module Graticule #:nodoc:
5
+ module Geocoder
6
+
7
+ # Abstract class for implementing geocoders.
8
+ #
9
+ # === Example
10
+ #
11
+ # The following methods must be implemented in sublcasses:
12
+ #
13
+ # * +initialize+:: Sets @url to the service enpoint.
14
+ # * +check_error+:: Checks for errors in the server response.
15
+ # * +parse_response+:: Extracts information from the server response.
16
+ #
17
+ # Optionally, you can also override
18
+ #
19
+ # * +prepare_response+:: Convert the string response into a different format
20
+ # that gets passed on to +check_error+ and +parse_response+.
21
+ #
22
+ # If you have extra URL paramaters (application id, output type) or need to
23
+ # perform URL customization, override +make_url+.
24
+ #
25
+ # class FakeGeocoder < Base
26
+ #
27
+ # def initialize(appid)
28
+ # @appid = appid
29
+ # @url = URI.parse 'http://example.com/test'
30
+ # end
31
+ #
32
+ # def locate(query)
33
+ # get :q => query
34
+ # end
35
+ #
36
+ # private
37
+ #
38
+ # def check_error(xml)
39
+ # raise Error, xml.elements['error'].text if xml.elements['error']
40
+ # end
41
+ #
42
+ # def make_url(params)
43
+ # params[:appid] = @appid
44
+ # super params
45
+ # end
46
+ #
47
+ # def parse_first(response)
48
+ # # return Location
49
+ # end
50
+ #
51
+ # end
52
+ #
53
+ class Base
54
+ include Comparable
55
+
56
+ USER_AGENT = "Mozilla/5.0 (compatible; Graticule/#{Graticule::Version::STRING}; http://graticule.rubyforge.org)"
57
+
58
+ attr_accessor :preference
59
+
60
+ def initialize
61
+ raise NotImplementedError
62
+ end
63
+
64
+ def <=>(other)
65
+ other.preference <=> preference
66
+ end
67
+
68
+ private
69
+
70
+ def location_from_params(params)
71
+ case params
72
+ when Location then params
73
+ when Hash then Location.new params
74
+ else
75
+ raise ArgumentError, "Expected a Graticule::Location or a hash with :street, :locality, :region, :postal_code, and :country attributes"
76
+ end
77
+ end
78
+
79
+ # Check for errors in +response+ and raise appropriate error, if any.
80
+ # Must return if no error could be found.
81
+ def check_error(response)
82
+ raise NotImplementedError
83
+ end
84
+
85
+ # Performs a GET request with +params+. Calls +check_error+ and returns
86
+ # the result of +parse_response+.
87
+ def get(*args)
88
+ params = args.last.is_a?(::Hash) ? args.pop : args
89
+ response = prepare_response(make_url(params).open('User-Agent' => USER_AGENT).read)
90
+ check_error(response)
91
+
92
+ result = parse_response(args.first, response)
93
+
94
+ # Make sure the parse_response method was overriden by a subclass to
95
+ # return a Location object. If it was, set its geocoder attribute to
96
+ # the current geocoder, so we know where the result came from.
97
+ if(result.kind_of? Array)
98
+ result.each do |location|
99
+ if(location.instance_of? Location)
100
+ location.geocoder = self
101
+ end
102
+ end
103
+ elsif(result.instance_of? Location)
104
+ result.geocoder = self
105
+ end
106
+
107
+ result
108
+ rescue OpenURI::HTTPError => e
109
+ check_error(prepare_response(e.io.read))
110
+ raise
111
+ end
112
+
113
+ # Creates a URI from the Hash +params+. Override this then call super if
114
+ # you need to add extra params like an application id or output type.
115
+ def make_url(params)
116
+ escaped_params = params.sort_by { |k,v| k.to_s }.map do |k,v|
117
+ "#{CGI.escape k.to_s}=#{CGI.escape v.to_s}"
118
+ end
119
+
120
+ url = @url.dup
121
+ url.query = escaped_params.join '&'
122
+ return url
123
+ end
124
+
125
+ # Override to convert the response to something besides a String, which
126
+ # will get passed to +check_error+ and +parse_response+.
127
+ def prepare_response(response)
128
+ response
129
+ end
130
+
131
+ # Must parse :first or :all results from +response+ into a Location.
132
+ def parse_response(parse_type, response)
133
+ raise NotImplementedError
134
+ end
135
+
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,15 @@
1
+ module Graticule #:nodoc:
2
+ module Geocoder #:nodoc:
3
+
4
+ # Bogus geocoder that can be used for test purposes
5
+ class Bogus
6
+
7
+ # returns a new location with the address set to the original query string
8
+ def locate(address)
9
+ Location.new :street => address
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,54 @@
1
+ module Graticule #:nodoc:
2
+ module Geocoder #:nodoc:
3
+
4
+ # TODO: Reverse Geocoding
5
+ class GeocoderCa < Rest
6
+
7
+ def initialize(auth = nil)
8
+ @url = URI.parse 'http://geocoder.ca/'
9
+ @auth = auth
10
+ end
11
+
12
+ def locate(address)
13
+ get :locate => address.is_a?(String) ? address : location_from_params(address).to_s(:country => false)
14
+ end
15
+
16
+ private
17
+
18
+ def parse_response(parse_type, xml) #:nodoc:
19
+ returning Location.new do |location|
20
+ location.latitude = xml.elements['geodata/latt'].text.to_f
21
+ location.longitude = xml.elements['geodata/longt'].text.to_f
22
+ location.street = xml.elements['geodata/standard/staddress'].text
23
+ location.locality = xml.elements['geodata/standard/city'].text
24
+ location.region = xml.elements['geodata/standard/prov'].text
25
+ end
26
+ end
27
+
28
+ def check_error(xml) #:nodoc:
29
+ error = xml.elements['geodata/error']
30
+ if error
31
+ code = error.elements['code'].text.to_i
32
+ message = error.elements['description'].text
33
+ if (1..3).include?(code)
34
+ raise CredentialsError, message
35
+ elsif (4..8).include?(code)
36
+ raise AddressError, message
37
+ else
38
+ raise Error, message
39
+ end
40
+ end
41
+ end
42
+
43
+ def make_url(params) #:nodoc:
44
+ params[:auth] = @auth if @auth
45
+ params[:standard] = 1
46
+ params[:showpostal] = 1
47
+ params[:geoit] = 'XML'
48
+ super params
49
+ end
50
+
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,49 @@
1
+ module Graticule #:nodoc:
2
+ module Geocoder #:nodoc:
3
+
4
+ # A library for lookup up coordinates with geocoder.us' API.
5
+ #
6
+ # http://geocoder.us/help/
7
+ class GeocoderUs < Rest
8
+
9
+ # Creates a new GeocoderUs object optionally using +username+ and
10
+ # +password+.
11
+ #
12
+ # You can sign up for a geocoder.us account here:
13
+ #
14
+ # http://geocoder.us/user/signup
15
+ def initialize(user = nil, password = nil)
16
+ if user and password then
17
+ @url = URI.parse 'http://geocoder.us/member/service/rest/geocode'
18
+ @url.user = user
19
+ @url.password = password
20
+ else
21
+ @url = URI.parse 'http://rpc.geocoder.us/service/rest/geocode'
22
+ end
23
+ end
24
+
25
+ # Locates +address+ and returns the address' latitude and longitude or
26
+ # raises an AddressError.
27
+ def locate(address)
28
+ get :address => address.is_a?(String) ? address : location_from_params(address).to_s(:country => false)
29
+ end
30
+
31
+ private
32
+
33
+ def parse_response(parse_type, xml) #:nodoc:
34
+ location = Location.new
35
+ location.street = xml.elements['rdf:RDF/geo:Point/dc:description'].text
36
+
37
+ location.latitude = xml.elements['rdf:RDF/geo:Point/geo:lat'].text.to_f
38
+ location.longitude = xml.elements['rdf:RDF/geo:Point/geo:long'].text.to_f
39
+
40
+ return location
41
+ end
42
+
43
+ def check_error(xml) #:nodoc:
44
+ raise AddressError, xml.text if xml.text =~ /couldn't find this address! sorry/
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,122 @@
1
+
2
+ module Graticule #:nodoc:
3
+ module Geocoder #:nodoc:
4
+
5
+ # First you need a Google Maps API key. You can register for one here:
6
+ # http://www.google.com/apis/maps/signup.html
7
+ #
8
+ # gg = Graticule.service(:google).new(MAPS_API_KEY)
9
+ # location = gg.locate '1600 Amphitheater Pkwy, Mountain View, CA'
10
+ # p location.coordinates
11
+ # #=> [37.423111, -122.081783
12
+ #
13
+ class Google < Rest
14
+ # http://www.google.com/apis/maps/documentation/#Geocoding_HTTP_Request
15
+
16
+ # http://www.google.com/apis/maps/documentation/reference.html#GGeoAddressAccuracy
17
+ PRECISION = {
18
+ 0 => Precision.unknown, # Unknown location. (Since 2.59)
19
+ 1 => Precision.country, # Country level accuracy. (Since 2.59)
20
+ 2 => Precision.state, # Region (state, province, prefecture, etc.) level accuracy. (Since 2.59)
21
+ 3 => Precision.state, # Sub-region (county, municipality, etc.) level accuracy. (Since 2.59)
22
+ 4 => Precision.city, # Town (city, village) level accuracy. (Since 2.59)
23
+ 5 => Precision.zip, # Post code (zip code) level accuracy. (Since 2.59)
24
+ 6 => Precision.street, # Street level accuracy. (Since 2.59)
25
+ 7 => Precision.street, # Intersection level accuracy. (Since 2.59)
26
+ 8 => Precision.address, # Address level accuracy. (Since 2.59)
27
+ 9 => Precision.premise # Premise (building name, property name, shopping center, etc.) level accuracy. (Since 2.105)
28
+ }
29
+
30
+ # Creates a new GoogleGeocode that will use Google Maps API +key+.
31
+ def initialize(key)
32
+ @key = key
33
+ @url = URI.parse 'http://maps.google.com/maps/geo'
34
+ end
35
+
36
+ # Locates +address+ returning a Location
37
+ def locate(*args)
38
+ case args.first
39
+ when :first then get :first, :q => extract_location(args[1])
40
+ when :all then get :all, :q => extract_location(args[1])
41
+ else get :first, :q => extract_location(args.first)
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def extract_location(address)
48
+ address.is_a?(String) ? address : location_from_params(address).to_s
49
+ end
50
+
51
+ # Extracts a Location from +xml+.
52
+ def parse_response(parse_type, xml) #:nodoc:
53
+ # puts xml.elements['//Placemark[1]'].to_s
54
+ if parse_type == :all
55
+ locations = []
56
+ xml.elements.each("//Placemark") do |element|
57
+ locations << parse_location_xml(element)
58
+ end
59
+ return locations
60
+ else
61
+ return parse_location_xml(xml.elements['//Placemark[1]'])
62
+ end
63
+ end
64
+
65
+ def parse_location_xml(xml)
66
+ longitude, latitude, = xml.elements['.//Point/coordinates'].text.split(',').map { |v| v.to_f }
67
+ returning Location.new(:latitude => latitude, :longitude => longitude) do |l|
68
+ address = REXML::XPath.first(xml, './/xal:AddressDetails',
69
+ 'xal' => "urn:oasis:names:tc:ciq:xsdschema:xAL:2.0")
70
+ if address
71
+ l.premise = value(address.elements['.//PremiseName/text()'])
72
+ l.street = value(address.elements['.//ThoroughfareName/text()'])
73
+ l.locality = value(address.elements['.//LocalityName/text()'])
74
+ l.region = value(address.elements['.//AdministrativeAreaName/text()'])
75
+ l.postal_code = value(address.elements['.//PostalCodeNumber/text()'])
76
+ l.country = value(address.elements['.//CountryNameCode/text()'])
77
+ l.precision = PRECISION[address.attribute('Accuracy').value.to_i] || Precision.unknown
78
+ end
79
+ end
80
+ end
81
+
82
+ # Extracts and raises an error from +xml+, if any.
83
+ def check_error(xml) #:nodoc:
84
+ status = xml.elements['/kml/Response/Status/code'].text.to_i
85
+ case status
86
+ when 200 then # ignore, ok
87
+ when 500 then
88
+ raise Error, 'server error'
89
+ when 601 then
90
+ raise AddressError, 'missing address'
91
+ when 602 then
92
+ raise AddressError, 'unknown address'
93
+ when 603 then
94
+ raise AddressError, 'unavailable address'
95
+ when 610 then
96
+ raise CredentialsError, 'invalid key'
97
+ when 620 then
98
+ raise CredentialsError, 'too many queries'
99
+ else
100
+ raise Error, "unknown error #{status}"
101
+ end
102
+ end
103
+
104
+ # Creates a URL from the Hash +params+. Automatically adds the key and
105
+ # sets the output type to 'xml'.
106
+ def make_url(params) #:nodoc:
107
+ params[:key] = @key
108
+ params[:output] = 'xml'
109
+
110
+ super params
111
+ end
112
+
113
+ def value(element)
114
+ element.value if element
115
+ end
116
+
117
+ def text(element)
118
+ element.text if element
119
+ end
120
+ end
121
+ end
122
+ end