graticule 2.0.1 → 2.1.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.
- data/lib/graticule.rb +1 -0
- data/lib/graticule/cli.rb +12 -11
- data/lib/graticule/core_ext.rb +3 -2
- data/lib/graticule/distance.rb +3 -2
- data/lib/graticule/distance/haversine.rb +6 -5
- data/lib/graticule/distance/spherical.rb +4 -3
- data/lib/graticule/distance/vincenty.rb +2 -1
- data/lib/graticule/geocoder.rb +3 -2
- data/lib/graticule/geocoder/base.rb +10 -9
- data/lib/graticule/geocoder/bogus.rb +4 -3
- data/lib/graticule/geocoder/freethepostcode.rb +5 -4
- data/lib/graticule/geocoder/geocoder_ca.rb +8 -7
- data/lib/graticule/geocoder/geocoder_us.rb +3 -2
- data/lib/graticule/geocoder/geonames.rb +9 -8
- data/lib/graticule/geocoder/google.rb +12 -11
- data/lib/graticule/geocoder/host_ip.rb +4 -3
- data/lib/graticule/geocoder/local_search_maps.rb +8 -7
- data/lib/graticule/geocoder/mapquest.rb +7 -6
- data/lib/graticule/geocoder/multi.rb +12 -11
- data/lib/graticule/geocoder/multimap.rb +20 -19
- data/lib/graticule/geocoder/simple_geo.rb +1 -0
- data/lib/graticule/geocoder/yahoo.rb +10 -9
- data/lib/graticule/location.rb +2 -1
- data/lib/graticule/precision.rb +8 -7
- data/lib/graticule/version.rb +2 -1
- metadata +76 -107
data/lib/graticule.rb
CHANGED
data/lib/graticule/cli.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
require 'graticule'
|
2
3
|
require 'optparse'
|
3
4
|
|
4
5
|
module Graticule
|
5
|
-
|
6
|
+
|
6
7
|
# A command line interface for geocoding. From the command line, run:
|
7
8
|
#
|
8
|
-
# geocode 49423
|
9
|
+
# geocode 49423
|
9
10
|
#
|
10
11
|
# Outputs:
|
11
12
|
#
|
@@ -13,16 +14,16 @@ module Graticule
|
|
13
14
|
# # latitude: 42.7654, longitude: -86.1085
|
14
15
|
#
|
15
16
|
# == Usage: geocode [options] location
|
16
|
-
#
|
17
|
-
# Options:
|
17
|
+
#
|
18
|
+
# Options:
|
18
19
|
# -s, --service service Geocoding service
|
19
20
|
# -a, --apikey apikey API key for the selected service
|
20
21
|
# -h, --help Help
|
21
22
|
class Cli
|
22
|
-
|
23
|
+
|
23
24
|
def self.start(args, out = STDOUT)
|
24
25
|
options = { :service => :yahoo, :api_key => 'YahooDemo' }
|
25
|
-
|
26
|
+
|
26
27
|
OptionParser.new do |opts|
|
27
28
|
opts.banner = "Usage: geocode [options] location"
|
28
29
|
opts.separator ""
|
@@ -31,9 +32,9 @@ module Graticule
|
|
31
32
|
opts.on("-s service", %w(yahoo google geocoder_us metacarta), "--service service", "Geocoding service") do |service|
|
32
33
|
options[:service] = service
|
33
34
|
end
|
34
|
-
|
35
|
+
|
35
36
|
opts.on("-a apikey", "--apikey apikey", "API key for the selected service")
|
36
|
-
|
37
|
+
|
37
38
|
opts.on_tail("-h", "--help", "Help") do
|
38
39
|
puts opts
|
39
40
|
exit
|
@@ -41,7 +42,7 @@ module Graticule
|
|
41
42
|
end.parse! args
|
42
43
|
|
43
44
|
options[:location] = args.join(" ")
|
44
|
-
|
45
|
+
|
45
46
|
result = Graticule.service(options[:service]).new(*options[:api_key].split(',')).locate(options[:location])
|
46
47
|
location = (result.is_a?(Array) ? result.first : result)
|
47
48
|
if location
|
@@ -57,8 +58,8 @@ module Graticule
|
|
57
58
|
Graticule::Error => error
|
58
59
|
$stderr.puts error.message
|
59
60
|
end
|
60
|
-
|
61
|
-
|
61
|
+
|
62
|
+
|
62
63
|
end
|
63
64
|
end
|
64
65
|
|
data/lib/graticule/core_ext.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule
|
2
3
|
module RadiansAndDegrees
|
3
4
|
# Convert from degrees to radians
|
4
5
|
def to_radians
|
5
6
|
( self / 360.0 ) * Math::PI * 2
|
6
7
|
end
|
7
|
-
|
8
|
+
|
8
9
|
# Convert from radians to degrees
|
9
10
|
def to_degrees
|
10
11
|
( self * 360.0 ) / Math::PI / 2
|
@@ -12,4 +13,4 @@ module Graticule
|
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
15
|
-
Numeric.send :include, Graticule::RadiansAndDegrees
|
16
|
+
Numeric.send :include, Graticule::RadiansAndDegrees
|
data/lib/graticule/distance.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule
|
2
3
|
module Distance
|
3
|
-
|
4
|
+
|
4
5
|
EARTH_RADIUS = { :kilometers => 6378.135, :miles => 3963.1676 }
|
5
6
|
# WGS-84 numbers
|
6
7
|
EARTH_MAJOR_AXIS_RADIUS = { :kilometers => 6378.137, :miles => 3963.19059 }
|
@@ -9,7 +10,7 @@ module Graticule
|
|
9
10
|
class DistanceFormula
|
10
11
|
include Math
|
11
12
|
extend Math
|
12
|
-
|
13
|
+
|
13
14
|
def initialize
|
14
15
|
raise NotImplementedError
|
15
16
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule
|
2
3
|
module Distance
|
3
4
|
#
|
@@ -7,7 +8,7 @@ module Graticule
|
|
7
8
|
# for distance formulas.
|
8
9
|
#
|
9
10
|
class Haversine < DistanceFormula
|
10
|
-
|
11
|
+
|
11
12
|
# Calculate the distance between two Locations using the Haversine formula
|
12
13
|
#
|
13
14
|
# Graticule::Distance::Haversine.distance(
|
@@ -25,9 +26,9 @@ module Graticule
|
|
25
26
|
latitude_delta = to_latitude - from_latitude
|
26
27
|
longitude_delta = to_longitude - from_longitude
|
27
28
|
|
28
|
-
a = sin(latitude_delta/2)**2 +
|
29
|
-
cos(from_latitude) *
|
30
|
-
cos(to_latitude) *
|
29
|
+
a = sin(latitude_delta/2)**2 +
|
30
|
+
cos(from_latitude) *
|
31
|
+
cos(to_latitude) *
|
31
32
|
sin(longitude_delta/2)**2
|
32
33
|
|
33
34
|
c = 2 * atan2(sqrt(a), sqrt(1-a))
|
@@ -37,4 +38,4 @@ module Graticule
|
|
37
38
|
|
38
39
|
end
|
39
40
|
end
|
40
|
-
end
|
41
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule
|
2
3
|
module Distance
|
3
4
|
|
@@ -25,7 +26,7 @@ module Graticule
|
|
25
26
|
Math.sin(from_latitude) *
|
26
27
|
Math.sin(to_latitude) +
|
27
28
|
|
28
|
-
Math.cos(from_latitude) *
|
29
|
+
Math.cos(from_latitude) *
|
29
30
|
Math.cos(to_latitude) *
|
30
31
|
Math.cos(to_longitude - from_longitude)
|
31
32
|
) * EARTH_RADIUS[units.to_sym]
|
@@ -46,7 +47,7 @@ module Graticule
|
|
46
47
|
) * #{Graticule::Distance::EARTH_RADIUS[options[:units].to_sym]})
|
47
48
|
}.gsub("\n", '').squeeze(" ")
|
48
49
|
end
|
49
|
-
|
50
|
+
|
50
51
|
end
|
51
52
|
end
|
52
|
-
end
|
53
|
+
end
|
data/lib/graticule/geocoder.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
require 'happymapper'
|
2
3
|
|
3
4
|
module Graticule
|
4
|
-
|
5
|
+
|
5
6
|
# Get a geocoder for the given service
|
6
7
|
#
|
7
8
|
# geocoder = Graticule.service(:google).new "api_key"
|
@@ -11,7 +12,7 @@ module Graticule
|
|
11
12
|
def self.service(name)
|
12
13
|
Geocoder.const_get name.to_s.camelize
|
13
14
|
end
|
14
|
-
|
15
|
+
|
15
16
|
# Base error class
|
16
17
|
class Error < RuntimeError; end
|
17
18
|
class CredentialsError < Error; end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
require 'open-uri'
|
2
3
|
|
3
4
|
module Graticule #:nodoc:
|
@@ -22,7 +23,7 @@ module Graticule #:nodoc:
|
|
22
23
|
# perform URL customization, override +make_url+.
|
23
24
|
#
|
24
25
|
# class FakeGeocoder < Base
|
25
|
-
#
|
26
|
+
#
|
26
27
|
# def initialize(appid)
|
27
28
|
# @appid = appid
|
28
29
|
# @url = URI.parse 'http://example.com/test'
|
@@ -31,22 +32,22 @@ module Graticule #:nodoc:
|
|
31
32
|
# def locate(query)
|
32
33
|
# get :q => query
|
33
34
|
# end
|
34
|
-
#
|
35
|
+
#
|
35
36
|
# private
|
36
|
-
#
|
37
|
+
#
|
37
38
|
# def check_error(xml)
|
38
39
|
# raise Error, xml.elements['error'].text if xml.elements['error']
|
39
40
|
# end
|
40
|
-
#
|
41
|
+
#
|
41
42
|
# def make_url(params)
|
42
43
|
# params[:appid] = @appid
|
43
44
|
# super params
|
44
45
|
# end
|
45
|
-
#
|
46
|
+
#
|
46
47
|
# def parse_response(response)
|
47
48
|
# # return Location
|
48
49
|
# end
|
49
|
-
#
|
50
|
+
#
|
50
51
|
# end
|
51
52
|
#
|
52
53
|
class Base
|
@@ -55,9 +56,9 @@ module Graticule #:nodoc:
|
|
55
56
|
def initialize
|
56
57
|
raise NotImplementedError
|
57
58
|
end
|
58
|
-
|
59
|
+
|
59
60
|
private
|
60
|
-
|
61
|
+
|
61
62
|
def location_from_params(params)
|
62
63
|
case params
|
63
64
|
when Location then params
|
@@ -95,7 +96,7 @@ module Graticule #:nodoc:
|
|
95
96
|
url.query = escaped_params.join '&'
|
96
97
|
return url
|
97
98
|
end
|
98
|
-
|
99
|
+
|
99
100
|
# Override to convert the response to something besides a String, which
|
100
101
|
# will get passed to +check_error+ and +parse_response+.
|
101
102
|
def prepare_response(response)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule #:nodoc:
|
2
3
|
module Geocoder #:nodoc:
|
3
4
|
# Bogus geocoder that can be used for test purposes
|
@@ -5,10 +6,10 @@ module Graticule #:nodoc:
|
|
5
6
|
# A queue of canned responses
|
6
7
|
class_attribute :responses
|
7
8
|
self.responses = []
|
8
|
-
|
9
|
+
|
9
10
|
# A default location to use if the responses queue is empty
|
10
|
-
|
11
|
-
|
11
|
+
class_attribute :default
|
12
|
+
|
12
13
|
def locate(address)
|
13
14
|
responses.shift || default || Location.new(:street => address)
|
14
15
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule #:nodoc:
|
2
3
|
module Geocoder #:nodoc:
|
3
|
-
|
4
|
+
|
4
5
|
# freethepostcode.org (http://www.freethepostcode.org/) is a
|
5
6
|
# free service to convert UK postcodes into geolocation data.
|
6
7
|
#
|
@@ -17,13 +18,13 @@ module Graticule #:nodoc:
|
|
17
18
|
def locate(postcode)
|
18
19
|
get :postcode => postcode
|
19
20
|
end
|
20
|
-
|
21
|
+
|
21
22
|
private
|
22
23
|
|
23
24
|
def prepare_response(response)
|
24
25
|
response.split("\n")[1]
|
25
26
|
end
|
26
|
-
|
27
|
+
|
27
28
|
def parse_response(response)
|
28
29
|
data = response.split
|
29
30
|
Location.new(:latitude => data[0].to_f, :longitude => data[1].to_f, :precision => :unknown)
|
@@ -32,7 +33,7 @@ module Graticule #:nodoc:
|
|
32
33
|
def check_error(response)
|
33
34
|
raise AddressError, 'unknown address' if response.blank?
|
34
35
|
end
|
35
|
-
|
36
|
+
|
36
37
|
end
|
37
38
|
end
|
38
39
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule #:nodoc:
|
2
3
|
module Geocoder #:nodoc:
|
3
4
|
|
@@ -12,9 +13,9 @@ module Graticule #:nodoc:
|
|
12
13
|
def locate(address)
|
13
14
|
get :locate => address.is_a?(String) ? address : location_from_params(address).to_s(:country => false)
|
14
15
|
end
|
15
|
-
|
16
|
+
|
16
17
|
private
|
17
|
-
|
18
|
+
|
18
19
|
class Response
|
19
20
|
include HappyMapper
|
20
21
|
tag 'geodata'
|
@@ -25,25 +26,25 @@ module Graticule #:nodoc:
|
|
25
26
|
element :locality, String, :deep => true, :tag => 'city'
|
26
27
|
element :postal_code, String, :tag => 'postal'
|
27
28
|
element :region, String, :deep => true, :tag => 'prov'
|
28
|
-
|
29
|
+
|
29
30
|
class Error
|
30
31
|
include HappyMapper
|
31
32
|
tag 'error'
|
32
33
|
element :code, Integer
|
33
34
|
element :description, String
|
34
35
|
end
|
35
|
-
|
36
|
+
|
36
37
|
has_one :error, Error
|
37
|
-
|
38
|
+
|
38
39
|
def street
|
39
40
|
[street_number, street_name].join(' ')
|
40
41
|
end
|
41
42
|
end
|
42
|
-
|
43
|
+
|
43
44
|
def prepare_response(xml)
|
44
45
|
Response.parse(xml, :single => true)
|
45
46
|
end
|
46
|
-
|
47
|
+
|
47
48
|
def parse_response(response) #:nodoc:
|
48
49
|
Location.new(
|
49
50
|
:latitude => response.latitude,
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule #:nodoc:
|
2
3
|
module Geocoder #:nodoc:
|
3
4
|
|
@@ -27,13 +28,13 @@ module Graticule #:nodoc:
|
|
27
28
|
def locate(address)
|
28
29
|
get :address => address.is_a?(String) ? address : location_from_params(address).to_s(:country => false)
|
29
30
|
end
|
30
|
-
|
31
|
+
|
31
32
|
private
|
32
33
|
class Point
|
33
34
|
include HappyMapper
|
34
35
|
tag 'Point'
|
35
36
|
namespace 'http://www.w3.org/2003/01/geo/wgs84_pos#'
|
36
|
-
|
37
|
+
|
37
38
|
element :description, String, :namespace => 'http://purl.org/dc/elements/1.1/'
|
38
39
|
element :longitude, Float, :tag => 'long'
|
39
40
|
element :latitude, Float, :tag => 'lat'
|
@@ -1,30 +1,31 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule #:nodoc:
|
2
3
|
module Geocoder #:nodoc:
|
3
4
|
class Geonames < Base
|
4
|
-
|
5
|
+
|
5
6
|
def initialize
|
6
7
|
@url = URI.parse 'http://ws.geonames.org/timezone'
|
7
8
|
end
|
8
|
-
|
9
|
+
|
9
10
|
def time_zone(location)
|
10
|
-
get :formatted => 'true', :style => 'full', :lat => location.latitude, :lng => location.longitude
|
11
|
+
get :formatted => 'true', :style => 'full', :lat => location.latitude, :lng => location.longitude
|
11
12
|
end
|
12
|
-
|
13
|
-
private
|
13
|
+
|
14
|
+
private
|
14
15
|
class Status
|
15
16
|
include HappyMapper
|
16
17
|
tag 'status'
|
17
18
|
attribute :message, String
|
18
19
|
attribute :value, String
|
19
20
|
end
|
20
|
-
|
21
|
+
|
21
22
|
class Response
|
22
23
|
include HappyMapper
|
23
24
|
tag 'geonames'
|
24
25
|
element :timezoneId, String, :deep => true
|
25
26
|
has_one :status, Status
|
26
27
|
end
|
27
|
-
|
28
|
+
|
28
29
|
def prepare_response(xml)
|
29
30
|
Response.parse(xml, :single => true)
|
30
31
|
end
|
@@ -32,7 +33,7 @@ module Graticule #:nodoc:
|
|
32
33
|
def parse_response(response) #:nodoc:
|
33
34
|
response.timezoneId
|
34
35
|
end
|
35
|
-
|
36
|
+
|
36
37
|
# Extracts and raises an error from +xml+, if any.
|
37
38
|
def check_error(response) #:nodoc:
|
38
39
|
if response && response.status
|
@@ -1,9 +1,10 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule #:nodoc:
|
2
3
|
module Geocoder #:nodoc:
|
3
|
-
|
4
|
+
|
4
5
|
# First you need a Google Maps API key. You can register for one here:
|
5
6
|
# http://www.google.com/apis/maps/signup.html
|
6
|
-
#
|
7
|
+
#
|
7
8
|
# gg = Graticule.service(:google).new(MAPS_API_KEY)
|
8
9
|
# location = gg.locate '1600 Amphitheater Pkwy, Mountain View, CA'
|
9
10
|
# p location.coordinates
|
@@ -11,7 +12,7 @@ module Graticule #:nodoc:
|
|
11
12
|
#
|
12
13
|
class Google < Base
|
13
14
|
# http://www.google.com/apis/maps/documentation/#Geocoding_HTTP_Request
|
14
|
-
|
15
|
+
|
15
16
|
# http://www.google.com/apis/maps/documentation/reference.html#GGeoAddressAccuracy
|
16
17
|
PRECISION = {
|
17
18
|
0 => Precision::Unknown, # Unknown location.
|
@@ -44,15 +45,15 @@ module Graticule #:nodoc:
|
|
44
45
|
|
45
46
|
attribute :accuracy, Integer, :tag => 'Accuracy'
|
46
47
|
end
|
47
|
-
|
48
|
+
|
48
49
|
class Placemark
|
49
50
|
include HappyMapper
|
50
51
|
tag 'Placemark'
|
51
52
|
element :coordinates, String, :deep => true
|
52
53
|
has_one :address, Address
|
53
|
-
|
54
|
+
|
54
55
|
attr_reader :longitude, :latitude
|
55
|
-
|
56
|
+
|
56
57
|
with_options :deep => true, :namespace => 'urn:oasis:names:tc:ciq:xsdschema:xAL:2.0' do |map|
|
57
58
|
map.element :street, String, :tag => 'ThoroughfareName'
|
58
59
|
map.element :locality, String, :tag => 'LocalityName'
|
@@ -60,27 +61,27 @@ module Graticule #:nodoc:
|
|
60
61
|
map.element :postal_code, String, :tag => 'PostalCodeNumber'
|
61
62
|
map.element :country, String, :tag => 'CountryNameCode'
|
62
63
|
end
|
63
|
-
|
64
|
+
|
64
65
|
def coordinates=(coordinates)
|
65
66
|
@longitude, @latitude, _ = coordinates.split(',').map { |v| v.to_f }
|
66
67
|
end
|
67
|
-
|
68
|
+
|
68
69
|
def accuracy
|
69
70
|
address.accuracy if address
|
70
71
|
end
|
71
|
-
|
72
|
+
|
72
73
|
def precision
|
73
74
|
PRECISION[accuracy] || :unknown
|
74
75
|
end
|
75
76
|
end
|
76
|
-
|
77
|
+
|
77
78
|
class Response
|
78
79
|
include HappyMapper
|
79
80
|
tag 'Response'
|
80
81
|
element :code, Integer, :tag => 'code', :deep => true
|
81
82
|
has_many :placemarks, Placemark
|
82
83
|
end
|
83
|
-
|
84
|
+
|
84
85
|
def prepare_response(xml)
|
85
86
|
Response.parse(xml, :single => true)
|
86
87
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
require 'yaml'
|
2
3
|
|
3
4
|
module Graticule #:nodoc:
|
@@ -13,14 +14,14 @@ module Graticule #:nodoc:
|
|
13
14
|
def locate(address)
|
14
15
|
get :ip => address, :position => true
|
15
16
|
end
|
16
|
-
|
17
|
+
|
17
18
|
private
|
18
|
-
|
19
|
+
|
19
20
|
def prepare_response(response)
|
20
21
|
# add new line so YAML.load doesn't puke
|
21
22
|
YAML.load(response + "\n")
|
22
23
|
end
|
23
|
-
|
24
|
+
|
24
25
|
def parse_response(response) #:nodoc:
|
25
26
|
Location.new.tap do |location|
|
26
27
|
location.latitude = response['Latitude']
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule #:nodoc:
|
2
3
|
module Geocoder #:nodoc:
|
3
4
|
|
@@ -5,20 +6,20 @@ module Graticule #:nodoc:
|
|
5
6
|
#
|
6
7
|
# See http://emad.fano.us/blog/?p=277
|
7
8
|
class LocalSearchMaps < Base
|
8
|
-
|
9
|
+
|
9
10
|
def initialize
|
10
11
|
@url = URI.parse 'http://geo.localsearchmaps.com/'
|
11
12
|
end
|
12
|
-
|
13
|
+
|
13
14
|
# This web service will handle some addresses outside the US
|
14
15
|
# if given more structured arguments than just a string address
|
15
16
|
# So allow input as a hash for the different arguments (:city, :country, :zip)
|
16
17
|
def locate(params)
|
17
18
|
get params.is_a?(String) ? {:loc => params} : map_attributes(location_from_params(params))
|
18
19
|
end
|
19
|
-
|
20
|
+
|
20
21
|
private
|
21
|
-
|
22
|
+
|
22
23
|
def map_attributes(location)
|
23
24
|
mapping = {:street => :street, :locality => :city, :region => :state, :postal_code => :zip, :country => :country}
|
24
25
|
mapping.keys.inject({}) do |result,attribute|
|
@@ -26,7 +27,7 @@ module Graticule #:nodoc:
|
|
26
27
|
result
|
27
28
|
end
|
28
29
|
end
|
29
|
-
|
30
|
+
|
30
31
|
def check_error(js)
|
31
32
|
case js
|
32
33
|
when nil
|
@@ -35,12 +36,12 @@ module Graticule #:nodoc:
|
|
35
36
|
raise AddressError, 'Location not found'
|
36
37
|
end
|
37
38
|
end
|
38
|
-
|
39
|
+
|
39
40
|
def parse_response(js)
|
40
41
|
coordinates = js.match(/map.centerAndZoom\(new GPoint\((.+?), (.+?)\)/)
|
41
42
|
Location.new(:longitude => coordinates[1].to_f, :latitude => coordinates[2].to_f)
|
42
43
|
end
|
43
|
-
|
44
|
+
|
44
45
|
end
|
45
46
|
end
|
46
47
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule #:nodoc:
|
2
3
|
module Geocoder #:nodoc:
|
3
4
|
|
@@ -6,10 +7,10 @@ module Graticule #:nodoc:
|
|
6
7
|
# http://developer.mapquest.com/Home/Register?_devAPISignup_WAR_devAPISignup_action=signup&_devAPISignup_WAR_devAPISignup_clientType=Developer
|
7
8
|
#
|
8
9
|
# mq = Graticule.service(:mapquest).new(CLIENT_ID, PASSWORD)
|
9
|
-
# location = gg.locate('44 Allen Rd., Lovell, ME 04051')
|
10
|
+
# location = gg.locate('44 Allen Rd., Lovell, ME 04051')
|
10
11
|
# [42.78942, -86.104424]
|
11
12
|
#
|
12
|
-
class Mapquest < Base
|
13
|
+
class Mapquest < Base
|
13
14
|
# I would link to the documentation here, but there is none that will do anything but confuse you.
|
14
15
|
|
15
16
|
PRECISION = {
|
@@ -48,7 +49,7 @@ module Graticule #:nodoc:
|
|
48
49
|
url.query = URI.escape(query)
|
49
50
|
url
|
50
51
|
end
|
51
|
-
|
52
|
+
|
52
53
|
class Address
|
53
54
|
include HappyMapper
|
54
55
|
tag 'GeoAddress'
|
@@ -60,18 +61,18 @@ module Graticule #:nodoc:
|
|
60
61
|
element :postal_code, String, :tag => 'PostalCode'
|
61
62
|
element :country, String, :tag => 'AdminArea1'
|
62
63
|
element :result_code, String, :tag => 'ResultCode'
|
63
|
-
|
64
|
+
|
64
65
|
def precision
|
65
66
|
PRECISION[result_code.to_s[0,2]] || :unknown
|
66
67
|
end
|
67
68
|
end
|
68
|
-
|
69
|
+
|
69
70
|
class Result
|
70
71
|
include HappyMapper
|
71
72
|
tag 'GeocodeResponse'
|
72
73
|
has_many :addresses, Address, :deep => true
|
73
74
|
end
|
74
|
-
|
75
|
+
|
75
76
|
def prepare_response(xml)
|
76
77
|
Result.parse(xml, :single => true)
|
77
78
|
end
|
@@ -1,9 +1,10 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
require 'timeout'
|
2
3
|
|
3
4
|
module Graticule #:nodoc:
|
4
5
|
module Geocoder #:nodoc:
|
5
6
|
class Multi
|
6
|
-
|
7
|
+
|
7
8
|
# The Multi geocoder allows you to use multiple geocoders in succession.
|
8
9
|
#
|
9
10
|
# geocoder = Graticule.service(:multi).new(
|
@@ -30,10 +31,10 @@ module Graticule #:nodoc:
|
|
30
31
|
#
|
31
32
|
def initialize(*geocoders, &acceptable)
|
32
33
|
@options = {:timeout => 10, :async => false}.merge(geocoders.extract_options!)
|
33
|
-
@acceptable = acceptable ||
|
34
|
-
@geocoders = geocoders
|
34
|
+
@acceptable = acceptable || Proc.new { true }
|
35
|
+
@geocoders = geocoders
|
35
36
|
end
|
36
|
-
|
37
|
+
|
37
38
|
def locate(address)
|
38
39
|
@lookup = @options[:async] ? ParallelLookup.new : SerialLookup.new
|
39
40
|
last_error = nil
|
@@ -53,16 +54,16 @@ module Graticule #:nodoc:
|
|
53
54
|
end
|
54
55
|
@lookup.result || raise(last_error || AddressError.new("Couldn't find '#{address}' with any of the services"))
|
55
56
|
end
|
56
|
-
|
57
|
+
|
57
58
|
class SerialLookup #:nodoc:
|
58
59
|
def initialize
|
59
60
|
@blocks = []
|
60
61
|
end
|
61
|
-
|
62
|
+
|
62
63
|
def perform(&block)
|
63
64
|
@blocks << block
|
64
65
|
end
|
65
|
-
|
66
|
+
|
66
67
|
def result
|
67
68
|
result = nil
|
68
69
|
@blocks.detect do |block|
|
@@ -71,19 +72,19 @@ module Graticule #:nodoc:
|
|
71
72
|
result
|
72
73
|
end
|
73
74
|
end
|
74
|
-
|
75
|
+
|
75
76
|
class ParallelLookup #:nodoc:
|
76
77
|
def initialize
|
77
78
|
@threads = []
|
78
79
|
@monitor = Monitor.new
|
79
80
|
end
|
80
|
-
|
81
|
+
|
81
82
|
def perform(&block)
|
82
83
|
@threads << Thread.new do
|
83
84
|
self.result = block.call
|
84
85
|
end
|
85
86
|
end
|
86
|
-
|
87
|
+
|
87
88
|
def result=(result)
|
88
89
|
if result
|
89
90
|
@monitor.synchronize do
|
@@ -92,7 +93,7 @@ module Graticule #:nodoc:
|
|
92
93
|
end
|
93
94
|
end
|
94
95
|
end
|
95
|
-
|
96
|
+
|
96
97
|
def result
|
97
98
|
@threads.each(&:join)
|
98
99
|
@result
|
@@ -1,14 +1,15 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule #:nodoc:
|
2
3
|
module Geocoder #:nodoc:
|
3
4
|
|
4
5
|
# Multimap geocoding API
|
5
|
-
|
6
|
+
|
6
7
|
class Multimap < Base
|
7
|
-
|
8
|
+
|
8
9
|
# This precision information is not complete.
|
9
10
|
# More details should be implemented from:
|
10
11
|
# http://www.multimap.com/share/documentation/clientzone/gqcodes.htm
|
11
|
-
|
12
|
+
|
12
13
|
PRECISION = {
|
13
14
|
6 => Precision::Country,
|
14
15
|
5 => Precision::Region,
|
@@ -17,39 +18,39 @@ module Graticule #:nodoc:
|
|
17
18
|
2 => Precision::Street,
|
18
19
|
1 => Precision::Address
|
19
20
|
}
|
20
|
-
|
21
|
+
|
21
22
|
# Web services initializer.
|
22
23
|
#
|
23
24
|
# The +api_key+ is the Open API key that uniquely identifies your
|
24
25
|
# application.
|
25
26
|
#
|
26
27
|
# See http://www.multimap.com/openapi/
|
27
|
-
|
28
|
+
|
28
29
|
def initialize(api_key)
|
29
30
|
@api_key = api_key
|
30
31
|
@url = URI.parse "http://clients.multimap.com/API/geocode/1.2/#{@api_key}"
|
31
32
|
end
|
32
|
-
|
33
|
+
|
33
34
|
# Returns a location for an address in the form of a String, Hash or Location.
|
34
|
-
|
35
|
+
|
35
36
|
def locate(address)
|
36
37
|
location = address.is_a?(String) ? address : location_from_params(address)
|
37
38
|
case location
|
38
39
|
when String
|
39
40
|
get :qs => location
|
40
41
|
when Location
|
41
|
-
get "street" => location.street,
|
42
|
-
"region" => location.region,
|
43
|
-
"city" => location.locality,
|
44
|
-
"postalCode" => location.postal_code,
|
42
|
+
get "street" => location.street,
|
43
|
+
"region" => location.region,
|
44
|
+
"city" => location.locality,
|
45
|
+
"postalCode" => location.postal_code,
|
45
46
|
"countryCode" => location.country
|
46
47
|
end
|
47
48
|
end
|
48
|
-
|
49
|
+
|
49
50
|
class Address
|
50
51
|
include HappyMapper
|
51
52
|
tag 'Location'
|
52
|
-
|
53
|
+
|
53
54
|
attribute :quality, Integer, :tag => 'geocodeQuality'
|
54
55
|
element :street, String, :tag => 'Street', :deep => true
|
55
56
|
element :locality, String, :tag => 'Area', :deep => true
|
@@ -58,23 +59,23 @@ module Graticule #:nodoc:
|
|
58
59
|
element :country, String, :tag => 'CountryCode', :deep => true
|
59
60
|
element :latitude, Float, :tag => 'Lat', :deep => true
|
60
61
|
element :longitude, Float, :tag => 'Lon', :deep => true
|
61
|
-
|
62
|
+
|
62
63
|
def precision
|
63
64
|
PRECISION[quality] || :unknown
|
64
65
|
end
|
65
66
|
end
|
66
|
-
|
67
|
+
|
67
68
|
class Result
|
68
69
|
include HappyMapper
|
69
70
|
tag 'Results'
|
70
71
|
attribute :error, String, :tag => 'errorCode'
|
71
72
|
has_many :addresses, Address
|
72
73
|
end
|
73
|
-
|
74
|
+
|
74
75
|
def prepare_response(xml)
|
75
76
|
Result.parse(xml, :single => true)
|
76
77
|
end
|
77
|
-
|
78
|
+
|
78
79
|
def parse_response(result)
|
79
80
|
addr = result.addresses.first
|
80
81
|
Location.new(
|
@@ -88,11 +89,11 @@ module Graticule #:nodoc:
|
|
88
89
|
:precision => addr.precision
|
89
90
|
)
|
90
91
|
end
|
91
|
-
|
92
|
+
|
92
93
|
def check_error(result)
|
93
94
|
raise Error, result.error unless result.error.blank?
|
94
95
|
end
|
95
|
-
|
96
|
+
|
96
97
|
end
|
97
98
|
end
|
98
99
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule #:nodoc:
|
2
3
|
module Geocoder #:nodoc:
|
3
|
-
|
4
|
+
|
4
5
|
# Yahoo geocoding API.
|
5
6
|
#
|
6
7
|
# http://developer.yahoo.com/maps/rest/V1/geocode.html
|
@@ -42,13 +43,13 @@ module Graticule #:nodoc:
|
|
42
43
|
# yahoo pukes on line breaks
|
43
44
|
get :location => location.gsub("\n", ', ')
|
44
45
|
end
|
45
|
-
|
46
|
+
|
46
47
|
private
|
47
|
-
|
48
|
+
|
48
49
|
class Address
|
49
50
|
include HappyMapper
|
50
51
|
tag 'Result'
|
51
|
-
|
52
|
+
|
52
53
|
attribute :precision, String
|
53
54
|
attribute :warning, String
|
54
55
|
element :latitude, Float, :tag => 'Latitude'
|
@@ -58,24 +59,24 @@ module Graticule #:nodoc:
|
|
58
59
|
element :region, String, :tag => 'State'
|
59
60
|
element :postal_code, String, :tag => 'Zip'
|
60
61
|
element :country, String, :tag => 'Country'
|
61
|
-
|
62
|
+
|
62
63
|
def precision
|
63
64
|
PRECISION[@precision] || :unknown
|
64
65
|
end
|
65
66
|
end
|
66
|
-
|
67
|
+
|
67
68
|
class Result
|
68
69
|
include HappyMapper
|
69
70
|
tag 'ResultSet'
|
70
71
|
has_many :addresses, Address
|
71
72
|
end
|
72
|
-
|
73
|
+
|
73
74
|
class Error
|
74
75
|
include HappyMapper
|
75
76
|
tag 'Error'
|
76
77
|
element :message, String, :tag => 'Message'
|
77
78
|
end
|
78
|
-
|
79
|
+
|
79
80
|
def parse_response(response) # :nodoc:
|
80
81
|
addr = Result.parse(response, :single => true).addresses.first
|
81
82
|
Location.new(
|
@@ -108,6 +109,6 @@ module Graticule #:nodoc:
|
|
108
109
|
end
|
109
110
|
|
110
111
|
end
|
111
|
-
|
112
|
+
|
112
113
|
end
|
113
114
|
end
|
data/lib/graticule/location.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule
|
2
3
|
|
3
4
|
# A geographic location
|
@@ -9,7 +10,7 @@ module Graticule
|
|
9
10
|
|
10
11
|
def initialize(attrs = {})
|
11
12
|
attrs.each do |key,value|
|
12
|
-
self.send("#{key}=", value)
|
13
|
+
self.send("#{key}=", value.respond_to?(:force_encoding) ? value.force_encoding('UTF-8') : value)
|
13
14
|
end
|
14
15
|
self.precision ||= :unknown
|
15
16
|
end
|
data/lib/graticule/precision.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Graticule
|
2
|
-
|
3
|
+
|
3
4
|
# Used to compare the precision of different geocoded locations
|
4
5
|
class Precision
|
5
6
|
include Comparable
|
6
7
|
attr_reader :name
|
7
|
-
|
8
|
+
|
8
9
|
NAMES = [
|
9
10
|
:unknown,
|
10
11
|
:country,
|
@@ -15,12 +16,12 @@ module Graticule
|
|
15
16
|
:address,
|
16
17
|
:premise
|
17
18
|
]
|
18
|
-
|
19
|
+
|
19
20
|
def initialize(name)
|
20
21
|
@name = name.to_sym
|
21
22
|
raise ArgumentError, "#{name} is not a valid precision. Use one of #{NAMES.inspect}" unless NAMES.include?(@name)
|
22
23
|
end
|
23
|
-
|
24
|
+
|
24
25
|
Unknown = Precision.new(:unknown)
|
25
26
|
Country = Precision.new(:country)
|
26
27
|
Region = Precision.new(:region)
|
@@ -29,16 +30,16 @@ module Graticule
|
|
29
30
|
Street = Precision.new(:street)
|
30
31
|
Address = Precision.new(:address)
|
31
32
|
Premise = Precision.new(:premise)
|
32
|
-
|
33
|
+
|
33
34
|
def to_s
|
34
35
|
@name.to_s
|
35
36
|
end
|
36
|
-
|
37
|
+
|
37
38
|
def <=>(other)
|
38
39
|
other = Precision.new(other) unless other.is_a?(Precision)
|
39
40
|
NAMES.index(self.name) <=> NAMES.index(other.name)
|
40
41
|
end
|
41
|
-
|
42
|
+
|
42
43
|
def ==(other)
|
43
44
|
(self <=> other) == 0
|
44
45
|
end
|
data/lib/graticule/version.rb
CHANGED
metadata
CHANGED
@@ -1,119 +1,92 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: graticule
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 2
|
8
|
-
- 0
|
9
|
-
- 1
|
10
|
-
version: 2.0.1
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.1.0
|
5
|
+
prerelease:
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Brandon Keepers
|
14
9
|
- Daniel Morrison
|
15
10
|
autorequire:
|
16
11
|
bindir: bin
|
17
12
|
cert_chain: []
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
version_requirements: &id001 !ruby/object:Gem::Requirement
|
13
|
+
date: 2011-08-05 00:00:00.000000000Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activesupport
|
17
|
+
requirement: &70239866982580 !ruby/object:Gem::Requirement
|
24
18
|
none: false
|
25
|
-
requirements:
|
26
|
-
- -
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
segments:
|
30
|
-
- 0
|
31
|
-
version: "0"
|
32
|
-
requirement: *id001
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
33
23
|
type: :runtime
|
34
|
-
name: activesupport
|
35
24
|
prerelease: false
|
36
|
-
|
37
|
-
|
25
|
+
version_requirements: *70239866982580
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: i18n
|
28
|
+
requirement: &70239866981940 !ruby/object:Gem::Requirement
|
38
29
|
none: false
|
39
|
-
requirements:
|
40
|
-
- -
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
|
43
|
-
segments:
|
44
|
-
- 0
|
45
|
-
version: "0"
|
46
|
-
requirement: *id002
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
47
34
|
type: :runtime
|
48
|
-
name: i18n
|
49
35
|
prerelease: false
|
50
|
-
|
51
|
-
|
36
|
+
version_requirements: *70239866981940
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: happymapper
|
39
|
+
requirement: &70239866981260 !ruby/object:Gem::Requirement
|
52
40
|
none: false
|
53
|
-
requirements:
|
54
|
-
- -
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
hash: 19
|
57
|
-
segments:
|
58
|
-
- 0
|
59
|
-
- 3
|
60
|
-
- 0
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
61
44
|
version: 0.3.0
|
62
|
-
requirement: *id003
|
63
45
|
type: :runtime
|
64
|
-
name: happymapper
|
65
46
|
prerelease: false
|
66
|
-
|
67
|
-
|
47
|
+
version_requirements: *70239866981260
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: json
|
50
|
+
requirement: &70239866980440 !ruby/object:Gem::Requirement
|
68
51
|
none: false
|
69
|
-
requirements:
|
70
|
-
- -
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
|
73
|
-
segments:
|
74
|
-
- 0
|
75
|
-
version: "0"
|
76
|
-
requirement: *id004
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
77
56
|
type: :runtime
|
78
|
-
name: json
|
79
57
|
prerelease: false
|
80
|
-
|
81
|
-
|
58
|
+
version_requirements: *70239866980440
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: mocha
|
61
|
+
requirement: &70239866979600 !ruby/object:Gem::Requirement
|
82
62
|
none: false
|
83
|
-
requirements:
|
84
|
-
- -
|
85
|
-
- !ruby/object:Gem::Version
|
86
|
-
|
87
|
-
segments:
|
88
|
-
- 0
|
89
|
-
version: "0"
|
90
|
-
requirement: *id005
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
91
67
|
type: :development
|
92
|
-
name: mocha
|
93
68
|
prerelease: false
|
94
|
-
|
95
|
-
|
69
|
+
version_requirements: *70239866979600
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rcov
|
72
|
+
requirement: &70239866978740 !ruby/object:Gem::Requirement
|
96
73
|
none: false
|
97
|
-
requirements:
|
98
|
-
- -
|
99
|
-
- !ruby/object:Gem::Version
|
100
|
-
|
101
|
-
segments:
|
102
|
-
- 0
|
103
|
-
version: "0"
|
104
|
-
requirement: *id006
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
105
78
|
type: :development
|
106
|
-
name: rcov
|
107
79
|
prerelease: false
|
108
|
-
|
80
|
+
version_requirements: *70239866978740
|
81
|
+
description: Graticule is a geocoding API that provides a common interface to all
|
82
|
+
the popular services, including Google, Yahoo, Geocoder.us, and MetaCarta.
|
109
83
|
email: brandon@opensoul.org
|
110
|
-
executables:
|
84
|
+
executables:
|
111
85
|
- geocode
|
112
86
|
extensions: []
|
113
|
-
|
114
|
-
extra_rdoc_files:
|
87
|
+
extra_rdoc_files:
|
115
88
|
- README.textile
|
116
|
-
files:
|
89
|
+
files:
|
117
90
|
- bin/geocode
|
118
91
|
- lib/graticule/cli.rb
|
119
92
|
- lib/graticule/core_ext.rb
|
@@ -143,42 +116,38 @@ files:
|
|
143
116
|
- CHANGELOG.txt
|
144
117
|
- LICENSE.txt
|
145
118
|
- README.textile
|
146
|
-
has_rdoc: true
|
147
119
|
homepage: http://github.com/collectiveidea/graticule
|
148
120
|
licenses: []
|
149
|
-
|
150
121
|
post_install_message:
|
151
|
-
rdoc_options:
|
122
|
+
rdoc_options:
|
152
123
|
- --main
|
153
124
|
- README.rdoc
|
154
125
|
- --inline-source
|
155
126
|
- --line-numbers
|
156
|
-
require_paths:
|
127
|
+
require_paths:
|
157
128
|
- lib
|
158
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
159
130
|
none: false
|
160
|
-
requirements:
|
161
|
-
- -
|
162
|
-
- !ruby/object:Gem::Version
|
163
|
-
|
164
|
-
segments:
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
segments:
|
165
136
|
- 0
|
166
|
-
|
167
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
hash: -334130965420677482
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
139
|
none: false
|
169
|
-
requirements:
|
170
|
-
- -
|
171
|
-
- !ruby/object:Gem::Version
|
172
|
-
|
173
|
-
segments:
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
segments:
|
174
145
|
- 0
|
175
|
-
|
146
|
+
hash: -334130965420677482
|
176
147
|
requirements: []
|
177
|
-
|
178
148
|
rubyforge_project: graticule
|
179
|
-
rubygems_version: 1.
|
149
|
+
rubygems_version: 1.8.6
|
180
150
|
signing_key:
|
181
151
|
specification_version: 3
|
182
152
|
summary: API for using all the popular geocoding services.
|
183
153
|
test_files: []
|
184
|
-
|