graticule 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +31 -10
- data/lib/graticule.rb +1 -0
- data/lib/graticule/cli.rb +4 -2
- data/lib/graticule/distance/vincenty.rb +12 -13
- data/lib/graticule/geocoder/base.rb +9 -1
- data/lib/graticule/geocoder/mapquest.rb +1 -1
- data/lib/graticule/geocoder/yandex.rb +131 -0
- data/lib/graticule/version.rb +1 -1
- metadata +17 -16
data/README.textile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
h1. Graticule
|
2
2
|
|
3
|
-
Graticule is a geocoding API for looking up address coordinates. It supports many popular APIs, including Yahoo, Google, Geocoder.ca and Geocoder.us.
|
3
|
+
Graticule is a geocoding API for looking up address coordinates. It supports many popular APIs, including Yahoo, Google, Yandex, Geocoder.ca and Geocoder.us.
|
4
4
|
|
5
5
|
h2. Usage
|
6
6
|
|
@@ -28,16 +28,37 @@ h2. Mailing List
|
|
28
28
|
|
29
29
|
Join us on the "mailing list":http://groups.google.com/group/graticule.
|
30
30
|
|
31
|
-
h2.
|
31
|
+
h2. Contributing
|
32
32
|
|
33
|
-
|
33
|
+
In the spirit of "free software":http://www.fsf.org/licensing/essays/free-sw.html, **everyone** is encouraged to help improve this project.
|
34
34
|
|
35
|
-
|
36
|
-
# If you don't see anything, create an issue with information on how to reproduce it.
|
35
|
+
Here are some ways *you* can contribute:
|
37
36
|
|
38
|
-
|
37
|
+
* using alpha, beta, and prerelease versions
|
38
|
+
* reporting bugs
|
39
|
+
* suggesting new features
|
40
|
+
* writing or editing documentation
|
41
|
+
* writing specifications
|
42
|
+
* writing code (**no patch is too small**: fix typos, add comments, clean up inconsistent whitespace)
|
43
|
+
* refactoring code
|
44
|
+
* closing "issues":https://github.com/collectiveidea/graticule/issues
|
45
|
+
* reviewing patches
|
39
46
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
47
|
+
h2. Submitting an Issue
|
48
|
+
|
49
|
+
We use the "GitHub issue tracker":https://github.com/collectiveidea/graticule/issues to track bugs
|
50
|
+
and features. Before submitting a bug report or feature request, check to make sure it hasn't already
|
51
|
+
been submitted. You can indicate support for an existing issuse by voting it up. When submitting a
|
52
|
+
bug report, please include a "Gist":https://gist.github.com/ that includes a stack trace and any
|
53
|
+
details that may be necessary to reproduce the bug, including your gem version, Ruby version, and
|
54
|
+
operating system. Ideally, a bug report should include a pull request with failing specs.
|
55
|
+
|
56
|
+
h2. Submitting a Pull Request
|
57
|
+
|
58
|
+
1. Fork the project.
|
59
|
+
2. Create a topic branch.
|
60
|
+
3. Implement your feature or bug fix.
|
61
|
+
4. Add specs for your feature or bug fix.
|
62
|
+
5. Run @bundle exec rake@. If your changes are not 100% covered and passing, go back to step 4.
|
63
|
+
6. Commit and push your changes.
|
64
|
+
7. Submit a pull request. Please do not include changes to the gemspec, version, or history file. (If you want to create your own version for some reason, please do so in a separate commit.)
|
data/lib/graticule.rb
CHANGED
@@ -12,6 +12,7 @@ require 'graticule/geocoder'
|
|
12
12
|
require 'graticule/geocoder/base'
|
13
13
|
require 'graticule/geocoder/bogus'
|
14
14
|
require 'graticule/geocoder/google'
|
15
|
+
require 'graticule/geocoder/yandex'
|
15
16
|
require 'graticule/geocoder/host_ip'
|
16
17
|
require 'graticule/geocoder/multi'
|
17
18
|
require 'graticule/geocoder/yahoo'
|
data/lib/graticule/cli.rb
CHANGED
@@ -29,11 +29,13 @@ module Graticule
|
|
29
29
|
opts.separator ""
|
30
30
|
opts.separator "Options: "
|
31
31
|
|
32
|
-
opts.on("-s service", %w(yahoo google geocoder_us metacarta), "--service service", "Geocoding service") do |service|
|
32
|
+
opts.on("-s service", %w(yahoo google yandex geocoder_us metacarta), "--service service", "Geocoding service") do |service|
|
33
33
|
options[:service] = service
|
34
34
|
end
|
35
35
|
|
36
|
-
opts.on("-a apikey", "--apikey apikey", "API key for the selected service")
|
36
|
+
opts.on("-a apikey", "--apikey apikey", "API key for the selected service") do |apikey|
|
37
|
+
options[:api_key] = apikey
|
38
|
+
end
|
37
39
|
|
38
40
|
opts.on_tail("-h", "--help", "Help") do
|
39
41
|
puts opts
|
@@ -23,7 +23,7 @@ module Graticule
|
|
23
23
|
from_latitude = from.latitude.to_radians
|
24
24
|
to_longitude = to.longitude.to_radians
|
25
25
|
to_latitude = to.latitude.to_radians
|
26
|
-
|
26
|
+
|
27
27
|
earth_major_axis_radius = EARTH_MAJOR_AXIS_RADIUS[units.to_sym]
|
28
28
|
earth_minor_axis_radius = EARTH_MINOR_AXIS_RADIUS[units.to_sym]
|
29
29
|
|
@@ -43,7 +43,7 @@ module Graticule
|
|
43
43
|
while (lambda-lambda_p).abs > 1e-12 && (iteration_limit -= 1) > 0
|
44
44
|
sin_lambda = sin(lambda)
|
45
45
|
cos_lambda = cos(lambda)
|
46
|
-
sin_sigma = sqrt((cos_u2*sin_lambda) * (cos_u2*sin_lambda) +
|
46
|
+
sin_sigma = sqrt((cos_u2*sin_lambda) * (cos_u2*sin_lambda) +
|
47
47
|
(cos_u1*sin_u2-sin_u1*cos_u2*cos_lambda) * (cos_u1*sin_u2-sin_u1*cos_u2*cos_lambda))
|
48
48
|
return 0 if sin_sigma == 0 # co-incident points
|
49
49
|
cos_sigma = sin_u1*sin_u2 + cos_u1*cos_u2*cos_lambda
|
@@ -58,20 +58,19 @@ module Graticule
|
|
58
58
|
lambda_p = lambda
|
59
59
|
lambda = l + (1-c) * f * sin_alpha *
|
60
60
|
(sigma + c*sin_sigma*(cos2SigmaM+c*cos_sigma*(-1+2*cos2SigmaM*cos2SigmaM)))
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
61
|
+
end
|
62
|
+
# formula failed to converge (happens on antipodal points)
|
63
|
+
# We'll call Haversine formula instead.
|
64
|
+
return Haversine.distance(from, to, units) if iteration_limit == 0
|
65
|
+
|
66
|
+
uSq = cosSqAlpha * (earth_major_axis_radius**2 - earth_minor_axis_radius**2) / (earth_minor_axis_radius**2)
|
67
|
+
a = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)))
|
68
|
+
b = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)))
|
69
|
+
delta_sigma = b*sin_sigma*(cos2SigmaM+b/4*(cos_sigma*(-1+2*cos2SigmaM*cos2SigmaM)-
|
70
|
+
b/6*cos2SigmaM*(-3+4*sin_sigma*sin_sigma)*(-3+4*cos2SigmaM*cos2SigmaM)))
|
65
71
|
|
66
|
-
uSq = cosSqAlpha * (earth_major_axis_radius**2 - earth_minor_axis_radius**2) / (earth_minor_axis_radius**2)
|
67
|
-
a = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)))
|
68
|
-
b = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)))
|
69
|
-
delta_sigma = b*sin_sigma*(cos2SigmaM+b/4*(cos_sigma*(-1+2*cos2SigmaM*cos2SigmaM)-
|
70
|
-
b/6*cos2SigmaM*(-3+4*sin_sigma*sin_sigma)*(-3+4*cos2SigmaM*cos2SigmaM)))
|
71
|
-
|
72
72
|
earth_minor_axis_radius * a * (sigma-delta_sigma)
|
73
73
|
end
|
74
|
-
|
75
74
|
end
|
76
75
|
end
|
77
76
|
end
|
@@ -89,7 +89,7 @@ module Graticule #:nodoc:
|
|
89
89
|
# you need to add extra params like an application id or output type.
|
90
90
|
def make_url(params)
|
91
91
|
escaped_params = params.sort_by { |k,v| k.to_s }.map do |k,v|
|
92
|
-
"#{
|
92
|
+
"#{escape k.to_s}=#{escape v.to_s}"
|
93
93
|
end
|
94
94
|
|
95
95
|
url = @url.dup
|
@@ -108,6 +108,14 @@ module Graticule #:nodoc:
|
|
108
108
|
raise NotImplementedError
|
109
109
|
end
|
110
110
|
|
111
|
+
def escape(string)
|
112
|
+
if URI.const_defined?(:Parser)
|
113
|
+
parser = URI::Parser.new
|
114
|
+
parser.escape string
|
115
|
+
else
|
116
|
+
URI.escape string
|
117
|
+
end
|
118
|
+
end
|
111
119
|
end
|
112
120
|
end
|
113
121
|
end
|
@@ -46,7 +46,7 @@ module Graticule #:nodoc:
|
|
46
46
|
query = "e=5&<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><Geocode Version=\"1\"> \
|
47
47
|
#{address_string(params[:q])}#{authentication_string}</Geocode>"
|
48
48
|
url = @url.dup
|
49
|
-
url.query =
|
49
|
+
url.query = escape(query)
|
50
50
|
url
|
51
51
|
end
|
52
52
|
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module Graticule #:nodoc:
|
3
|
+
module Geocoder #:nodoc:
|
4
|
+
|
5
|
+
# First you need a Yandex Maps API key. You can register for one here:
|
6
|
+
# http://api.yandex.ru/maps/form.xml
|
7
|
+
#
|
8
|
+
# gg = Graticule.service(:yandex).new(MAPS_API_KEY)
|
9
|
+
# location = gg.locate 'Россия, Москва, ул. Моховая, д.18'
|
10
|
+
# p location.coordinates
|
11
|
+
# #=> [37.612281, 55.753342]
|
12
|
+
#
|
13
|
+
class Yandex < Base
|
14
|
+
# http://api.yandex.ru/maps/geocoder/doc/desc/concepts/input_params.xml
|
15
|
+
# http://api.yandex.ru/maps/geocoder/doc/desc/concepts/response_structure.xml
|
16
|
+
|
17
|
+
PRECISION = {
|
18
|
+
:country => Precision::Country, # Country level accuracy.
|
19
|
+
:province => Precision::Region, # Region (state, province, prefecture, etc.) level accuracy.
|
20
|
+
:area => Precision::Region, # Sub-region (county, municipality, etc.) level accuracy.
|
21
|
+
:locality => Precision::Locality, # Town (city, village) level accuracy.
|
22
|
+
:metro => Precision::Street, # Street level accuracy.
|
23
|
+
:street => Precision::Street, # Intersection level accuracy.
|
24
|
+
:house => Precision::Address, # Address level accuracy.
|
25
|
+
}.stringify_keys
|
26
|
+
|
27
|
+
def initialize(key)
|
28
|
+
@key = key
|
29
|
+
@url = URI.parse 'http://geocode-maps.yandex.ru/1.x/'
|
30
|
+
end
|
31
|
+
|
32
|
+
# Locates +address+ returning a Location
|
33
|
+
def locate(address)
|
34
|
+
get :geocode => address.is_a?(String) ? address : location_from_params(address).to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
class GeocoderMetaData
|
40
|
+
include HappyMapper
|
41
|
+
|
42
|
+
tag 'GeocoderMetaData'
|
43
|
+
namespace 'http://maps.yandex.ru/geocoder/1.x'
|
44
|
+
|
45
|
+
element :kind, String, :tag => 'kind'
|
46
|
+
end
|
47
|
+
|
48
|
+
class FeatureMember
|
49
|
+
include HappyMapper
|
50
|
+
|
51
|
+
tag 'featureMember'
|
52
|
+
namespace 'http://www.opengis.net/gml'
|
53
|
+
|
54
|
+
has_one :geocoder_meta_data, GeocoderMetaData
|
55
|
+
|
56
|
+
attr_reader :longitude, :latitude
|
57
|
+
|
58
|
+
element :coordinates, String, :tag => 'pos', :deep => true
|
59
|
+
|
60
|
+
with_options :deep => true, :namespace => 'urn:oasis:names:tc:ciq:xsdschema:xAL:2.0' do |map|
|
61
|
+
map.element :street, String, :tag => 'ThoroughfareName'
|
62
|
+
map.element :locality, String, :tag => 'LocalityName'
|
63
|
+
map.element :region, String, :tag => 'AdministrativeAreaName'
|
64
|
+
map.element :postal_code, String, :tag => 'PostalCodeNumber'
|
65
|
+
map.element :country, String, :tag => 'CountryNameCode'
|
66
|
+
end
|
67
|
+
|
68
|
+
def coordinates=(coordinates)
|
69
|
+
@longitude, @latitude = coordinates.split(' ').map { |v| v.to_f }
|
70
|
+
end
|
71
|
+
|
72
|
+
def precision
|
73
|
+
PRECISION[geocoder_meta_data.kind] || :unknown
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Error
|
78
|
+
include HappyMapper
|
79
|
+
|
80
|
+
tag 'error'
|
81
|
+
element :status, Integer, :tag => 'status'
|
82
|
+
element :message, String, :tag => 'message'
|
83
|
+
end
|
84
|
+
|
85
|
+
class Response
|
86
|
+
include HappyMapper
|
87
|
+
|
88
|
+
tag 'GeoObjectCollection'
|
89
|
+
has_many :feature_members, FeatureMember
|
90
|
+
|
91
|
+
def status
|
92
|
+
200
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def prepare_response(xml)
|
97
|
+
Response.parse(xml, :single => true) || Error.parse(xml, :single => true)
|
98
|
+
end
|
99
|
+
|
100
|
+
def parse_response(response) #:nodoc:
|
101
|
+
result = response.feature_members.first
|
102
|
+
Location.new(
|
103
|
+
:latitude => result.latitude,
|
104
|
+
:longitude => result.longitude,
|
105
|
+
:street => result.street,
|
106
|
+
:locality => result.locality,
|
107
|
+
:country => result.country,
|
108
|
+
:precision => result.precision
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Extracts and raises an error from +xml+, if any.
|
113
|
+
def check_error(response) #:nodoc:
|
114
|
+
case response.status
|
115
|
+
when 200 then # ignore, ok
|
116
|
+
when 401 then
|
117
|
+
raise CredentialsError, response.message
|
118
|
+
else
|
119
|
+
raise Error, response.message
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Creates a URL from the Hash +params+.
|
124
|
+
# sets the output type to 'xml'.
|
125
|
+
def make_url(params) #:nodoc:
|
126
|
+
super params.merge(:key => @key)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
data/lib/graticule/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graticule
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-09-14 00:00:00.000000000Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
17
|
-
requirement: &
|
17
|
+
requirement: &70276838707980 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70276838707980
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: i18n
|
28
|
-
requirement: &
|
28
|
+
requirement: &70276838705640 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70276838705640
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: happymapper
|
39
|
-
requirement: &
|
39
|
+
requirement: &70276838703420 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: 0.3.0
|
45
45
|
type: :runtime
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70276838703420
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: json
|
50
|
-
requirement: &
|
50
|
+
requirement: &70276838701800 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :runtime
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *70276838701800
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: mocha
|
61
|
-
requirement: &
|
61
|
+
requirement: &70276838699580 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ! '>='
|
@@ -66,10 +66,10 @@ dependencies:
|
|
66
66
|
version: '0'
|
67
67
|
type: :development
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *70276838699580
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: rcov
|
72
|
-
requirement: &
|
72
|
+
requirement: &70276838697520 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
75
|
- - ! '>='
|
@@ -77,7 +77,7 @@ dependencies:
|
|
77
77
|
version: '0'
|
78
78
|
type: :development
|
79
79
|
prerelease: false
|
80
|
-
version_requirements: *
|
80
|
+
version_requirements: *70276838697520
|
81
81
|
description: Graticule is a geocoding API that provides a common interface to all
|
82
82
|
the popular services, including Google, Yahoo, Geocoder.us, and MetaCarta.
|
83
83
|
email: brandon@opensoul.org
|
@@ -108,6 +108,7 @@ files:
|
|
108
108
|
- lib/graticule/geocoder/multimap.rb
|
109
109
|
- lib/graticule/geocoder/simple_geo.rb
|
110
110
|
- lib/graticule/geocoder/yahoo.rb
|
111
|
+
- lib/graticule/geocoder/yandex.rb
|
111
112
|
- lib/graticule/geocoder.rb
|
112
113
|
- lib/graticule/location.rb
|
113
114
|
- lib/graticule/precision.rb
|
@@ -134,7 +135,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
134
135
|
version: '0'
|
135
136
|
segments:
|
136
137
|
- 0
|
137
|
-
hash:
|
138
|
+
hash: 473484385783211524
|
138
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
140
|
none: false
|
140
141
|
requirements:
|
@@ -143,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
143
144
|
version: '0'
|
144
145
|
segments:
|
145
146
|
- 0
|
146
|
-
hash:
|
147
|
+
hash: 473484385783211524
|
147
148
|
requirements: []
|
148
149
|
rubyforge_project: graticule
|
149
150
|
rubygems_version: 1.8.6
|