aub-graticule 0.2.11
Sign up to get free protection for your applications and to get access to all the features.
- 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>
|