geocoder 1.1.4 → 1.1.8

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.
Files changed (110) hide show
  1. data/.travis.yml +4 -0
  2. data/{CHANGELOG.rdoc → CHANGELOG.md} +120 -39
  3. data/README.md +200 -54
  4. data/examples/autoexpire_cache_dalli.rb +62 -0
  5. data/examples/{autoexpire_cache.rb → autoexpire_cache_redis.rb} +4 -6
  6. data/lib/generators/geocoder/config/templates/initializer.rb +19 -23
  7. data/lib/geocoder/cache.rb +6 -1
  8. data/lib/geocoder/calculations.rb +45 -13
  9. data/lib/geocoder/cli.rb +10 -11
  10. data/lib/geocoder/configuration.rb +67 -43
  11. data/lib/geocoder/configuration_hash.rb +11 -0
  12. data/lib/geocoder/exceptions.rb +3 -0
  13. data/lib/geocoder/lookup.rb +3 -1
  14. data/lib/geocoder/lookups/base.rb +89 -27
  15. data/lib/geocoder/lookups/bing.rb +21 -11
  16. data/lib/geocoder/lookups/esri.rb +48 -0
  17. data/lib/geocoder/lookups/freegeoip.rb +8 -4
  18. data/lib/geocoder/lookups/geocoder_ca.rb +11 -7
  19. data/lib/geocoder/lookups/google.rb +18 -9
  20. data/lib/geocoder/lookups/google_premier.rb +16 -8
  21. data/lib/geocoder/lookups/mapquest.rb +33 -5
  22. data/lib/geocoder/lookups/maxmind.rb +88 -0
  23. data/lib/geocoder/lookups/nominatim.rb +13 -8
  24. data/lib/geocoder/lookups/ovi.rb +52 -0
  25. data/lib/geocoder/lookups/test.rb +10 -0
  26. data/lib/geocoder/lookups/yahoo.rb +51 -38
  27. data/lib/geocoder/lookups/yandex.rb +17 -9
  28. data/lib/geocoder/models/mongoid.rb +1 -1
  29. data/lib/geocoder/query.rb +20 -5
  30. data/lib/geocoder/request.rb +7 -1
  31. data/lib/geocoder/results/base.rb +8 -2
  32. data/lib/geocoder/results/esri.rb +51 -0
  33. data/lib/geocoder/results/google.rb +34 -0
  34. data/lib/geocoder/results/mapquest.rb +46 -2
  35. data/lib/geocoder/results/maxmind.rb +135 -0
  36. data/lib/geocoder/results/nominatim.rb +0 -10
  37. data/lib/geocoder/results/ovi.rb +62 -0
  38. data/lib/geocoder/results/test.rb +2 -1
  39. data/lib/geocoder/results/yahoo.rb +9 -2
  40. data/lib/geocoder/results/yandex.rb +12 -2
  41. data/lib/geocoder/sql.rb +6 -4
  42. data/lib/geocoder/stores/active_record.rb +57 -30
  43. data/lib/geocoder/stores/base.rb +3 -2
  44. data/lib/geocoder/stores/mongo_base.rb +2 -1
  45. data/lib/geocoder/version.rb +1 -1
  46. data/lib/geocoder.rb +2 -4
  47. data/lib/hash_recursive_merge.rb +74 -0
  48. data/lib/oauth_util.rb +112 -0
  49. data/test/cache_test.rb +19 -0
  50. data/test/calculations_test.rb +10 -4
  51. data/test/configuration_test.rb +26 -51
  52. data/test/error_handling_test.rb +8 -4
  53. data/test/fixtures/bing_invalid_key +1 -0
  54. data/test/fixtures/esri_madison_square_garden +59 -0
  55. data/test/fixtures/esri_no_results +8 -0
  56. data/test/fixtures/esri_reverse +21 -0
  57. data/test/fixtures/mapquest_madison_square_garden +52 -0
  58. data/test/fixtures/mapquest_no_results +7 -0
  59. data/test/fixtures/maxmind_24_24_24_21 +1 -0
  60. data/test/fixtures/maxmind_24_24_24_22 +1 -0
  61. data/test/fixtures/maxmind_24_24_24_23 +1 -0
  62. data/test/fixtures/maxmind_24_24_24_24 +1 -0
  63. data/test/fixtures/maxmind_74_200_247_59 +1 -0
  64. data/test/fixtures/maxmind_invalid_key +1 -0
  65. data/test/fixtures/maxmind_no_results +1 -0
  66. data/test/fixtures/ovi_madison_square_garden +72 -0
  67. data/test/fixtures/ovi_no_results +8 -0
  68. data/test/fixtures/yahoo_error +1 -0
  69. data/test/fixtures/yahoo_invalid_key +2 -0
  70. data/test/fixtures/yahoo_madison_square_garden +52 -0
  71. data/test/fixtures/yahoo_no_results +10 -0
  72. data/test/fixtures/yahoo_over_limit +2 -0
  73. data/test/fixtures/yandex_no_city_and_town +112 -0
  74. data/test/https_test.rb +3 -3
  75. data/test/integration/smoke_test.rb +2 -2
  76. data/test/lookup_test.rb +84 -11
  77. data/test/near_test.rb +43 -0
  78. data/test/oauth_util_test.rb +30 -0
  79. data/test/proxy_test.rb +2 -2
  80. data/test/query_test.rb +13 -0
  81. data/test/request_test.rb +29 -0
  82. data/test/result_test.rb +12 -2
  83. data/test/services_test.rb +208 -57
  84. data/test/test_helper.rb +66 -100
  85. data/test/test_mode_test.rb +35 -26
  86. metadata +58 -35
  87. data/test/fixtures/mapquest_madison_square_garden.json +0 -27
  88. data/test/fixtures/mapquest_no_results.json +0 -1
  89. data/test/fixtures/yahoo_madison_square_garden.json +0 -52
  90. data/test/fixtures/yahoo_no_results.json +0 -10
  91. data/test/fixtures/yahoo_v1_madison_square_garden.json +0 -46
  92. data/test/fixtures/yahoo_v1_no_results.json +0 -10
  93. /data/test/fixtures/{bing_madison_square_garden.json → bing_madison_square_garden} +0 -0
  94. /data/test/fixtures/{bing_no_results.json → bing_no_results} +0 -0
  95. /data/test/fixtures/{bing_reverse.json → bing_reverse} +0 -0
  96. /data/test/fixtures/{freegeoip_74_200_247_59.json → freegeoip_74_200_247_59} +0 -0
  97. /data/test/fixtures/{freegeoip_no_results.json → freegeoip_no_results} +0 -0
  98. /data/test/fixtures/{geocoder_ca_madison_square_garden.json → geocoder_ca_madison_square_garden} +0 -0
  99. /data/test/fixtures/{geocoder_ca_no_results.json → geocoder_ca_no_results} +0 -0
  100. /data/test/fixtures/{geocoder_ca_reverse.json → geocoder_ca_reverse} +0 -0
  101. /data/test/fixtures/{google_garbage.json → google_garbage} +0 -0
  102. /data/test/fixtures/{google_madison_square_garden.json → google_madison_square_garden} +0 -0
  103. /data/test/fixtures/{google_no_city_data.json → google_no_city_data} +0 -0
  104. /data/test/fixtures/{google_no_locality.json → google_no_locality} +0 -0
  105. /data/test/fixtures/{google_no_results.json → google_no_results} +0 -0
  106. /data/test/fixtures/{nominatim_madison_square_garden.json → nominatim_madison_square_garden} +0 -0
  107. /data/test/fixtures/{nominatim_no_results.json → nominatim_no_results} +0 -0
  108. /data/test/fixtures/{yandex_invalid_key.json → yandex_invalid_key} +0 -0
  109. /data/test/fixtures/{yandex_kremlin.json → yandex_kremlin} +0 -0
  110. /data/test/fixtures/{yandex_no_results.json → yandex_no_results} +0 -0
@@ -0,0 +1,48 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/esri"
3
+
4
+ module Geocoder::Lookup
5
+ class Esri < Base
6
+
7
+ def name
8
+ "Esri"
9
+ end
10
+
11
+ def query_url(query)
12
+ search_keyword = query.reverse_geocode? ? "reverseGeocode" : "find"
13
+
14
+ "#{protocol}://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/#{search_keyword}?" +
15
+ url_query_string(query)
16
+ end
17
+
18
+ private # ---------------------------------------------------------------
19
+
20
+ def results(query)
21
+ return [] unless doc = fetch_data(query)
22
+
23
+ if (!query.reverse_geocode?)
24
+ return [] if doc['locations'].empty?
25
+ end
26
+
27
+ if (doc['error'].nil?)
28
+ return [ doc ]
29
+ else
30
+ return []
31
+ end
32
+ end
33
+
34
+ def query_url_params(query)
35
+ params = {
36
+ :f => "pjson",
37
+ :outFields => "*"
38
+ }
39
+ if query.reverse_geocode?
40
+ params[:location] = query.coordinates.reverse.join(',')
41
+ else
42
+ params[:text] = query.sanitized_text
43
+ end
44
+ params.merge(super)
45
+ end
46
+
47
+ end
48
+ end
@@ -4,6 +4,14 @@ require 'geocoder/results/freegeoip'
4
4
  module Geocoder::Lookup
5
5
  class Freegeoip < Base
6
6
 
7
+ def name
8
+ "FreeGeoIP"
9
+ end
10
+
11
+ def query_url(query)
12
+ "#{protocol}://freegeoip.net/json/#{query.sanitized_text}"
13
+ end
14
+
7
15
  private # ---------------------------------------------------------------
8
16
 
9
17
  def parse_raw_data(raw_data)
@@ -35,9 +43,5 @@ module Geocoder::Lookup
35
43
  "country_code" => "RD"
36
44
  }
37
45
  end
38
-
39
- def query_url(query)
40
- "http://freegeoip.net/json/#{query.sanitized_text}"
41
- end
42
46
  end
43
47
  end
@@ -4,6 +4,14 @@ require "geocoder/results/geocoder_ca"
4
4
  module Geocoder::Lookup
5
5
  class GeocoderCa < Base
6
6
 
7
+ def name
8
+ "Geocoder.ca"
9
+ end
10
+
11
+ def query_url(query)
12
+ "#{protocol}://geocoder.ca/?" + url_query_string(query)
13
+ end
14
+
7
15
  private # ---------------------------------------------------------------
8
16
 
9
17
  def results(query)
@@ -19,12 +27,12 @@ module Geocoder::Lookup
19
27
  end
20
28
 
21
29
  def query_url_params(query)
22
- params = super.merge(
30
+ params = {
23
31
  :geoit => "xml",
24
32
  :jsonp => 1,
25
33
  :callback => "test",
26
- :auth => Geocoder::Configuration.api_key
27
- )
34
+ :auth => configuration.api_key
35
+ }.merge(super)
28
36
  if query.reverse_geocode?
29
37
  lat,lon = query.coordinates
30
38
  params[:latt] = lat
@@ -38,10 +46,6 @@ module Geocoder::Lookup
38
46
  params
39
47
  end
40
48
 
41
- def query_url(query)
42
- "http://geocoder.ca/?" + url_query_string(query)
43
- end
44
-
45
49
  def parse_raw_data(raw_data)
46
50
  super raw_data[/^test\((.*)\)\;\s*$/, 1]
47
51
  end
@@ -4,10 +4,18 @@ require "geocoder/results/google"
4
4
  module Geocoder::Lookup
5
5
  class Google < Base
6
6
 
7
+ def name
8
+ "Google"
9
+ end
10
+
7
11
  def map_link_url(coordinates)
8
12
  "http://maps.google.com/maps?q=#{coordinates.join(',')}"
9
13
  end
10
14
 
15
+ def query_url(query)
16
+ "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + url_query_string(query)
17
+ end
18
+
11
19
  private # ---------------------------------------------------------------
12
20
 
13
21
  def results(query)
@@ -31,23 +39,24 @@ module Geocoder::Lookup
31
39
  params = {
32
40
  (query.reverse_geocode? ? :latlng : :address) => query.sanitized_text,
33
41
  :sensor => "false",
34
- :language => Geocoder::Configuration.language
42
+ :language => configuration.language
35
43
  }
36
44
  unless (bounds = query.options[:bounds]).nil?
37
45
  params[:bounds] = bounds.map{ |point| "%f,%f" % point }.join('|')
38
46
  end
47
+ unless (region = query.options[:region]).nil?
48
+ params[:region] = region
49
+ end
50
+ unless (components = query.options[:components]).nil?
51
+ params[:components] = components.is_a?(Array) ? components.join("|") : components
52
+ end
39
53
  params
40
54
  end
41
55
 
42
56
  def query_url_params(query)
43
- super.merge(query_url_google_params(query)).merge(
44
- :key => Geocoder::Configuration.api_key
45
- )
46
- end
47
-
48
- def query_url(query)
49
- "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + url_query_string(query)
57
+ query_url_google_params(query).merge(
58
+ :key => configuration.api_key
59
+ ).merge(super)
50
60
  end
51
61
  end
52
62
  end
53
-
@@ -6,14 +6,12 @@ require 'geocoder/results/google_premier'
6
6
  module Geocoder::Lookup
7
7
  class GooglePremier < Google
8
8
 
9
- private # ---------------------------------------------------------------
9
+ def name
10
+ "Google Premier"
11
+ end
10
12
 
11
- def query_url_params(query)
12
- super.merge(query_url_google_params(query)).merge(
13
- :key => nil, # don't use param inherited from Google lookup
14
- :client => Geocoder::Configuration.api_key[1],
15
- :channel => Geocoder::Configuration.api_key[2]
16
- )
13
+ def required_api_key_parts
14
+ ["private key", "client", "channel"]
17
15
  end
18
16
 
19
17
  def query_url(query)
@@ -21,8 +19,18 @@ module Geocoder::Lookup
21
19
  "#{protocol}://maps.googleapis.com#{path}&signature=#{sign(path)}"
22
20
  end
23
21
 
22
+ private # ---------------------------------------------------------------
23
+
24
+ def query_url_params(query)
25
+ query_url_google_params(query).merge(super).merge(
26
+ :key => nil, # don't use param inherited from Google lookup
27
+ :client => configuration.api_key[1],
28
+ :channel => configuration.api_key[2]
29
+ )
30
+ end
31
+
24
32
  def sign(string)
25
- raw_private_key = url_safe_base64_decode(Geocoder::Configuration.api_key[0])
33
+ raw_private_key = url_safe_base64_decode(configuration.api_key[0])
26
34
  digest = OpenSSL::Digest::Digest.new('sha1')
27
35
  raw_signature = OpenSSL::HMAC.digest(digest, raw_private_key, string)
28
36
  url_safe_base64_encode(raw_signature)
@@ -1,15 +1,43 @@
1
+ require 'cgi'
1
2
  require 'geocoder/lookups/base'
2
- require "geocoder/lookups/nominatim"
3
3
  require "geocoder/results/mapquest"
4
4
 
5
5
  module Geocoder::Lookup
6
- class Mapquest < Nominatim
6
+ class Mapquest < Base
7
7
 
8
- private # ---------------------------------------------------------------
8
+ def name
9
+ "Mapquest"
10
+ end
11
+
12
+ def required_api_key_parts
13
+ []
14
+ end
9
15
 
10
16
  def query_url(query)
11
- method = query.reverse_geocode? ? "reverse" : "search"
12
- "http://open.mapquestapi.com/#{method}?" + url_query_string(query)
17
+ key = configuration.api_key
18
+ domain = key ? "www" : "open"
19
+ url = "#{protocol}://#{domain}.mapquestapi.com/geocoding/v1/#{search_type(query)}?"
20
+ url + url_query_string(query)
13
21
  end
22
+
23
+ private # ---------------------------------------------------------------
24
+
25
+ def search_type(query)
26
+ query.reverse_geocode? ? "reverse" : "address"
27
+ end
28
+
29
+ def query_url_params(query)
30
+ params = { :location => query.sanitized_text }
31
+ if key = configuration.api_key
32
+ params[:key] = CGI.unescape(key)
33
+ end
34
+ params.merge(super)
35
+ end
36
+
37
+ def results(query)
38
+ return [] unless doc = fetch_data(query)
39
+ doc["results"][0]['locations']
40
+ end
41
+
14
42
  end
15
43
  end
@@ -0,0 +1,88 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/maxmind'
3
+ require 'csv'
4
+
5
+ module Geocoder::Lookup
6
+ class Maxmind < Base
7
+
8
+ def name
9
+ "MaxMind"
10
+ end
11
+
12
+ def query_url(query)
13
+ "#{protocol}://geoip.maxmind.com/#{service_code}?" + url_query_string(query)
14
+ end
15
+
16
+ private # ---------------------------------------------------------------
17
+
18
+ ##
19
+ # Return the name of the configured service, or raise an exception.
20
+ #
21
+ def configured_service!
22
+ if s = configuration[:service] and services.keys.include?(s)
23
+ return s
24
+ else
25
+ raise(
26
+ Geocoder::ConfigurationError,
27
+ "When using MaxMind you MUST specify a service name: " +
28
+ "Geocoder.configure(:maxmind => {:service => ...}), " +
29
+ "where '...' is one of: #{services.keys.inspect}"
30
+ )
31
+ end
32
+ end
33
+
34
+ def service_code
35
+ services[configured_service!]
36
+ end
37
+
38
+ def service_response_fields_count
39
+ Geocoder::Result::Maxmind.field_names[configured_service!].size
40
+ end
41
+
42
+ def data_contains_error?(parsed_data)
43
+ # if all fields given then there is an error
44
+ parsed_data.size == service_response_fields_count and !parsed_data.last.nil?
45
+ end
46
+
47
+ ##
48
+ # Service names mapped to code used in URL.
49
+ #
50
+ def services
51
+ {
52
+ :country => "a",
53
+ :city => "b",
54
+ :city_isp_org => "f",
55
+ :omni => "e"
56
+ }
57
+ end
58
+
59
+ def results(query)
60
+ # don't look up a loopback address, just return the stored result
61
+ return [reserved_result] if query.loopback_ip_address?
62
+ doc = fetch_data(query)
63
+ if doc and doc.is_a?(Array)
64
+ if !data_contains_error?(doc)
65
+ return [doc]
66
+ elsif doc.last == "INVALID_LICENSE_KEY"
67
+ raise_error(Geocoder::InvalidApiKey) || warn("Invalid MaxMind API key.")
68
+ end
69
+ end
70
+ return []
71
+ end
72
+
73
+ def parse_raw_data(raw_data)
74
+ CSV.parse_line raw_data
75
+ end
76
+
77
+ def reserved_result
78
+ ",,,,0,0,0,0,,,"
79
+ end
80
+
81
+ def query_url_params(query)
82
+ {
83
+ :l => configuration.api_key,
84
+ :i => query.sanitized_text
85
+ }.merge(super)
86
+ end
87
+ end
88
+ end
@@ -4,10 +4,20 @@ require "geocoder/results/nominatim"
4
4
  module Geocoder::Lookup
5
5
  class Nominatim < Base
6
6
 
7
+ def name
8
+ "Nominatim"
9
+ end
10
+
7
11
  def map_link_url(coordinates)
8
12
  "http://www.openstreetmap.org/?lat=#{coordinates[0]}&lon=#{coordinates[1]}&zoom=15&layers=M"
9
13
  end
10
14
 
15
+ def query_url(query)
16
+ method = query.reverse_geocode? ? "reverse" : "search"
17
+ host = configuration[:host] || "nominatim.openstreetmap.org"
18
+ "#{protocol}://#{host}/#{method}?" + url_query_string(query)
19
+ end
20
+
11
21
  private # ---------------------------------------------------------------
12
22
 
13
23
  def results(query)
@@ -16,12 +26,12 @@ module Geocoder::Lookup
16
26
  end
17
27
 
18
28
  def query_url_params(query)
19
- params = super.merge(
29
+ params = {
20
30
  :format => "json",
21
31
  :polygon => "1",
22
32
  :addressdetails => "1",
23
- :"accept-language" => Geocoder::Configuration.language
24
- )
33
+ :"accept-language" => configuration.language
34
+ }.merge(super)
25
35
  if query.reverse_geocode?
26
36
  lat,lon = query.coordinates
27
37
  params[:lat] = lat
@@ -31,10 +41,5 @@ module Geocoder::Lookup
31
41
  end
32
42
  params
33
43
  end
34
-
35
- def query_url(query)
36
- method = query.reverse_geocode? ? "reverse" : "search"
37
- "http://nominatim.openstreetmap.org/#{method}?" + url_query_string(query)
38
- end
39
44
  end
40
45
  end
@@ -0,0 +1,52 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ovi'
3
+
4
+ module Geocoder::Lookup
5
+ class Ovi < Base
6
+
7
+ def name
8
+ "Ovi"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ []
13
+ end
14
+
15
+ def query_url(query)
16
+ "#{protocol}://lbs.ovi.com/search/6.2/geocode.json?" + url_query_string(query)
17
+ end
18
+
19
+ private # ---------------------------------------------------------------
20
+
21
+ def results(query)
22
+ return [] unless doc = fetch_data(query)
23
+ return [] unless doc['Response'] && doc['Response']['View']
24
+ if r=doc['Response']['View']
25
+ return [] if r.nil? || !r.is_a?(Array) || r.empty?
26
+ return r.first['Result']
27
+ end
28
+ []
29
+ end
30
+
31
+ def query_url_params(query)
32
+ super.merge(
33
+ :searchtext=>query.sanitized_text,
34
+ :gen=>1,
35
+ :app_id=>api_key,
36
+ :app_code=>api_code
37
+ )
38
+ end
39
+
40
+ def api_key
41
+ if a=configuration.api_key
42
+ return a.first if a.is_a?(Array)
43
+ end
44
+ end
45
+
46
+ def api_code
47
+ if a=configuration.api_key
48
+ return a.last if a.is_a?(Array)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -5,12 +5,21 @@ module Geocoder
5
5
  module Lookup
6
6
  class Test < Base
7
7
 
8
+ def name
9
+ "Test"
10
+ end
11
+
8
12
  def self.add_stub(query_text, results)
9
13
  stubs[query_text] = results
10
14
  end
11
15
 
16
+ def self.set_default_stub(results)
17
+ @default_stub = results
18
+ end
19
+
12
20
  def self.read_stub(query_text)
13
21
  stubs.fetch(query_text) {
22
+ return @default_stub unless @default_stub.nil?
14
23
  raise ArgumentError, "unknown stub request #{query_text}"
15
24
  }
16
25
  end
@@ -21,6 +30,7 @@ module Geocoder
21
30
 
22
31
  def self.reset
23
32
  @stubs = {}
33
+ @default_stub = nil
24
34
  end
25
35
 
26
36
  private
@@ -1,73 +1,86 @@
1
1
  require 'geocoder/lookups/base'
2
2
  require "geocoder/results/yahoo"
3
+ require 'oauth_util'
3
4
 
4
5
  module Geocoder::Lookup
5
6
  class Yahoo < Base
6
7
 
8
+ def name
9
+ "Yahoo BOSS"
10
+ end
11
+
7
12
  def map_link_url(coordinates)
8
13
  "http://maps.yahoo.com/#lat=#{coordinates[0]}&lon=#{coordinates[1]}"
9
14
  end
10
15
 
11
- private # ---------------------------------------------------------------
12
-
13
- def results(query)
14
- return [] unless doc = fetch_data(query)
15
- doc = doc['ResultSet']
16
- if api_version(doc).to_i == 1
17
- return version_1_results(doc)
18
- elsif api_version(doc).to_i == 2
19
- return version_2_results(doc)
20
- else
21
- warn "Yahoo Geocoding API error: #{doc['Error']} (#{doc['ErrorMessage']})."
22
- return []
23
- end
16
+ def required_api_key_parts
17
+ ["consumer key", "consumer secret"]
24
18
  end
25
19
 
26
- def api_version(doc)
27
- if doc.include?('version')
28
- return doc['version'].to_f
29
- elsif doc.include?('@version')
30
- return doc['@version'].to_f
31
- end
20
+ def query_url(query)
21
+ parsed_url = URI.parse(raw_url(query))
22
+ o = OauthUtil.new
23
+ o.consumer_key = configuration.api_key[0]
24
+ o.consumer_secret = configuration.api_key[1]
25
+ base_url + o.sign(parsed_url).query_string
32
26
  end
33
27
 
34
- def version_1_results(doc)
35
- if doc['Error'] == 0
36
- if doc['Found'] > 0
37
- return doc['Results']
28
+ private # ---------------------------------------------------------------
29
+
30
+ def results(query)
31
+ return [] unless doc = fetch_data(query)
32
+ doc = doc['bossresponse']
33
+ if doc['responsecode'].to_i == 200
34
+ if doc['placefinder']['count'].to_i > 0
35
+ return doc['placefinder']['results']
38
36
  else
39
37
  return []
40
38
  end
39
+ else
40
+ warn "Yahoo Geocoding API error: #{doc['responsecode']} (#{doc['reason']})."
41
+ return []
41
42
  end
42
43
  end
43
44
 
44
45
  ##
45
- # Return array of results, or nil if an error.
46
+ # Yahoo returns errors as XML even when JSON format is specified.
47
+ # Handle that here, without parsing the XML
48
+ # (which would add unnecessary complexity).
49
+ # Yahoo auth errors can also be cryptic, so add raw error desc
50
+ # to warning message.
46
51
  #
47
- def version_2_results(doc)
48
- # seems to have Error == 7 when no results, though this is not documented
49
- if [0, 7].include?(doc['Error'].to_i)
50
- if doc['Found'].to_i > 0
51
- r = doc['Result']
52
- return r.is_a?(Array) ? r : [r]
53
- else
54
- return []
52
+ def parse_raw_data(raw_data)
53
+ if raw_data.match /^<\?xml/
54
+ if raw_data.include?("Rate Limit Exceeded")
55
+ raise_error(Geocoder::OverQueryLimitError) || warn("Over API query limit.")
56
+ elsif raw_data =~ /<yahoo:description>(Please provide valid credentials.*)<\/yahoo:description>/i
57
+ raise_error(Geocoder::InvalidApiKey) || warn("Invalid API key. Error response: #{$1}")
55
58
  end
59
+ else
60
+ super(raw_data)
56
61
  end
57
62
  end
58
63
 
59
64
  def query_url_params(query)
60
- super.merge(
65
+ {
61
66
  :location => query.sanitized_text,
62
67
  :flags => "JXTSR",
63
68
  :gflags => "AC#{'R' if query.reverse_geocode?}",
64
- :locale => "#{Geocoder::Configuration.language}_US",
65
- :appid => Geocoder::Configuration.api_key
66
- )
69
+ :locale => "#{configuration.language}_US",
70
+ :appid => configuration.api_key
71
+ }.merge(super)
67
72
  end
68
73
 
69
- def query_url(query)
70
- "http://where.yahooapis.com/geocode?" + url_query_string(query)
74
+ def cache_key(query)
75
+ raw_url(query)
76
+ end
77
+
78
+ def base_url
79
+ "#{protocol}://yboss.yahooapis.com/geo/placefinder?"
80
+ end
81
+
82
+ def raw_url(query)
83
+ base_url + url_query_string(query)
71
84
  end
72
85
  end
73
86
  end
@@ -4,16 +4,28 @@ require "geocoder/results/yandex"
4
4
  module Geocoder::Lookup
5
5
  class Yandex < Base
6
6
 
7
+ def name
8
+ "Yandex"
9
+ end
10
+
7
11
  def map_link_url(coordinates)
8
12
  "http://maps.yandex.ru/?ll=#{coordinates.reverse.join(',')}"
9
13
  end
10
14
 
15
+ def query_url(query)
16
+ "#{protocol}://geocode-maps.yandex.ru/1.x/?" + url_query_string(query)
17
+ end
18
+
11
19
  private # ---------------------------------------------------------------
12
20
 
13
21
  def results(query)
14
22
  return [] unless doc = fetch_data(query)
15
23
  if err = doc['error']
16
- warn "Yandex Geocoding API error: #{err['status']} (#{err['message']})."
24
+ if err["status"] == 401 and err["message"] == "invalid key"
25
+ raise_error(Geocoder::InvalidApiKey) || warn("Invalid API key.")
26
+ else
27
+ warn "Yandex Geocoding API error: #{err['status']} (#{err['message']})."
28
+ end
17
29
  return []
18
30
  end
19
31
  if doc = doc['response']['GeoObjectCollection']
@@ -31,16 +43,12 @@ module Geocoder::Lookup
31
43
  else
32
44
  q = query.sanitized_text
33
45
  end
34
- super.merge(
46
+ {
35
47
  :geocode => q,
36
48
  :format => "json",
37
- :plng => "#{Geocoder::Configuration.language}", # supports ru, uk, be
38
- :key => Geocoder::Configuration.api_key
39
- )
40
- end
41
-
42
- def query_url(query)
43
- "http://geocode-maps.yandex.ru/1.x/?" + url_query_string(query)
49
+ :plng => "#{configuration.language}", # supports ru, uk, be
50
+ :key => configuration.api_key
51
+ }.merge(super)
44
52
  end
45
53
  end
46
54
  end
@@ -18,7 +18,7 @@ module Geocoder
18
18
  super(options)
19
19
  if options[:skip_index] == false
20
20
  # create 2d index
21
- if (::Mongoid::VERSION >= "3")
21
+ if defined?(::Mongoid::VERSION) && ::Mongoid::VERSION >= "3"
22
22
  index({ geocoder_options[:coordinates].to_sym => '2d' },
23
23
  {:min => -180, :max => 180})
24
24
  else