geocoder 0.9.12 → 1.0.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.
@@ -0,0 +1,39 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/yandex"
3
+
4
+ module Geocoder::Lookup
5
+ class Yandex < Base
6
+
7
+ def map_link_url(coordinates)
8
+ "http://maps.yandex.ru/?ll=#{coordinates.reverse.join(',')}"
9
+ end
10
+
11
+ private # ---------------------------------------------------------------
12
+
13
+ def results(query, reverse = false)
14
+ return [] unless doc = fetch_data(query, reverse)
15
+ if err = doc['error']
16
+ warn "Yandex Geocoding API error: #{err['status']} (#{err['message']})."
17
+ return []
18
+ end
19
+ if doc = doc['response']['GeoObjectCollection']
20
+ meta = doc['metaDataProperty']['GeocoderResponseMetaData']
21
+ return meta['found'].to_i > 0 ? doc['featureMember'] : []
22
+ else
23
+ warn "Yandex Geocoding API error: unexpected response format."
24
+ return []
25
+ end
26
+ end
27
+
28
+ def query_url(query, reverse = false)
29
+ query = query.split(",").reverse.join(",") if reverse
30
+ params = {
31
+ :geocode => query,
32
+ :format => "json",
33
+ :plng => "#{Geocoder::Configuration.language}", # supports ru, uk, be
34
+ :key => Geocoder::Configuration.api_key
35
+ }
36
+ "http://geocode-maps.yandex.ru/1.x/?" + hash_to_query(params)
37
+ end
38
+ end
39
+ end
@@ -9,7 +9,11 @@ module Geocoder
9
9
  module Base
10
10
 
11
11
  def geocoder_options
12
- @geocoder_options
12
+ if defined?(@geocoder_options)
13
+ @geocoder_options
14
+ elsif superclass.respond_to?(:geocoder_options)
15
+ superclass.geocoder_options
16
+ end
13
17
  end
14
18
 
15
19
  def geocoded_by
@@ -32,6 +32,22 @@ module Geocoder
32
32
  coordinates[1]
33
33
  end
34
34
 
35
+ def state
36
+ fail
37
+ end
38
+
39
+ def province
40
+ state
41
+ end
42
+
43
+ def state_code
44
+ fail
45
+ end
46
+
47
+ def province_code
48
+ state_code
49
+ end
50
+
35
51
  def country
36
52
  fail
37
53
  end
@@ -0,0 +1,48 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Bing < Base
5
+
6
+ def address(format = :full)
7
+ @data['address']['formattedAddress']
8
+ end
9
+
10
+ def city
11
+ @data['address']['locality']
12
+ end
13
+
14
+ def state_code
15
+ @data['address']['adminDistrict']
16
+ end
17
+
18
+ alias_method :state, :state_code
19
+
20
+ def country
21
+ @data['address']['countryRegion']
22
+ end
23
+
24
+ alias_method :country_code, :country
25
+
26
+ def postal_code
27
+ @data['address']['postalCode']
28
+ end
29
+
30
+ def coordinates
31
+ @data['point']['coordinates']
32
+ end
33
+
34
+ def address_data
35
+ @data['address']
36
+ end
37
+
38
+ def self.response_attributes
39
+ %w[bbox name confidence entityType]
40
+ end
41
+
42
+ response_attributes.each do |a|
43
+ define_method a do
44
+ @data[a]
45
+ end
46
+ end
47
+ end
48
+ end
@@ -4,13 +4,21 @@ module Geocoder::Result
4
4
  class Freegeoip < Base
5
5
 
6
6
  def address(format = :full)
7
- "#{city}#{', ' + region_code unless region_code == ''} #{postal_code}, #{country}"
7
+ "#{city}#{', ' + state_code unless state_code == ''} #{postal_code}, #{country}".sub(/^[ ,]*/, "")
8
8
  end
9
9
 
10
10
  def city
11
11
  @data['city']
12
12
  end
13
13
 
14
+ def state
15
+ @data['region_name']
16
+ end
17
+
18
+ def state_code
19
+ @data['region_code']
20
+ end
21
+
14
22
  def country
15
23
  @data['country_name']
16
24
  end
@@ -24,8 +32,7 @@ module Geocoder::Result
24
32
  end
25
33
 
26
34
  def self.response_attributes
27
- %w[city region_code region_name metrocode
28
- zipcode country_name country_code ip]
35
+ %w[metrocode ip]
29
36
  end
30
37
 
31
38
  response_attributes.each do |a|
@@ -8,7 +8,7 @@ module Geocoder::Result
8
8
  end
9
9
 
10
10
  def address(format = :full)
11
- "#{street_address}, #{city}, #{state} #{postal_code}, #{country}"
11
+ "#{street_address}, #{city}, #{state} #{postal_code}, #{country}".sub(/^[ ,]*/, "")
12
12
  end
13
13
 
14
14
  def street_address
@@ -23,7 +23,7 @@ module Geocoder::Result
23
23
  @data['prov']
24
24
  end
25
25
 
26
- alias_method :province, :state
26
+ alias_method :state_code, :state
27
27
 
28
28
  def postal_code
29
29
  @data['postal']
@@ -34,19 +34,14 @@ module Geocoder::Result
34
34
  end
35
35
 
36
36
  def country_code
37
- prov = @data['prov']
38
- return nil if prov.nil? || prov == ""
39
- canadian_province_abbreviations.include?(@data['prov']) ? "CA" : "US"
40
- end
41
-
42
- def canadian_province_abbreviations
43
- %w[ON QC NS NB MB BC PE SK AB NL]
37
+ return nil if state.nil? || state == ""
38
+ canadian_province_abbreviations.include?(state) ? "CA" : "US"
44
39
  end
45
40
 
46
41
  def self.response_attributes
47
- %w[latt longt inlatt inlongt betweenRoad1 betweenRoad2 distance
48
- stnumber staddress city prov postal
49
- NearRoad NearRoadDistance intersection major_intersection]
42
+ %w[latt longt inlatt inlongt distance stnumber staddress prov
43
+ NearRoad NearRoadDistance betweenRoad1 betweenRoad2
44
+ intersection major_intersection]
50
45
  end
51
46
 
52
47
  response_attributes.each do |a|
@@ -54,5 +49,12 @@ module Geocoder::Result
54
49
  @data[a]
55
50
  end
56
51
  end
52
+
53
+
54
+ private # ----------------------------------------------------------------
55
+
56
+ def canadian_province_abbreviations
57
+ %w[ON QC NS NB MB BC PE SK AB NL]
58
+ end
57
59
  end
58
60
  end
@@ -12,8 +12,9 @@ module Geocoder::Result
12
12
  end
13
13
 
14
14
  def city
15
- fields = [:locality, :sublocality, :administrative_area_level_3,
16
- :administrative_area_level_2, :administrative_area_level_1]
15
+ fields = [:locality, :sublocality,
16
+ :administrative_area_level_3,
17
+ :administrative_area_level_2]
17
18
  fields.each do |f|
18
19
  if entity = address_components_of_type(f).first
19
20
  return entity['long_name']
@@ -21,6 +22,18 @@ module Geocoder::Result
21
22
  end
22
23
  end
23
24
 
25
+ def state
26
+ if state = address_components_of_type(:administrative_area_level_1).first
27
+ state['long_name']
28
+ end
29
+ end
30
+
31
+ def state_code
32
+ if state = address_components_of_type(:administrative_area_level_1).first
33
+ state['short_name']
34
+ end
35
+ end
36
+
24
37
  def country
25
38
  if country = address_components_of_type(:country).first
26
39
  country['long_name']
@@ -11,6 +11,14 @@ module Geocoder::Result
11
11
  @data['city']
12
12
  end
13
13
 
14
+ def state
15
+ @data['state']
16
+ end
17
+
18
+ def state_code
19
+ @data['statecode']
20
+ end
21
+
14
22
  def country
15
23
  @data['country']
16
24
  end
@@ -25,8 +33,8 @@ module Geocoder::Result
25
33
 
26
34
  def self.response_attributes
27
35
  %w[quality offsetlat offsetlon radius boundingbox name
28
- line1 line2 line3 line4 cross house street xstreet unittype unit postal
29
- neighborhood city county state country countrycode statecode countycode
36
+ line1 line2 line3 line4 cross house street xstreet unittype unit
37
+ neighborhood county countycode
30
38
  level0 level1 level2 level3 level4 level0code level1code level2code
31
39
  timezone areacode uzip hash woeid woetype]
32
40
  end
@@ -0,0 +1,48 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Yandex < Base
5
+
6
+ def coordinates
7
+ @data['GeoObject']['Point']['pos'].split(' ').reverse.map(&:to_f)
8
+ end
9
+
10
+ def address(format = :full)
11
+ @data['GeoObject']['metaDataProperty']['GeocoderMetaData']['text']
12
+ end
13
+
14
+ def city
15
+ address_details['Locality']['LocalityName']
16
+ end
17
+
18
+ def country
19
+ address_details['CountryName']
20
+ end
21
+
22
+ def country_code
23
+ address_details['CountryNameCode']
24
+ end
25
+
26
+ def state
27
+ ""
28
+ end
29
+
30
+ def state_code
31
+ ""
32
+ end
33
+
34
+ def postal_code
35
+ ""
36
+ end
37
+
38
+ def premise_name
39
+ address_details['Locality']['Premise']['PremiseName']
40
+ end
41
+
42
+ private # ----------------------------------------------------------------
43
+
44
+ def address_details
45
+ @data['GeoObject']['metaDataProperty']['GeocoderMetaData']['AddressDetails']['Country']
46
+ end
47
+ end
48
+ end
@@ -1,5 +1,4 @@
1
1
  require 'geocoder/stores/base'
2
- require 'geocoder/stores/active_record_legacy'
3
2
 
4
3
  ##
5
4
  # Add geocoding functionality to any ActiveRecord object.
@@ -7,7 +6,6 @@ require 'geocoder/stores/active_record_legacy'
7
6
  module Geocoder::Store
8
7
  module ActiveRecord
9
8
  include Base
10
- include ActiveRecord::Legacy
11
9
 
12
10
  ##
13
11
  # Implementation of 'included' hook method.
@@ -180,9 +178,6 @@ module Geocoder::Store
180
178
  conditions[0] << " AND #{table_name}.id != ?"
181
179
  conditions << obj.id
182
180
  end
183
- if options[:limit] || options[:offset]
184
- warn "DEPRECATION WARNING: The :limit and :offset options to Geocoder's 'near' method are deprecated and will be removed in Geocoder v1.0. Please specify these options using ARel relations instead, for example: Place.near(...).limit(10).offset(20)."
185
- end
186
181
  {
187
182
  :group => columns.map{ |c| "#{table_name}.#{c.name}" }.join(','),
188
183
  :order => options[:order],
@@ -208,7 +203,7 @@ module Geocoder::Store
208
203
  end
209
204
  end
210
205
 
211
- #alias_method :fetch_coordinates, :geocode
206
+ alias_method :fetch_coordinates, :geocode
212
207
 
213
208
  ##
214
209
  # Look up address and assign to +address+ attribute (or other as specified
@@ -224,6 +219,6 @@ module Geocoder::Store
224
219
  end
225
220
  end
226
221
 
227
- #alias_method :fetch_address, :reverse_geocode
222
+ alias_method :fetch_address, :reverse_geocode
228
223
  end
229
224
  end
@@ -22,14 +22,10 @@ module Geocoder
22
22
  # the point. Also takes a symbol specifying the units
23
23
  # (:mi or :km; default is :mi).
24
24
  #
25
- def distance_to(point, *args)
26
- if point.is_a?(Numeric) and args[0].is_a?(Numeric)
27
- warn "DEPRECATION WARNING: Instead of passing latitude/longitude as separate arguments to the distance_to/from method, please pass an array [#{point},#{args[0]}], a geocoded object, or a geocodable address (string). The old argument format will not be supported in Geocoder v.1.0."
28
- point = [point, args.shift]
29
- end
25
+ def distance_to(point, units = :mi)
30
26
  return nil unless geocoded?
31
27
  Geocoder::Calculations.distance_between(
32
- to_coordinates, point, :units => args.pop || :mi)
28
+ to_coordinates, point, :units => units)
33
29
  end
34
30
 
35
31
  alias_method :distance_from, :distance_to
@@ -62,10 +58,6 @@ module Geocoder
62
58
  #
63
59
  def nearbys(radius = 20, options = {})
64
60
  return [] unless geocoded?
65
- if options.is_a?(Symbol)
66
- options = {:units => options}
67
- warn "DEPRECATION WARNING: The units argument to the nearbys method has been replaced with an options hash (same options hash as the near scope). You should instead call: obj.nearbys(#{radius}, :units => #{options[:units]}). The old syntax will not be supported in Geocoder v1.0."
68
- end
69
61
  options.merge!(:exclude => self)
70
62
  self.class.near(self, radius, options)
71
63
  end
@@ -19,11 +19,17 @@ module Geocoder::Store
19
19
  coords = Geocoder::Calculations.extract_coordinates(location)
20
20
  radius = args.size > 0 ? args.shift : 20
21
21
  options = args.size > 0 ? args.shift : {}
22
- conds = {:coordinates => {
23
- "$nearSphere" => coords.reverse,
24
- "$maxDistance" => Geocoder::Calculations.distance_to_radians(
25
- radius, options[:units] || :mi)
26
- }}
22
+
23
+ # Use BSON::OrderedHash if Ruby's hashes are unordered.
24
+ # Conditions must be in order required by indexes (see mongo gem).
25
+ empty = RUBY_VERSION.split('.')[1].to_i < 9 ? BSON::OrderedHash.new : {}
26
+
27
+ conds = empty.clone
28
+ conds[:coordinates] = empty.clone
29
+ conds[:coordinates]["$nearSphere"] = coords.reverse
30
+ conds[:coordinates]["$maxDistance"] = \
31
+ Geocoder::Calculations.distance_to_radians(radius, options[:units] || :mi)
32
+
27
33
  if obj = options[:exclude]
28
34
  conds[:_id.ne] = obj.id
29
35
  end
@@ -0,0 +1,3 @@
1
+ module Geocoder
2
+ VERSION = "1.0.0"
3
+ end
data/lib/geocoder.rb CHANGED
@@ -11,32 +11,8 @@ module Geocoder
11
11
  ##
12
12
  # Search for information about an address or a set of coordinates.
13
13
  #
14
- def search(query, *args)
15
- # convert coordinates as separate arguments to an array
16
- if query.is_a?(Numeric) and args.first.is_a?(Numeric)
17
- warn "DEPRECATION WARNING: Instead of passing latitude/longitude as separate arguments to the search method, please pass an array: [#{query},#{args.first}]. The old argument format will not be supported in Geocoder v.1.0."
18
- query = [query, args.first]
19
- end
20
- if blank_query?(query)
21
- results = []
22
- else
23
- results = lookup(ip_address?(query)).search(query)
24
- end
25
- results.instance_eval do
26
- def warn_search_deprecation(attr)
27
- warn "DEPRECATION WARNING: Geocoder.search now returns an array of Geocoder::Result objects. " +
28
- "Calling '%s' directly on the returned array will cause an exception in Geocoder v1.0." % attr
29
- end
30
-
31
- def coordinates; warn_search_deprecation('coordinates'); first.coordinates if first; end
32
- def latitude; warn_search_deprecation('latitude'); first.latitude if first; end
33
- def longitude; warn_search_deprecation('longitude'); first.longitude if first; end
34
- def address; warn_search_deprecation('address'); first.address if first; end
35
- def city; warn_search_deprecation('city'); first.city if first; end
36
- def country; warn_search_deprecation('country'); first.country if first; end
37
- def country_code; warn_search_deprecation('country_code'); first.country_code if first; end
38
- end
39
- return results
14
+ def search(query)
15
+ blank_query?(query) ? [] : lookup(query).search(query)
40
16
  end
41
17
 
42
18
  ##
@@ -52,11 +28,7 @@ module Geocoder
52
28
  # Look up the address of the given coordinates ([lat,lon])
53
29
  # or IP address (string).
54
30
  #
55
- def address(query, *args)
56
- if lon = args.first
57
- warn "DEPRECATION WARNING: Instead of passing latitude/longitude as separate arguments to the address method, please pass an array: [#{query},#{args.first}]. The old argument format will not be supported in Geocoder v.1.0."
58
- query = [query, lon]
59
- end
31
+ def address(query)
60
32
  if (results = search(query)).size > 0
61
33
  results.first.address
62
34
  end
@@ -72,6 +44,27 @@ module Geocoder
72
44
  @cache
73
45
  end
74
46
 
47
+ ##
48
+ # Array of valid Lookup names.
49
+ #
50
+ def valid_lookups
51
+ street_lookups + ip_lookups
52
+ end
53
+
54
+ ##
55
+ # All street address lookups, default first.
56
+ #
57
+ def street_lookups
58
+ [:google, :yahoo, :bing, :geocoder_ca, :yandex]
59
+ end
60
+
61
+ ##
62
+ # All IP address lookups, default first.
63
+ #
64
+ def ip_lookups
65
+ [:freegeoip]
66
+ end
67
+
75
68
 
76
69
  # exception classes
77
70
  class Error < StandardError; end
@@ -82,13 +75,14 @@ module Geocoder
82
75
 
83
76
  ##
84
77
  # Get a Lookup object (which communicates with the remote geocoding API).
85
- # Returns an IP address lookup if +ip+ parameter true.
78
+ # Takes a search query and returns an IP or street address Lookup
79
+ # depending on the query contents.
86
80
  #
87
- def lookup(ip = false)
88
- if ip
89
- get_lookup :freegeoip
81
+ def lookup(query)
82
+ if ip_address?(query)
83
+ get_lookup(ip_lookups.first)
90
84
  else
91
- get_lookup Configuration.lookup || :google
85
+ get_lookup(Configuration.lookup || street_lookups.first)
92
86
  end
93
87
  end
94
88
 
@@ -121,13 +115,6 @@ module Geocoder
121
115
  end
122
116
  end
123
117
 
124
- ##
125
- # Array of valid Lookup names.
126
- #
127
- def valid_lookups
128
- [:google, :yahoo, :geocoder_ca, :freegeoip]
129
- end
130
-
131
118
  ##
132
119
  # Does the given value look like an IP address?
133
120
  #
@@ -0,0 +1,40 @@
1
+ {
2
+ "authenticationResultCode":"ValidCredentials",
3
+ "brandLogoUri":"http:\/\/dev.virtualearth.net\/Branding\/logo_powered_by.png",
4
+ "copyright":"Copyright © 2011 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
5
+ "resourceSets":[
6
+ {
7
+ "estimatedTotal":1,
8
+ "resources":[
9
+ {
10
+ "__type":"Location:http:\/\/schemas.microsoft.com\/search\/local\/ws\/rest\/v1",
11
+ "bbox":[
12
+ 40.744944289326668,
13
+ -74.002353921532631,
14
+ 40.755675807595253,
15
+ -73.983625397086143
16
+ ],
17
+ "name":"Madison Square Garden, NY",
18
+ "point":{
19
+ "type":"Point",
20
+ "coordinates":[
21
+ 40.75031,
22
+ -73.99299
23
+ ]
24
+ },
25
+ "address":{
26
+ "adminDistrict":"NY",
27
+ "countryRegion":"United States",
28
+ "formattedAddress":"Madison Square Garden, NY",
29
+ "locality":"New York"
30
+ },
31
+ "confidence":"High",
32
+ "entityType":"Stadium"
33
+ }
34
+ ]
35
+ }
36
+ ],
37
+ "statusCode":200,
38
+ "statusDescription":"OK",
39
+ "traceId":"55094ee53c8d45e789794014666328cd|CH1M001466|02.00.82.2800|CH1MSNVM001396, CH1MSNVM001370, CH1MSNVM001397"
40
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "authenticationResultCode":"ValidCredentials",
3
+ "brandLogoUri":"http:\/\/dev.virtualearth.net\/Branding\/logo_powered_by.png",
4
+ "copyright":"Copyright © 2011 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
5
+ "resourceSets":[
6
+ {
7
+ "estimatedTotal":0,
8
+ "resources":[
9
+
10
+ ]
11
+ }
12
+ ],
13
+ "statusCode":200,
14
+ "statusDescription":"OK",
15
+ "traceId":"907b76a307bc49129a489de3d4c992ea|CH1M001463|02.00.82.2800|CH1MSNVM001383, CH1MSNVM001358, CH1MSNVM001397"
16
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ "authenticationResultCode":"ValidCredentials",
3
+ "brandLogoUri":"http:\/\/dev.virtualearth.net\/Branding\/logo_powered_by.png",
4
+ "copyright":"Copyright © 2011 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
5
+ "resourceSets":[
6
+ {
7
+ "estimatedTotal":1,
8
+ "resources":[
9
+ {
10
+ "__type":"Location:http:\/\/schemas.microsoft.com\/search\/local\/ws\/rest\/v1",
11
+ "bbox":[
12
+ 45.419835111675845,
13
+ -75.683656128790716,
14
+ 45.4275605468172,
15
+ -75.66898098334994
16
+ ],
17
+ "name":"291 Rue Somerset E, Ottawa, ON, K1N",
18
+ "point":{
19
+ "type":"Point",
20
+ "coordinates":[
21
+ 45.423697829246521,
22
+ -75.676318556070328
23
+ ]
24
+ },
25
+ "address":{
26
+ "addressLine":"291 Rue Somerset E",
27
+ "adminDistrict":"ON",
28
+ "countryRegion":"Canada",
29
+ "formattedAddress":"291 Rue Somerset E, Ottawa, ON, K1N",
30
+ "locality":"Ottawa",
31
+ "postalCode":"K1N"
32
+ },
33
+ "confidence":"Medium",
34
+ "entityType":"Address"
35
+ }
36
+ ]
37
+ }
38
+ ],
39
+ "statusCode":200,
40
+ "statusDescription":"OK",
41
+ "traceId":"27bd5ed659e64ba6970c4144f1d4ea94|CH1M001470|02.00.82.2800|CH1MSNVM001396, CH1MSNVM001374"
42
+ }
@@ -0,0 +1 @@
1
+ {"error":{"status":401,"message":"invalid key"}}
@@ -0,0 +1,48 @@
1
+ {
2
+ "response": {
3
+ "GeoObjectCollection": {
4
+ "metaDataProperty": {
5
+ "GeocoderResponseMetaData": {
6
+ "request": "Кремль, Moscow, Russia",
7
+ "found": "1",
8
+ "results": "10"
9
+ }
10
+ },
11
+ "featureMember": [
12
+ {
13
+ "GeoObject": {
14
+ "metaDataProperty": {
15
+ "GeocoderMetaData": {
16
+ "kind": "vegetation",
17
+ "text": "Россия, Москва, Московский Кремль",
18
+ "precision": "other",
19
+ "AddressDetails": {
20
+ "Country": {
21
+ "CountryNameCode": "RU",
22
+ "CountryName": "Россия",
23
+ "Locality": {
24
+ "LocalityName": "Москва",
25
+ "Premise": {
26
+ "PremiseName": "Московский Кремль"
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
32
+ },
33
+ "name": "Московский Кремль",
34
+ "boundedBy": {
35
+ "Envelope": {
36
+ "lowerCorner": "37.584182 55.733361",
37
+ "upperCorner": "37.650064 55.770517"
38
+ }
39
+ },
40
+ "Point": {
41
+ "pos": "37.617123 55.751943"
42
+ }
43
+ }
44
+ }
45
+ ]
46
+ }
47
+ }
48
+ }