graticule 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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. How to contribute
31
+ h2. Contributing
32
32
 
33
- If you find what you might think is a bug:
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
- # Check the "GitHub issue tracker":http://github.com/collectiveidea/graticule/issues/ to see if anyone else has had the same issue.
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
- If you want to contribute an enhancement or a fix:
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
- # Fork "the project":http://github.com/collectiveidea/graticule/ on GitHub.
41
- # Make your changes with tests.
42
- # Commit the changes without making changes to the Rakefile, VERSION, or any other files that aren't related to your enhancement or fix
43
- # Send a pull request.
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.)
@@ -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'
@@ -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
- 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
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
- "#{URI.escape k.to_s}=#{URI.escape v.to_s}"
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 = URI.escape(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
+
@@ -1,4 +1,4 @@
1
1
  # encoding: UTF-8
2
2
  module Graticule
3
- VERSION = '2.1.0' unless defined?(::Graticule::VERSION)
3
+ VERSION = '2.2.0' unless defined?(::Graticule::VERSION)
4
4
  end
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.1.0
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-08-05 00:00:00.000000000Z
13
+ date: 2011-09-14 00:00:00.000000000Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
17
- requirement: &70239866982580 !ruby/object:Gem::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: *70239866982580
25
+ version_requirements: *70276838707980
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: i18n
28
- requirement: &70239866981940 !ruby/object:Gem::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: *70239866981940
36
+ version_requirements: *70276838705640
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: happymapper
39
- requirement: &70239866981260 !ruby/object:Gem::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: *70239866981260
47
+ version_requirements: *70276838703420
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: json
50
- requirement: &70239866980440 !ruby/object:Gem::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: *70239866980440
58
+ version_requirements: *70276838701800
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: mocha
61
- requirement: &70239866979600 !ruby/object:Gem::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: *70239866979600
69
+ version_requirements: *70276838699580
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: rcov
72
- requirement: &70239866978740 !ruby/object:Gem::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: *70239866978740
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: -334130965420677482
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: -334130965420677482
147
+ hash: 473484385783211524
147
148
  requirements: []
148
149
  rubyforge_project: graticule
149
150
  rubygems_version: 1.8.6