graticule 0.1.3 → 0.2.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.
Files changed (50) hide show
  1. data/CHANGELOG.txt +11 -0
  2. data/Manifest.txt +26 -11
  3. data/README.txt +1 -1
  4. data/bin/geocode +1 -1
  5. data/lib/graticule.rb +10 -8
  6. data/lib/graticule/cli.rb +1 -0
  7. data/lib/graticule/geocoder.rb +1 -12
  8. data/lib/graticule/geocoder/bogus.rb +15 -0
  9. data/lib/graticule/geocoder/geocoder_ca.rb +52 -0
  10. data/lib/graticule/geocoder/geocoder_us.rb +47 -0
  11. data/lib/graticule/geocoder/google.rb +106 -0
  12. data/lib/graticule/geocoder/host_ip.rb +50 -0
  13. data/lib/graticule/geocoder/local_search_maps.rb +45 -0
  14. data/lib/graticule/geocoder/meta_carta.rb +38 -0
  15. data/lib/graticule/geocoder/postcode_anywhere.rb +63 -0
  16. data/lib/graticule/geocoder/rest.rb +110 -0
  17. data/lib/graticule/geocoder/yahoo.rb +96 -0
  18. data/lib/graticule/location.rb +19 -7
  19. data/lib/graticule/version.rb +2 -2
  20. data/test/fixtures/responses/host_ip/private.txt +4 -0
  21. data/test/fixtures/responses/host_ip/success.txt +4 -0
  22. data/test/fixtures/responses/host_ip/unknown.txt +4 -0
  23. data/test/fixtures/responses/local_search_maps/success.txt +1 -0
  24. data/test/fixtures/responses/postcode_anywhere/badkey.xml +9 -0
  25. data/test/fixtures/responses/postcode_anywhere/canada.xml +16 -0
  26. data/test/fixtures/responses/postcode_anywhere/empty.xml +16 -0
  27. data/test/fixtures/responses/postcode_anywhere/success.xml +16 -0
  28. data/test/fixtures/responses/postcode_anywhere/uk.xml +18 -0
  29. data/test/test_helper.rb +4 -2
  30. data/test/unit/graticule/geocoder/geocoder_us_test.rb +43 -0
  31. data/test/unit/graticule/geocoder/google_test.rb +66 -0
  32. data/test/unit/graticule/geocoder/host_ip_test.rb +39 -0
  33. data/test/unit/graticule/geocoder/local_search_maps_test.rb +30 -0
  34. data/test/unit/graticule/geocoder/meta_carta_test.rb +44 -0
  35. data/test/unit/graticule/geocoder/postcode_anywhere_test.rb +50 -0
  36. data/test/unit/graticule/geocoder/yahoo_test.rb +48 -0
  37. data/test/unit/graticule/geocoder_test.rb +5 -9
  38. data/test/unit/graticule/location_test.rb +22 -7
  39. metadata +37 -18
  40. data/lib/graticule/geocoders/bogus.rb +0 -11
  41. data/lib/graticule/geocoders/geocoder_us.rb +0 -45
  42. data/lib/graticule/geocoders/google.rb +0 -99
  43. data/lib/graticule/geocoders/meta_carta.rb +0 -102
  44. data/lib/graticule/geocoders/rest.rb +0 -98
  45. data/lib/graticule/geocoders/yahoo.rb +0 -101
  46. data/test/unit/graticule/geocoders/geocoder_us_test.rb +0 -42
  47. data/test/unit/graticule/geocoders/geocoders.rb +0 -56
  48. data/test/unit/graticule/geocoders/google_test.rb +0 -22
  49. data/test/unit/graticule/geocoders/meta_carta_test.rb +0 -70
  50. data/test/unit/graticule/geocoders/yahoo_test.rb +0 -49
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.11
2
+ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: graticule
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.3
7
- date: 2007-02-14 00:00:00 -05:00
6
+ version: 0.2.0
7
+ date: 2007-03-17 00:00:00 -04:00
8
8
  summary: API for using all the popular geocoding services.
9
9
  require_paths:
10
10
  - lib
@@ -25,6 +25,7 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
25
25
  platform: ruby
26
26
  signing_key:
27
27
  cert_chain:
28
+ post_install_message:
28
29
  authors:
29
30
  - Brandon Keepers
30
31
  files:
@@ -42,12 +43,16 @@ files:
42
43
  - lib/graticule/distance/spherical.rb
43
44
  - lib/graticule/distance/vincenty.rb
44
45
  - lib/graticule/geocoder.rb
45
- - lib/graticule/geocoders/bogus.rb
46
- - lib/graticule/geocoders/geocoder_us.rb
47
- - lib/graticule/geocoders/google.rb
48
- - lib/graticule/geocoders/meta_carta.rb
49
- - lib/graticule/geocoders/rest.rb
50
- - lib/graticule/geocoders/yahoo.rb
46
+ - lib/graticule/geocoder/bogus.rb
47
+ - lib/graticule/geocoder/geocoder_ca.rb
48
+ - lib/graticule/geocoder/geocoder_us.rb
49
+ - lib/graticule/geocoder/google.rb
50
+ - lib/graticule/geocoder/host_ip.rb
51
+ - lib/graticule/geocoder/local_search_maps.rb
52
+ - lib/graticule/geocoder/meta_carta.rb
53
+ - lib/graticule/geocoder/postcode_anywhere.rb
54
+ - lib/graticule/geocoder/rest.rb
55
+ - lib/graticule/geocoder/yahoo.rb
51
56
  - lib/graticule/location.rb
52
57
  - lib/graticule/version.rb
53
58
  - test/fixtures/responses/geocoder_us/success.xml
@@ -59,29 +64,43 @@ files:
59
64
  - test/fixtures/responses/google/success.xml
60
65
  - test/fixtures/responses/google/unavailable.xml
61
66
  - test/fixtures/responses/google/unknown_address.xml
67
+ - test/fixtures/responses/host_ip/private.txt
68
+ - test/fixtures/responses/host_ip/success.txt
69
+ - test/fixtures/responses/host_ip/unknown.txt
70
+ - test/fixtures/responses/local_search_maps/success.txt
62
71
  - test/fixtures/responses/meta_carta/bad_address.xml
63
72
  - test/fixtures/responses/meta_carta/multiple.xml
64
73
  - test/fixtures/responses/meta_carta/success.xml
74
+ - test/fixtures/responses/postcode_anywhere/badkey.xml
75
+ - test/fixtures/responses/postcode_anywhere/canada.xml
76
+ - test/fixtures/responses/postcode_anywhere/empty.xml
77
+ - test/fixtures/responses/postcode_anywhere/success.xml
78
+ - test/fixtures/responses/postcode_anywhere/uk.xml
65
79
  - test/fixtures/responses/yahoo/success.xml
66
80
  - test/fixtures/responses/yahoo/unknown_address.xml
67
81
  - test/mocks/uri.rb
68
82
  - test/test_helper.rb
69
83
  - test/unit/graticule/distance_test.rb
84
+ - test/unit/graticule/geocoder/geocoder_us_test.rb
85
+ - test/unit/graticule/geocoder/google_test.rb
86
+ - test/unit/graticule/geocoder/host_ip_test.rb
87
+ - test/unit/graticule/geocoder/local_search_maps_test.rb
88
+ - test/unit/graticule/geocoder/meta_carta_test.rb
89
+ - test/unit/graticule/geocoder/postcode_anywhere_test.rb
90
+ - test/unit/graticule/geocoder/yahoo_test.rb
70
91
  - test/unit/graticule/geocoder_test.rb
71
- - test/unit/graticule/geocoders/geocoder_us_test.rb
72
- - test/unit/graticule/geocoders/geocoders.rb
73
- - test/unit/graticule/geocoders/google_test.rb
74
- - test/unit/graticule/geocoders/meta_carta_test.rb
75
- - test/unit/graticule/geocoders/yahoo_test.rb
76
92
  - test/unit/graticule/location_test.rb
77
93
  test_files:
78
94
  - test/unit/graticule/distance_test.rb
79
95
  - test/unit/graticule/geocoder_test.rb
80
96
  - test/unit/graticule/location_test.rb
81
- - test/unit/graticule/geocoders/geocoder_us_test.rb
82
- - test/unit/graticule/geocoders/google_test.rb
83
- - test/unit/graticule/geocoders/meta_carta_test.rb
84
- - test/unit/graticule/geocoders/yahoo_test.rb
97
+ - test/unit/graticule/geocoder/geocoder_us_test.rb
98
+ - test/unit/graticule/geocoder/google_test.rb
99
+ - test/unit/graticule/geocoder/host_ip_test.rb
100
+ - test/unit/graticule/geocoder/local_search_maps_test.rb
101
+ - test/unit/graticule/geocoder/meta_carta_test.rb
102
+ - test/unit/graticule/geocoder/postcode_anywhere_test.rb
103
+ - test/unit/graticule/geocoder/yahoo_test.rb
85
104
  rdoc_options: []
86
105
 
87
106
  extra_rdoc_files: []
@@ -1,11 +0,0 @@
1
- module Graticule #:nodoc:
2
-
3
- # Bogus geocoder that can be used for test purposes
4
- class BogusGeocoder < Geocoder
5
-
6
- def locate(address)
7
- Location.new :street => address
8
- end
9
-
10
- end
11
- end
@@ -1,45 +0,0 @@
1
- module Graticule #:nodoc:
2
-
3
- # A library for lookup up coordinates with geocoder.us' API.
4
- #
5
- # http://geocoder.us/help/
6
- class GeocoderUsGeocoder < RestGeocoder
7
-
8
- # Creates a new GeocoderUs object optionally using +username+ and
9
- # +password+.
10
- #
11
- # You can sign up for a geocoder.us account here:
12
- #
13
- # http://geocoder.us/user/signup
14
- def initialize(user = nil, password = nil)
15
- if user and password then
16
- @url = URI.parse 'http://geocoder.us/member/service/rest/geocode'
17
- @url.user = user
18
- @url.password = password
19
- else
20
- @url = URI.parse 'http://rpc.geocoder.us/service/rest/geocode'
21
- end
22
- end
23
-
24
- # Locates +address+ and returns the address' latitude and longitude or
25
- # raises an AddressError.
26
- def locate(address)
27
- get :address => address
28
- end
29
-
30
- def parse_response(xml) #:nodoc:
31
- location = Location.new
32
- location.street = xml.elements['rdf:RDF/geo:Point/dc:description'].text
33
-
34
- location.latitude = xml.elements['rdf:RDF/geo:Point/geo:lat'].text.to_f
35
- location.longitude = xml.elements['rdf:RDF/geo:Point/geo:long'].text.to_f
36
-
37
- return location
38
- end
39
-
40
- def check_error(xml) #:nodoc:
41
- raise AddressError, xml.text if xml.text == 'couldn\'t find this address! sorry'
42
- end
43
-
44
- end
45
- end
@@ -1,99 +0,0 @@
1
-
2
- module Graticule
3
-
4
- # First you need a Google Maps API key. You can register for one here:
5
- # http://www.google.com/apis/maps/signup.html
6
- #
7
- # Then you create a GoogleGeocode object and start locating addresses:
8
- #
9
- # require 'rubygems'
10
- # require 'graticule'
11
- #
12
- # gg = Graticule.service(:google).new(:key => MAPS_API_KEY)
13
- # location = gg.locate '1600 Amphitheater Pkwy, Mountain View, CA'
14
- # p location.coordinates
15
- #
16
- class GoogleGeocoder < RestGeocoder
17
- # http://www.google.com/apis/maps/documentation/#Geocoding_HTTP_Request
18
-
19
- # http://www.google.com/apis/maps/documentation/reference.html#GGeoAddressAccuracy
20
- PRECISION = {
21
- 0 => :unknown, # Unknown location. (Since 2.59)
22
- 1 => :country, # Country level accuracy. (Since 2.59)
23
- 2 => :state, # Region (state, province, prefecture, etc.) level accuracy. (Since 2.59)
24
- 3 => :state, # Sub-region (county, municipality, etc.) level accuracy. (Since 2.59)
25
- 4 => :city, # Town (city, village) level accuracy. (Since 2.59)
26
- 5 => :zip, # Post code (zip code) level accuracy. (Since 2.59)
27
- 6 => :street, # Street level accuracy. (Since 2.59)
28
- 7 => :street, # Intersection level accuracy. (Since 2.59)
29
- 8 => :address # Address level accuracy. (Since 2.59)
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
- def initialize(key)
37
- @key = key
38
- @url = URI.parse 'http://maps.google.com/maps/geo'
39
- end
40
-
41
- # Locates +address+ returning a Location
42
- def locate(address)
43
- get :q => address
44
- end
45
-
46
- # Extracts a Location from +xml+.
47
- def parse_response(xml) #:nodoc:
48
- address = REXML::XPath.first(xml, '//xal:AddressDetails', 'xal' => "urn:oasis:names:tc:ciq:xsdschema:xAL:2.0")
49
-
50
- longitude, latitude, = xml.elements['/kml/Response/Placemark/Point/coordinates'].text.split(',').map { |v| v.to_f }
51
-
52
- Location.new \
53
- :street => address.elements['Country/AdministrativeArea/SubAdministrativeArea/Locality/Thoroughfare/ThoroughfareName/text()'].value,
54
- :city => address.elements['Country/AdministrativeArea/SubAdministrativeArea/Locality/LocalityName/text()'].value,
55
- :state => address.elements['Country/AdministrativeArea/AdministrativeAreaName/text()'].value,
56
- :zip => address.elements['Country/AdministrativeArea/SubAdministrativeArea/Locality/PostalCode/PostalCodeNumber/text()'].value,
57
- :country => address.elements['Country/CountryNameCode/text()'].value,
58
- :latitude => latitude,
59
- :longitude => longitude,
60
- :precision => PRECISION[address.attribute('Accuracy').value.to_i] || :unknown
61
- end
62
-
63
- # Extracts and raises an error from +xml+, if any.
64
- def check_error(xml) #:nodoc:
65
- status ||= xml.elements['/kml/Response/Status/code'].text.to_i
66
- case status
67
- when 200 then # ignore, ok
68
- when 500 then
69
- raise Error, 'server error'
70
- when 601 then
71
- raise AddressError, 'missing address'
72
- when 602 then
73
- raise AddressError, 'unknown address'
74
- when 603 then
75
- raise AddressError, 'unavailable address'
76
- when 610 then
77
- raise CredentialsError, 'invalid key'
78
- when 620 then
79
- raise CredentialsError, 'too many queries'
80
- else
81
- raise Error, "unknown error #{status}"
82
- end
83
- end
84
-
85
- # Creates a URL from the Hash +params+. Automatically adds the key and
86
- # sets the output type to 'xml'.
87
- def make_url(params) #:nodoc:
88
- params[:key] = @key
89
- params[:output] = 'xml'
90
-
91
- super params
92
- end
93
-
94
- private
95
- def text(element)
96
- element.text if element
97
- end
98
- end
99
- end
@@ -1,102 +0,0 @@
1
-
2
- module Graticule
3
-
4
- # Library for looking up coordinates with MetaCarta's GeoParser API.
5
- #
6
- # http://labs.metacarta.com/GeoParser/documentation.html
7
- class MetaCartaGeocoder < RestGeocoder
8
- Location = Struct.new :name, :type, :population, :hierarchy,
9
- :latitude, :longitude, :confidence, :viewbox
10
-
11
- def initialize # :nodoc:
12
- @url = URI.parse 'http://labs.metacarta.com/GeoParser/'
13
- end
14
-
15
- # Locates +place+ and returns a Location object.
16
- def locate(place)
17
- locations, = get :q => place
18
- return locations.first
19
- end
20
-
21
- # Retrieve all locations matching +place+.
22
- #
23
- # Returns an Array of Location objects and a pair of coordinates that will
24
- # surround them.
25
- def locations(place)
26
- get :loc => place
27
- end
28
-
29
- def check_error(xml) # :nodoc:
30
- raise AddressError, 'bad location' unless xml.elements['Locations/Location']
31
- end
32
-
33
- def make_url(params) # :nodoc:
34
- params[:output] = 'locations'
35
-
36
- super params
37
- end
38
-
39
- def parse_response(xml) # :nodoc:
40
- locations = []
41
-
42
- xml.elements['/Locations'].each do |l|
43
- next if REXML::Text === l or l.name == 'ViewBox'
44
- location = Location.new
45
-
46
- location.viewbox = viewbox_coords l.elements['ViewBox/gml:Box/gml:coordinates']
47
-
48
- location.name = l.attributes['Name']
49
- location.type = l.attributes['Type']
50
- population = l.attributes['Population'].to_i
51
- location.population = population > 0 ? population : nil
52
- location.hierarchy = l.attributes['Hierarchy']
53
-
54
- coords = l.elements['Centroid/gml:Point/gml:coordinates'].text.split ','
55
- location.latitude = coords.first.to_f
56
- location.longitude = coords.last.to_f
57
-
58
- confidence = l.elements['Confidence']
59
- location.confidence = confidence.text.to_f if confidence
60
-
61
- locations << location
62
- end
63
-
64
- query_viewbox = xml.elements['/Locations/ViewBox/gml:Box/gml:coordinates']
65
-
66
- return locations, viewbox_coords(query_viewbox)
67
- end
68
-
69
- # Turns a element containing a pair of coordinates into a pair of coordinate
70
- # Arrays.
71
- def viewbox_coords(viewbox) # :nodoc:
72
- return viewbox.text.split(' ').map do |coords|
73
- coords.split(',').map { |c| c.to_f }
74
- end
75
- end
76
-
77
- end
78
-
79
- # A Location contains the following fields:
80
- #
81
- # +name+:: The name of this location
82
- # +type+:: The type of this location (no clue what it means)
83
- # +population+:: The number of people who live here or nil
84
- # +hierarchy+:: The places above this place
85
- # +latitude+:: Latitude of the location
86
- # +longitude+:: Longitude of the location
87
- # +confidence+:: Accuracy confidence (if any)
88
- # +viewbox+:: Pair of coordinates forming a box around this place
89
- #
90
- # viewbox runs from lower left to upper right.
91
- class MetaCartaGeocoder::Location
92
-
93
- ##
94
- # The latitude and longitude for this location.
95
-
96
- def coordinates
97
- [latitude, longitude]
98
- end
99
-
100
- end
101
-
102
- end
@@ -1,98 +0,0 @@
1
- require 'open-uri'
2
- require 'rexml/document'
3
-
4
- module Graticule #:nodoc:
5
-
6
- # Abstract class for implementing REST APIs.
7
- #
8
- # === Example
9
- #
10
- # The following methods must be implemented in sublcasses:
11
- #
12
- # +initialize+:: Sets @url to the service enpoint.
13
- # +check_error+:: Checks for errors in the server response.
14
- # +parse_response+:: Extracts information from the server response.
15
- #
16
- # If you have extra URL paramaters (application id, output type) or need to
17
- # perform URL customization, override +make_url+.
18
- #
19
- # class FakeService < RCRest
20
- #
21
- # class Error < RCRest::Error; end
22
- #
23
- # def initialize(appid)
24
- # @appid = appid
25
- # @url = URI.parse 'http://example.com/test'
26
- # end
27
- #
28
- # def check_error(xml)
29
- # raise Error, xml.elements['error'].text if xml.elements['error']
30
- # end
31
- #
32
- # def make_url(params)
33
- # params[:appid] = @appid
34
- # super params
35
- # end
36
- #
37
- # def parse_response(xml)
38
- # return xml
39
- # end
40
- #
41
- # def test(query)
42
- # get :q => query
43
- # end
44
- #
45
- # end
46
- class RestGeocoder < Geocoder
47
-
48
- # Web services initializer.
49
- #
50
- # Concrete web services implementations must set the +url+ instance
51
- # variable which must be a URI.
52
- def initialize
53
- raise NotImplementedError
54
- end
55
-
56
- # Must extract and raise an error from +xml+, an REXML::Document, if any.
57
- # Must returns if no error could be found.
58
- def check_error(xml)
59
- raise NotImplementedError
60
- end
61
-
62
- # Performs a GET request with +params+. Calls the parse_response method on
63
- # the concrete class with an REXML::Document instance and returns its
64
- # result.
65
- def get(params = {})
66
- url = make_url params
67
-
68
- url.open do |response|
69
- res = REXML::Document.new response.read
70
- check_error(res)
71
- return parse_response(res)
72
- end
73
- rescue OpenURI::HTTPError => e
74
- response = REXML::Document.new e.io.read
75
- check_error response
76
- raise
77
- end
78
-
79
- # Creates a URI from the Hash +params+. Override this then call super if
80
- # you need to add extra params like an application id or output type.
81
- def make_url(params)
82
- escaped_params = params.sort_by { |k,v| k.to_s }.map do |k,v|
83
- "#{URI.escape k.to_s}=#{URI.escape v.to_s}"
84
- end
85
-
86
- url = @url.dup
87
- url.query = escaped_params.join '&'
88
- return url
89
- end
90
-
91
- # Must parse results from +xml+, an REXML::Document, into something sensible
92
- # for the API.
93
- def parse_response(xml)
94
- raise NotImplementedError
95
- end
96
-
97
- end
98
- end