aub-graticule 0.2.11
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/.gitignore +4 -0
- data/CHANGELOG.txt +61 -0
- data/LICENSE.txt +30 -0
- data/Manifest.txt +84 -0
- data/README.txt +41 -0
- data/Rakefile +143 -0
- data/VERSION +1 -0
- data/bin/geocode +5 -0
- data/graticule.gemspec +143 -0
- data/init.rb +2 -0
- data/lib/graticule/cli.rb +64 -0
- data/lib/graticule/core_ext.rb +15 -0
- data/lib/graticule/distance/haversine.rb +40 -0
- data/lib/graticule/distance/spherical.rb +52 -0
- data/lib/graticule/distance/vincenty.rb +76 -0
- data/lib/graticule/distance.rb +18 -0
- data/lib/graticule/geocoder/base.rb +116 -0
- data/lib/graticule/geocoder/bogus.rb +15 -0
- data/lib/graticule/geocoder/geocoder_ca.rb +54 -0
- data/lib/graticule/geocoder/geocoder_us.rb +51 -0
- data/lib/graticule/geocoder/google.rb +100 -0
- data/lib/graticule/geocoder/host_ip.rb +41 -0
- data/lib/graticule/geocoder/local_search_maps.rb +44 -0
- data/lib/graticule/geocoder/mapquest.rb +96 -0
- data/lib/graticule/geocoder/meta_carta.rb +32 -0
- data/lib/graticule/geocoder/multi.rb +46 -0
- data/lib/graticule/geocoder/multimap.rb +73 -0
- data/lib/graticule/geocoder/postcode_anywhere.rb +63 -0
- data/lib/graticule/geocoder/rest.rb +18 -0
- data/lib/graticule/geocoder/yahoo.rb +84 -0
- data/lib/graticule/geocoder.rb +21 -0
- data/lib/graticule/location.rb +61 -0
- data/lib/graticule/version.rb +9 -0
- data/lib/graticule.rb +26 -0
- data/site/index.html +114 -0
- data/site/plugin.html +82 -0
- data/site/stylesheets/style.css +69 -0
- data/test/config.yml.default +36 -0
- data/test/fixtures/responses/geocoder_us/success.xml +18 -0
- data/test/fixtures/responses/geocoder_us/unknown.xml +1 -0
- data/test/fixtures/responses/google/badkey.xml +1 -0
- data/test/fixtures/responses/google/limit.xml +10 -0
- data/test/fixtures/responses/google/missing_address.xml +1 -0
- data/test/fixtures/responses/google/only_coordinates.xml +1 -0
- data/test/fixtures/responses/google/partial.xml +1 -0
- data/test/fixtures/responses/google/server_error.xml +10 -0
- data/test/fixtures/responses/google/success.xml +1 -0
- data/test/fixtures/responses/google/success_multiple_results.xml +88 -0
- data/test/fixtures/responses/google/unavailable.xml +1 -0
- data/test/fixtures/responses/google/unknown_address.xml +1 -0
- data/test/fixtures/responses/host_ip/private.txt +4 -0
- data/test/fixtures/responses/host_ip/success.txt +4 -0
- data/test/fixtures/responses/host_ip/unknown.txt +4 -0
- data/test/fixtures/responses/local_search_maps/empty.txt +1 -0
- data/test/fixtures/responses/local_search_maps/not_found.txt +1 -0
- data/test/fixtures/responses/local_search_maps/success.txt +1 -0
- data/test/fixtures/responses/mapquest/multi_result.xml +1 -0
- data/test/fixtures/responses/mapquest/success.xml +1 -0
- data/test/fixtures/responses/meta_carta/bad_address.xml +17 -0
- data/test/fixtures/responses/meta_carta/multiple.xml +33 -0
- data/test/fixtures/responses/meta_carta/success.xml +31 -0
- data/test/fixtures/responses/multimap/missing_params.xml +4 -0
- data/test/fixtures/responses/multimap/no_matches.xml +4 -0
- data/test/fixtures/responses/multimap/success.xml +19 -0
- data/test/fixtures/responses/postcode_anywhere/badkey.xml +9 -0
- data/test/fixtures/responses/postcode_anywhere/canada.xml +16 -0
- data/test/fixtures/responses/postcode_anywhere/empty.xml +16 -0
- data/test/fixtures/responses/postcode_anywhere/success.xml +16 -0
- data/test/fixtures/responses/postcode_anywhere/uk.xml +18 -0
- data/test/fixtures/responses/yahoo/success.xml +3 -0
- data/test/fixtures/responses/yahoo/unknown_address.xml +6 -0
- data/test/mocks/uri.rb +52 -0
- data/test/test_helper.rb +31 -0
- data/test/unit/graticule/distance_test.rb +58 -0
- data/test/unit/graticule/geocoder/geocoder_us_test.rb +43 -0
- data/test/unit/graticule/geocoder/geocoders.rb +56 -0
- data/test/unit/graticule/geocoder/google_test.rb +112 -0
- data/test/unit/graticule/geocoder/host_ip_test.rb +40 -0
- data/test/unit/graticule/geocoder/local_search_maps_test.rb +30 -0
- data/test/unit/graticule/geocoder/mapquest_test.rb +61 -0
- data/test/unit/graticule/geocoder/meta_carta_test.rb +44 -0
- data/test/unit/graticule/geocoder/multi_test.rb +43 -0
- data/test/unit/graticule/geocoder/multimap_test.rb +52 -0
- data/test/unit/graticule/geocoder/postcode_anywhere_test.rb +50 -0
- data/test/unit/graticule/geocoder/yahoo_test.rb +48 -0
- data/test/unit/graticule/geocoder_test.rb +27 -0
- data/test/unit/graticule/location_test.rb +73 -0
- metadata +166 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
module Graticule
|
3
|
+
module Geocoder
|
4
|
+
|
5
|
+
# Library for looking up coordinates with MetaCarta's GeoParser API.
|
6
|
+
#
|
7
|
+
# http://labs.metacarta.com/GeoParser/documentation.html
|
8
|
+
class MetaCarta < Rest
|
9
|
+
|
10
|
+
def initialize # :nodoc:
|
11
|
+
@url = URI.parse 'http://labs.metacarta.com/GeoParser/'
|
12
|
+
end
|
13
|
+
|
14
|
+
# Finds +location+ and returns a Location object.
|
15
|
+
def locate(location)
|
16
|
+
get :q => location.is_a?(String) ? location : location_from_params(location).to_s, :output => 'locations'
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def check_error(xml) # :nodoc:
|
22
|
+
raise AddressError, 'bad location' unless xml.elements['Locations/Location']
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse_response(xml) # :nodoc:
|
26
|
+
result = xml.elements['/Locations/Location[1]']
|
27
|
+
coords = result.elements['Centroid/gml:Point/gml:coordinates'].text.split ','
|
28
|
+
[Location.new(:latitude => coords.first.to_f, :longitude => coords.last.to_f)]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Graticule #:nodoc:
|
2
|
+
module Geocoder #:nodoc:
|
3
|
+
class Multi
|
4
|
+
|
5
|
+
# The Multi geocoder allows you to use multiple geocoders in succession.
|
6
|
+
#
|
7
|
+
# geocoder = Graticule.service(:multi).new(
|
8
|
+
# Graticule.service(:google).new("api_key"),
|
9
|
+
# Graticule.service(:yahoo).new("api_key"),
|
10
|
+
# )
|
11
|
+
# geocoder.locate '49423' # <= tries geocoders in succession
|
12
|
+
#
|
13
|
+
# The Multi geocoder will try the geocoders in order if a Graticule::AddressError
|
14
|
+
# is raised. You can customize this behavior by passing in a block to the Multi
|
15
|
+
# geocoder. For example, to try the geocoders until one returns a result with a
|
16
|
+
# high enough precision:
|
17
|
+
#
|
18
|
+
# geocoder = Graticule.service(:multi).new(geocoders) do |result|
|
19
|
+
# [:address, :street].include?(result.precision)
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# Geocoders will be tried in order until the block returned true for one of the results
|
23
|
+
#
|
24
|
+
def initialize(*geocoders, &acceptable)
|
25
|
+
@acceptable = acceptable || lambda { true }
|
26
|
+
@geocoders = geocoders.flatten
|
27
|
+
end
|
28
|
+
|
29
|
+
def locate(address)
|
30
|
+
last_error = nil
|
31
|
+
@geocoders.each do |geocoder|
|
32
|
+
begin
|
33
|
+
result = geocoder.locate address
|
34
|
+
return result if @acceptable.call(result)
|
35
|
+
rescue Error => e
|
36
|
+
last_error = e
|
37
|
+
rescue Errno::ECONNREFUSED
|
38
|
+
logger.error("Connection refused to #{service}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
raise last_error || AddressError.new("Couldn't find '#{address}' with any of the services")
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Graticule #:nodoc:
|
2
|
+
module Geocoder #:nodoc:
|
3
|
+
|
4
|
+
# Multimap geocoding API
|
5
|
+
|
6
|
+
class Multimap < Rest
|
7
|
+
|
8
|
+
# This precision information is not complete.
|
9
|
+
# More details should be implemented from:
|
10
|
+
# http://www.multimap.com/share/documentation/clientzone/gqcodes.htm
|
11
|
+
|
12
|
+
PRECISION = {
|
13
|
+
"6"=> :country,
|
14
|
+
"5" => :state,
|
15
|
+
"4" => :postal_code,
|
16
|
+
"3" => :city,
|
17
|
+
"2" => :street,
|
18
|
+
"1" => :address
|
19
|
+
}
|
20
|
+
|
21
|
+
# Web services initializer.
|
22
|
+
#
|
23
|
+
# The +api_key+ is the Open API key that uniquely identifies your
|
24
|
+
# application.
|
25
|
+
#
|
26
|
+
# See http://www.multimap.com/openapi/
|
27
|
+
|
28
|
+
def initialize(api_key)
|
29
|
+
@api_key = api_key
|
30
|
+
@url = URI.parse "http://clients.multimap.com/API/geocode/1.2/#{@api_key}"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns a location for an address in the form of a String, Hash or Location.
|
34
|
+
|
35
|
+
def locate(address)
|
36
|
+
location = address.is_a?(String) ? address : location_from_params(address)
|
37
|
+
case location
|
38
|
+
when String
|
39
|
+
get :qs => location
|
40
|
+
when Location
|
41
|
+
get "street" => location.street,
|
42
|
+
"region" => location.region,
|
43
|
+
"city" => location.city,
|
44
|
+
"postalCode" => location.postal_code,
|
45
|
+
"countryCode" => location.country
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse_response(xml)
|
50
|
+
r = xml.elements['Results/Location[1]']
|
51
|
+
|
52
|
+
location = Location.new
|
53
|
+
location.precision = PRECISION[r.attributes['geocodeQuality']] || :unknown
|
54
|
+
|
55
|
+
location.street = r.elements['Address/Street'].text.titleize unless r.elements['Address/Street'].nil?
|
56
|
+
location.locality = r.elements['Address/Areas/Area'].text.titleize unless r.elements['Address/Areas/Area'].nil?
|
57
|
+
location.region = r.elements['Address/State'].text.titleize unless r.elements['Address/State'].nil?
|
58
|
+
location.postal_code = r.elements['Address/PostalCode'].text unless r.elements['Address/PostalCode'].nil?
|
59
|
+
location.country = r.elements['Address/CountryCode'].text
|
60
|
+
|
61
|
+
location.latitude = r.elements['Point/Lat'].text.to_f
|
62
|
+
location.longitude = r.elements['Point/Lon'].text.to_f
|
63
|
+
[location]
|
64
|
+
end
|
65
|
+
|
66
|
+
def check_error(xml)
|
67
|
+
error = xml.elements['Results'].attributes['errorCode']
|
68
|
+
raise Error, error unless error.nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Graticule #:nodoc:
|
2
|
+
module Geocoder #:nodoc:
|
3
|
+
|
4
|
+
class PostcodeAnywhere < Rest
|
5
|
+
|
6
|
+
# http://www.postcodeanywhere.com/register/
|
7
|
+
def initialize(account_code, license_code)
|
8
|
+
@url = URI.parse 'http://services.postcodeanywhere.co.uk/xml.aspx'
|
9
|
+
@account_code = account_code
|
10
|
+
@license_code = license_code
|
11
|
+
end
|
12
|
+
|
13
|
+
def locate(params)
|
14
|
+
location = location_from_params(params)
|
15
|
+
get :address => location.to_s(:country => false), :country => location.country
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def make_url(params) #:nodoc:
|
21
|
+
params[:account_code] = @account_code
|
22
|
+
params[:license_code] = @license_code
|
23
|
+
params[:action] = 'geocode'
|
24
|
+
super params
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse_response(xml) #:nodoc:
|
28
|
+
result = xml.elements['/PostcodeAnywhere/Data/Item[1]']
|
29
|
+
location = Location.new
|
30
|
+
location.latitude = result.attribute('latitude').value.to_f
|
31
|
+
location.longitude = result.attribute('longitude').value.to_f
|
32
|
+
location.street = value(result.attribute('line1'))
|
33
|
+
location.locality = value(result.attribute('city'))
|
34
|
+
location.region = value(result.attribute('state'))
|
35
|
+
location.postal_code = value(result.attribute('postal_code'))
|
36
|
+
location.country = value(result.attribute('country'))
|
37
|
+
[location]
|
38
|
+
end
|
39
|
+
|
40
|
+
def value(attribute)
|
41
|
+
attribute.value if attribute
|
42
|
+
end
|
43
|
+
|
44
|
+
# http://www.postcodeanywhere.co.uk/developers/documentation/errors.aspx
|
45
|
+
def check_error(xml) #:nodoc:
|
46
|
+
#raise AddressError, xml.text if xml.text == 'couldn\'t find this address! sorry'
|
47
|
+
if error = xml.elements['/PostcodeAnywhere/Data/Item[@error_number][1]']
|
48
|
+
error_number = error.attribute('error_number').value.to_i
|
49
|
+
message = error.attribute('message').value
|
50
|
+
if (1..11).include?(error_number) || (34..38).include?(error_number)
|
51
|
+
raise CredentialsError, message
|
52
|
+
else
|
53
|
+
raise Error, message
|
54
|
+
end
|
55
|
+
elsif xml.elements['/PostcodeAnywhere/Data'].elements.empty?
|
56
|
+
raise AddressError, 'No results returned'
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module Graticule #:nodoc:
|
4
|
+
module Geocoder #:nodoc:
|
5
|
+
|
6
|
+
# Abstract class for implementing REST geocoders. Passes on a REXML::Document
|
7
|
+
# to +check_errors+ and +parse_response+.
|
8
|
+
class Rest < Base
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def prepare_response(response)
|
13
|
+
REXML::Document.new(response)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Graticule #:nodoc:
|
2
|
+
module Geocoder #:nodoc:
|
3
|
+
|
4
|
+
# Yahoo geocoding API.
|
5
|
+
#
|
6
|
+
# http://developer.yahoo.com/maps/rest/V1/geocode.html
|
7
|
+
class Yahoo < Rest
|
8
|
+
|
9
|
+
PRECISION = {
|
10
|
+
"country"=> :country,
|
11
|
+
"state" => :state,
|
12
|
+
"city" => :city,
|
13
|
+
"zip+4" => :zip,
|
14
|
+
"zip+2" => :zip,
|
15
|
+
"zip" => :zip,
|
16
|
+
"street" => :street,
|
17
|
+
"address" => :address
|
18
|
+
}
|
19
|
+
|
20
|
+
# Web services initializer.
|
21
|
+
#
|
22
|
+
# The +appid+ is the Application ID that uniquely identifies your
|
23
|
+
# application. See: http://developer.yahoo.com/faq/index.html#appid
|
24
|
+
#
|
25
|
+
# See http://developer.yahoo.com/search/rest.html
|
26
|
+
def initialize(appid)
|
27
|
+
@appid = appid
|
28
|
+
@url = URI.parse "http://api.local.yahoo.com/MapsService/V1/geocode"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns a Location for +address+.
|
32
|
+
#
|
33
|
+
# The +address+ can be any of:
|
34
|
+
# * city, state
|
35
|
+
# * city, state, zip
|
36
|
+
# * zip
|
37
|
+
# * street, city, state
|
38
|
+
# * street, city, state, zip
|
39
|
+
# * street, zip
|
40
|
+
def locate(address)
|
41
|
+
location = (address.is_a?(String) ? address : location_from_params(address).to_s(:country => false))
|
42
|
+
# yahoo pukes on line breaks
|
43
|
+
get :location => location.gsub("\n", ', ')
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse_response(xml) # :nodoc:
|
47
|
+
r = xml.elements['ResultSet/Result[1]']
|
48
|
+
location = Location.new
|
49
|
+
location.precision = PRECISION[r.attributes['precision']] || :unknown
|
50
|
+
|
51
|
+
if r.attributes.include? 'warning' then
|
52
|
+
location.warning = r.attributes['warning']
|
53
|
+
end
|
54
|
+
|
55
|
+
location.latitude = r.elements['Latitude'].text.to_f
|
56
|
+
location.longitude = r.elements['Longitude'].text.to_f
|
57
|
+
|
58
|
+
location.street = r.elements['Address'].text.titleize unless r.elements['Address'].text.blank?
|
59
|
+
location.locality = r.elements['City'].text.titleize unless r.elements['City'].text.blank?
|
60
|
+
location.region = r.elements['State'].text
|
61
|
+
location.postal_code = r.elements['Zip'].text
|
62
|
+
location.country = r.elements['Country'].text
|
63
|
+
[location]
|
64
|
+
end
|
65
|
+
|
66
|
+
# Extracts and raises an error from +xml+, if any.
|
67
|
+
def check_error(xml) #:nodoc:
|
68
|
+
err = xml.elements['Error']
|
69
|
+
raise Error, err.elements['Message'].text if err
|
70
|
+
end
|
71
|
+
|
72
|
+
# Creates a URL from the Hash +params+. Automatically adds the appid and
|
73
|
+
# sets the output type to 'xml'.
|
74
|
+
def make_url(params) #:nodoc:
|
75
|
+
params[:appid] = @appid
|
76
|
+
params[:output] = 'xml'
|
77
|
+
|
78
|
+
super params
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
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,61 @@
|
|
1
|
+
module Graticule
|
2
|
+
|
3
|
+
# A geographic location
|
4
|
+
class Location
|
5
|
+
attr_accessor :latitude, :longitude, :street, :locality, :region, :postal_code, :country, :precision, :warning
|
6
|
+
alias_method :city, :locality
|
7
|
+
alias_method :state, :region
|
8
|
+
alias_method :zip, :postal_code
|
9
|
+
|
10
|
+
def initialize(attrs = {})
|
11
|
+
attrs.each do |key,value|
|
12
|
+
instance_variable_set "@#{key}", value
|
13
|
+
end
|
14
|
+
self.precision ||= :unknown
|
15
|
+
end
|
16
|
+
|
17
|
+
def attributes
|
18
|
+
[:latitude, :longitude, :street, :locality, :region, :postal_code, :country, :precision].inject({}) do |result,attr|
|
19
|
+
result[attr] = self.send(attr) unless self.send(attr).blank?
|
20
|
+
result
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def blank?
|
25
|
+
attributes.except(:precision).empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns an Array with latitude and longitude.
|
29
|
+
def coordinates
|
30
|
+
[latitude, longitude]
|
31
|
+
end
|
32
|
+
|
33
|
+
def ==(other)
|
34
|
+
other.respond_to?(:attributes) ? attributes == other.attributes : false
|
35
|
+
end
|
36
|
+
|
37
|
+
# Calculate the distance to another location. See the various Distance formulas
|
38
|
+
# for more information
|
39
|
+
def distance_to(destination, options = {})
|
40
|
+
options = {:formula => :haversine, :units => :miles}.merge(options)
|
41
|
+
"Graticule::Distance::#{options[:formula].to_s.titleize}".constantize.distance(self, destination, options[:units])
|
42
|
+
end
|
43
|
+
|
44
|
+
# Where would I be if I dug through the center of the earth?
|
45
|
+
def antipode
|
46
|
+
Location.new :latitude => -latitude, :longitude => longitude + (longitude >= 0 ? -180 : 180)
|
47
|
+
end
|
48
|
+
alias_method :antipodal_location, :antipode
|
49
|
+
|
50
|
+
def to_s(options = {})
|
51
|
+
options = {:coordinates => false, :country => true}.merge(options)
|
52
|
+
result = ""
|
53
|
+
result << "#{street}\n" if street
|
54
|
+
result << [locality, [region, postal_code].compact.join(" ")].compact.join(", ")
|
55
|
+
result << " #{country}" if options[:country] && country
|
56
|
+
result << "\nlatitude: #{latitude}, longitude: #{longitude}" if options[:coordinates] && [latitude, longitude].any?
|
57
|
+
result
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
data/lib/graticule.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
|
5
|
+
require 'graticule/version'
|
6
|
+
require 'graticule/core_ext'
|
7
|
+
require 'graticule/location'
|
8
|
+
require 'graticule/geocoder'
|
9
|
+
require 'graticule/geocoder/base'
|
10
|
+
require 'graticule/geocoder/bogus'
|
11
|
+
require 'graticule/geocoder/rest'
|
12
|
+
require 'graticule/geocoder/google'
|
13
|
+
require 'graticule/geocoder/host_ip'
|
14
|
+
require 'graticule/geocoder/multi'
|
15
|
+
require 'graticule/geocoder/yahoo'
|
16
|
+
require 'graticule/geocoder/geocoder_ca'
|
17
|
+
require 'graticule/geocoder/geocoder_us'
|
18
|
+
require 'graticule/geocoder/local_search_maps'
|
19
|
+
require 'graticule/geocoder/meta_carta'
|
20
|
+
require 'graticule/geocoder/postcode_anywhere'
|
21
|
+
require 'graticule/geocoder/multimap'
|
22
|
+
require 'graticule/geocoder/mapquest'
|
23
|
+
require 'graticule/distance'
|
24
|
+
require 'graticule/distance/haversine'
|
25
|
+
require 'graticule/distance/spherical'
|
26
|
+
require 'graticule/distance/vincenty'
|
data/site/index.html
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
3
|
+
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
5
|
+
<head>
|
6
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
7
|
+
<title>Graticule</title>
|
8
|
+
<link rel="stylesheet" type="text/css" href="http://opensoul.org/stylesheets/code.css" />
|
9
|
+
<link rel="stylesheet" type="text/css" href="stylesheets/style.css" />
|
10
|
+
<link href="http://opensoul.org/stylesheets/ci.css" rel="stylesheet" type="text/css" />
|
11
|
+
<script src="http://opensoul.org/javascripts/code_highlighter.js" type="text/javascript"></script>
|
12
|
+
<script src="http://opensoul.org/javascripts/ruby.js" type="text/javascript"></script>
|
13
|
+
</head>
|
14
|
+
|
15
|
+
<body>
|
16
|
+
<div id="collectiveidea">
|
17
|
+
<a href="http://collectiveidea.com"><img src="http://opensoul.org/images/header_logo.gif" alt="Collective Idea" class="logo" width="17" height="22" /></a>
|
18
|
+
<ul class="links">
|
19
|
+
<li><a href="http://daniel.collectiveidea.com/blog">Daniel</a></li>
|
20
|
+
<li><a href="http://opensoul.org">Brandon</a></li>
|
21
|
+
<li class="name"><a href="http://collectiveidea.com"><img src="http://opensoul.org/images/header_collectiveidea.gif" alt="Collective Idea" width="123" height="21" /></a></li>
|
22
|
+
</ul>
|
23
|
+
</div>
|
24
|
+
<div id="main">
|
25
|
+
<div id="header">
|
26
|
+
<h1><a href="/">Graticule</a></h1>
|
27
|
+
<ul id="nav">
|
28
|
+
<li><a href="graticule">API Docs</a></li>
|
29
|
+
<li><a href="plugin.html">Rails Plugin</a></li>
|
30
|
+
<li><a href="http://rubyforge.org/projects/graticule">RubyForge</a></li>
|
31
|
+
<li><a href="http://opensoul.org/tags/geocoding">Blog</a></li>
|
32
|
+
</ul>
|
33
|
+
</div>
|
34
|
+
<div id="content">
|
35
|
+
<dl lang="en" xml:lang="en">
|
36
|
+
<dt><strong>grat·i·cule</strong>, <span class="pronunciation">|ˈgratəˌkyoōl|</span>,
|
37
|
+
<em><abbr title="noun">n.</abbr></em>
|
38
|
+
<span class="description">technical</span>
|
39
|
+
</dt>
|
40
|
+
<dd><em>Navigation.</em> a network of parallels and meridians on a map or chart.</dd>
|
41
|
+
</dl>
|
42
|
+
|
43
|
+
<p>Graticule is a geocoding API for looking up address coordinates and performing distance calculations. It supports many popular APIs, including:</p>
|
44
|
+
|
45
|
+
<ul>
|
46
|
+
<li>Yahoo</li>
|
47
|
+
<li>Google</li>
|
48
|
+
<li>Geocoder.ca</li>
|
49
|
+
<li>Geocoder.us</li>
|
50
|
+
<li>PostcodeAnywhere</li>
|
51
|
+
<li>MetaCarta</li>
|
52
|
+
</ul>
|
53
|
+
|
54
|
+
<p>There is a <a href="plugin.html">companion Rails plugin</a> that makes geocoding seem like magic.</p>
|
55
|
+
|
56
|
+
<h2>Example</h2>
|
57
|
+
|
58
|
+
<pre><code class="ruby">require 'rubygems'
|
59
|
+
require 'graticule'
|
60
|
+
geocoder = Graticule.service(:google).new "api_key"
|
61
|
+
location = geocoder.locate "1600 Amphitheatre Parkway, Mountain View, CA"
|
62
|
+
location.coordinates #=> [37.423021, -122.083739]
|
63
|
+
location.country #=> "US"</code></pre>
|
64
|
+
|
65
|
+
<p>See the <a href="graticule">API documentation</a> for more details.</p>
|
66
|
+
|
67
|
+
<h2>International Support</h2>
|
68
|
+
|
69
|
+
<p>Graticule supports several services with international support. The international geocoders require slightly more structured data than the US ones:</p>
|
70
|
+
|
71
|
+
<pre><code class="ruby">g = Graticule.service(:local_search_maps).new
|
72
|
+
location = g.locate :street => '48 Leicester Square', :locality => 'London', :country => 'UK'
|
73
|
+
location.coordinates #=> [51.510036, -0.130427]</code></pre>
|
74
|
+
|
75
|
+
<h2>Distance Calculation</h2>
|
76
|
+
|
77
|
+
<p>Graticule includes 3 different distance formulas, Spherical (simplest but least accurate), Vincenty (most accurate and most complicated), and Haversine (somewhere inbetween).</p>
|
78
|
+
|
79
|
+
<pre><code class="ruby">location = geocoder.locate("Holland, MI")
|
80
|
+
location.distance_to(geocoder.locate("Chicago, IL"))
|
81
|
+
#=> 101.997458788177</code></pre>
|
82
|
+
|
83
|
+
<h2>Command Line</h2>
|
84
|
+
<p>Graticule also includes a command line interface to the various geocoders:</p>
|
85
|
+
|
86
|
+
<pre>
|
87
|
+
$ geocode -s yahoo -a yahookey Washington, DC
|
88
|
+
Washington, DC US
|
89
|
+
latitude: 38.895222, longitude: -77.036758</pre>
|
90
|
+
|
91
|
+
<h2>Installation</h2>
|
92
|
+
|
93
|
+
<p>Install the gem by executing:</p>
|
94
|
+
|
95
|
+
<pre>gem install graticule</pre>
|
96
|
+
|
97
|
+
<p>Or, download it from <a href="http://rubyforge.org/frs/?group_id=2643">RubyForge</a>.</p>
|
98
|
+
|
99
|
+
<h2>Contributing</h2>
|
100
|
+
|
101
|
+
<p>Contributions are welcome and appreciated! Join the <a href="http://rubyforge.org/mailman/listinfo/graticule-users">mailing list</a> and grab the source from:</p>
|
102
|
+
|
103
|
+
<pre>http://source.collectiveidea.com/public/geocode/trunk/</pre>
|
104
|
+
</div>
|
105
|
+
</div>
|
106
|
+
|
107
|
+
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
|
108
|
+
</script>
|
109
|
+
<script type="text/javascript">
|
110
|
+
_uacct = "UA-194397-7";
|
111
|
+
urchinTracker();
|
112
|
+
</script>
|
113
|
+
</body>
|
114
|
+
</html>
|
data/site/plugin.html
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
3
|
+
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
5
|
+
<head>
|
6
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
7
|
+
<title>acts_as_geocodable - Graticule</title>
|
8
|
+
<link rel="stylesheet" type="text/css" href="http://opensoul.org/stylesheets/code.css" />
|
9
|
+
<link rel="stylesheet" type="text/css" href="stylesheets/style.css" />
|
10
|
+
<link href="http://opensoul.org/stylesheets/ci.css" rel="stylesheet" type="text/css" />
|
11
|
+
<script src="http://opensoul.org/javascripts/code_highlighter.js" type="text/javascript"></script>
|
12
|
+
<script src="http://opensoul.org/javascripts/ruby.js" type="text/javascript"></script>
|
13
|
+
</head>
|
14
|
+
|
15
|
+
<body>
|
16
|
+
<div id="collectiveidea">
|
17
|
+
<a href="http://collectiveidea.com"><img src="http://opensoul.org/images/header_logo.gif" alt="Collective Idea" class="logo" width="17" height="22" /></a>
|
18
|
+
<ul class="links">
|
19
|
+
<li><a href="http://daniel.collectiveidea.com/blog">Daniel</a></li>
|
20
|
+
<li><a href="http://opensoul.org">Brandon</a></li>
|
21
|
+
<li class="name"><a href="http://collectiveidea.com"><img src="http://opensoul.org/images/header_collectiveidea.gif" alt="Collective Idea" width="123" height="21" /></a></li>
|
22
|
+
</ul>
|
23
|
+
</div>
|
24
|
+
<div id="main">
|
25
|
+
<div id="header">
|
26
|
+
<h1><a href="/">Graticule</a> » acts_as_geocodable</h1>
|
27
|
+
<ul id="nav">
|
28
|
+
<li><a href="acts_as_geocodable">API Docs</a></li>
|
29
|
+
<li><a href="plugin.html">Rails Plugin</a></li>
|
30
|
+
<li><a href="http://rubyforge.org/projects/graticule">RubyForge</a></li>
|
31
|
+
<li><a href="http://opensoul.org/tags/geocoding">Blog</a></li>
|
32
|
+
</ul>
|
33
|
+
</div>
|
34
|
+
<div id="content">
|
35
|
+
<p>acts_as_geocodable is a Rails plugin that makes your applications geo-aware. A picture (er, example) is worth a thousand words:</p>
|
36
|
+
|
37
|
+
<h2>Examples</h2>
|
38
|
+
|
39
|
+
<pre><code class="ruby">event = Event.create :street => "777 NE Martin Luther King, Jr. Blvd.",
|
40
|
+
:locality => "Portland", :region => "Oregon", :postal_code => 97232
|
41
|
+
|
42
|
+
# how far am I from RailsConf 2007?
|
43
|
+
event.distance_to "49423" #=> 1807.66560483205
|
44
|
+
|
45
|
+
# Find our new event, and any other ones in the area
|
46
|
+
Event.find(:all, :within => 50, :origin => "97232")
|
47
|
+
|
48
|
+
# Find the nearest restaurant with beer
|
49
|
+
Restaurant.find(:nearest, :origin => event, :conditions => 'beer = true')</code></pre>
|
50
|
+
|
51
|
+
|
52
|
+
<p>See the <a href="acts_as_geocodable">API documentation</a> for more details.</p>
|
53
|
+
|
54
|
+
<h2>IP-based geocoding</h2>
|
55
|
+
|
56
|
+
<p>acts_as_geocodable adds a <code>remote_location</code> method to your Rails controllers for retrieving a user's location based on their remote IP address.</p>
|
57
|
+
|
58
|
+
<pre><code class="ruby">@nearest_store = Store.find(:nearest, :origin => remote_location) if remote_location</code></pre>
|
59
|
+
|
60
|
+
<p>Don't rely too heavily on remote_location because the location of many IP addresses cannot be determined through <a href="http://hostip.info">HostIP</a>.
|
61
|
+
|
62
|
+
<h2>Installation</h2>
|
63
|
+
|
64
|
+
<p>Install the plugin by executing:</p>
|
65
|
+
|
66
|
+
<pre>script/plugin install -x http://source.collectiveidea.com/public/rails/plugins/acts_as_geocodable</pre>
|
67
|
+
|
68
|
+
<h2>Contributing</h2>
|
69
|
+
|
70
|
+
<p>Contributions are welcome and appreciated! Grab the source from:</p>
|
71
|
+
|
72
|
+
<pre>http://source.collectiveidea.com/public/rails/plugins/acts_as_geocodable</pre>
|
73
|
+
</div>
|
74
|
+
</div>
|
75
|
+
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
|
76
|
+
</script>
|
77
|
+
<script type="text/javascript">
|
78
|
+
_uacct = "UA-194397-7";
|
79
|
+
urchinTracker();
|
80
|
+
</script>
|
81
|
+
</body>
|
82
|
+
</html>
|