geocoder-sgonyea 1.1.6.1

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 (122) hide show
  1. data/.gitignore +5 -0
  2. data/.travis.yml +23 -0
  3. data/CHANGELOG.md +298 -0
  4. data/LICENSE +20 -0
  5. data/README.md +656 -0
  6. data/Rakefile +25 -0
  7. data/bin/geocode +5 -0
  8. data/examples/autoexpire_cache.rb +28 -0
  9. data/gemfiles/Gemfile.mongoid-2.4.x +15 -0
  10. data/lib/generators/geocoder/config/config_generator.rb +14 -0
  11. data/lib/generators/geocoder/config/templates/initializer.rb +21 -0
  12. data/lib/geocoder.rb +55 -0
  13. data/lib/geocoder/cache.rb +85 -0
  14. data/lib/geocoder/calculations.rb +319 -0
  15. data/lib/geocoder/cli.rb +114 -0
  16. data/lib/geocoder/configuration.rb +130 -0
  17. data/lib/geocoder/configuration_hash.rb +11 -0
  18. data/lib/geocoder/exceptions.rb +21 -0
  19. data/lib/geocoder/lookup.rb +82 -0
  20. data/lib/geocoder/lookups/base.rb +250 -0
  21. data/lib/geocoder/lookups/bing.rb +47 -0
  22. data/lib/geocoder/lookups/freegeoip.rb +47 -0
  23. data/lib/geocoder/lookups/geocoder_ca.rb +54 -0
  24. data/lib/geocoder/lookups/google.rb +62 -0
  25. data/lib/geocoder/lookups/google_premier.rb +47 -0
  26. data/lib/geocoder/lookups/mapquest.rb +43 -0
  27. data/lib/geocoder/lookups/maxmind.rb +88 -0
  28. data/lib/geocoder/lookups/nominatim.rb +45 -0
  29. data/lib/geocoder/lookups/ovi.rb +52 -0
  30. data/lib/geocoder/lookups/test.rb +38 -0
  31. data/lib/geocoder/lookups/yahoo.rb +84 -0
  32. data/lib/geocoder/lookups/yandex.rb +54 -0
  33. data/lib/geocoder/models/active_record.rb +46 -0
  34. data/lib/geocoder/models/base.rb +42 -0
  35. data/lib/geocoder/models/mongo_base.rb +60 -0
  36. data/lib/geocoder/models/mongo_mapper.rb +26 -0
  37. data/lib/geocoder/models/mongoid.rb +32 -0
  38. data/lib/geocoder/query.rb +103 -0
  39. data/lib/geocoder/railtie.rb +26 -0
  40. data/lib/geocoder/request.rb +23 -0
  41. data/lib/geocoder/results/base.rb +67 -0
  42. data/lib/geocoder/results/bing.rb +48 -0
  43. data/lib/geocoder/results/freegeoip.rb +45 -0
  44. data/lib/geocoder/results/geocoder_ca.rb +60 -0
  45. data/lib/geocoder/results/google.rb +106 -0
  46. data/lib/geocoder/results/google_premier.rb +6 -0
  47. data/lib/geocoder/results/mapquest.rb +51 -0
  48. data/lib/geocoder/results/maxmind.rb +136 -0
  49. data/lib/geocoder/results/nominatim.rb +94 -0
  50. data/lib/geocoder/results/ovi.rb +62 -0
  51. data/lib/geocoder/results/test.rb +16 -0
  52. data/lib/geocoder/results/yahoo.rb +55 -0
  53. data/lib/geocoder/results/yandex.rb +80 -0
  54. data/lib/geocoder/sql.rb +106 -0
  55. data/lib/geocoder/stores/active_record.rb +259 -0
  56. data/lib/geocoder/stores/base.rb +120 -0
  57. data/lib/geocoder/stores/mongo_base.rb +85 -0
  58. data/lib/geocoder/stores/mongo_mapper.rb +13 -0
  59. data/lib/geocoder/stores/mongoid.rb +13 -0
  60. data/lib/geocoder/version.rb +3 -0
  61. data/lib/hash_recursive_merge.rb +74 -0
  62. data/lib/oauth_util.rb +112 -0
  63. data/lib/tasks/geocoder.rake +25 -0
  64. data/test/active_record_test.rb +15 -0
  65. data/test/cache_test.rb +19 -0
  66. data/test/calculations_test.rb +195 -0
  67. data/test/configuration_test.rb +78 -0
  68. data/test/custom_block_test.rb +32 -0
  69. data/test/error_handling_test.rb +43 -0
  70. data/test/fixtures/bing_invalid_key +1 -0
  71. data/test/fixtures/bing_madison_square_garden +40 -0
  72. data/test/fixtures/bing_no_results +16 -0
  73. data/test/fixtures/bing_reverse +42 -0
  74. data/test/fixtures/freegeoip_74_200_247_59 +12 -0
  75. data/test/fixtures/freegeoip_no_results +1 -0
  76. data/test/fixtures/geocoder_ca_madison_square_garden +1 -0
  77. data/test/fixtures/geocoder_ca_no_results +1 -0
  78. data/test/fixtures/geocoder_ca_reverse +34 -0
  79. data/test/fixtures/google_garbage +456 -0
  80. data/test/fixtures/google_madison_square_garden +57 -0
  81. data/test/fixtures/google_no_city_data +44 -0
  82. data/test/fixtures/google_no_locality +51 -0
  83. data/test/fixtures/google_no_results +4 -0
  84. data/test/fixtures/mapquest_madison_square_garden +52 -0
  85. data/test/fixtures/mapquest_no_results +7 -0
  86. data/test/fixtures/maxmind_24_24_24_21 +1 -0
  87. data/test/fixtures/maxmind_24_24_24_22 +1 -0
  88. data/test/fixtures/maxmind_24_24_24_23 +1 -0
  89. data/test/fixtures/maxmind_24_24_24_24 +1 -0
  90. data/test/fixtures/maxmind_74_200_247_59 +1 -0
  91. data/test/fixtures/maxmind_invalid_key +1 -0
  92. data/test/fixtures/maxmind_no_results +1 -0
  93. data/test/fixtures/nominatim_madison_square_garden +150 -0
  94. data/test/fixtures/nominatim_no_results +1 -0
  95. data/test/fixtures/ovi_madison_square_garden +72 -0
  96. data/test/fixtures/ovi_no_results +8 -0
  97. data/test/fixtures/yahoo_error +1 -0
  98. data/test/fixtures/yahoo_invalid_key +2 -0
  99. data/test/fixtures/yahoo_madison_square_garden +52 -0
  100. data/test/fixtures/yahoo_no_results +10 -0
  101. data/test/fixtures/yahoo_over_limit +2 -0
  102. data/test/fixtures/yandex_invalid_key +1 -0
  103. data/test/fixtures/yandex_kremlin +48 -0
  104. data/test/fixtures/yandex_no_city_and_town +112 -0
  105. data/test/fixtures/yandex_no_results +16 -0
  106. data/test/geocoder_test.rb +59 -0
  107. data/test/https_test.rb +16 -0
  108. data/test/integration/smoke_test.rb +26 -0
  109. data/test/lookup_test.rb +116 -0
  110. data/test/method_aliases_test.rb +25 -0
  111. data/test/mongoid_test.rb +39 -0
  112. data/test/mongoid_test_helper.rb +43 -0
  113. data/test/near_test.rb +43 -0
  114. data/test/oauth_util_test.rb +30 -0
  115. data/test/proxy_test.rb +23 -0
  116. data/test/query_test.rb +51 -0
  117. data/test/request_test.rb +29 -0
  118. data/test/result_test.rb +42 -0
  119. data/test/services_test.rb +277 -0
  120. data/test/test_helper.rb +279 -0
  121. data/test/test_mode_test.rb +50 -0
  122. metadata +170 -0
@@ -0,0 +1,47 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/bing"
3
+
4
+ module Geocoder::Lookup
5
+ class Bing < Base
6
+
7
+ def name
8
+ "Bing"
9
+ end
10
+
11
+ def map_link_url(coordinates)
12
+ "http://www.bing.com/maps/default.aspx?cp=#{coordinates.join('~')}"
13
+ end
14
+
15
+ def required_api_key_parts
16
+ ["key"]
17
+ end
18
+
19
+ def query_url(query)
20
+ "#{protocol}://dev.virtualearth.net/REST/v1/Locations" +
21
+ (query.reverse_geocode? ? "/#{query.sanitized_text}?" : "?") +
22
+ url_query_string(query)
23
+ end
24
+
25
+ private # ---------------------------------------------------------------
26
+
27
+ def results(query)
28
+ return [] unless doc = fetch_data(query)
29
+
30
+ if doc['statusCode'] == 200
31
+ return doc['resourceSets'].first['estimatedTotal'] > 0 ? doc['resourceSets'].first['resources'] : []
32
+ elsif doc['statusCode'] == 401 and doc["authenticationResultCode"] == "InvalidCredentials"
33
+ raise_error(Geocoder::InvalidApiKey) || warn("Invalid Bing API key.")
34
+ else
35
+ warn "Bing Geocoding API error: #{doc['statusCode']} (#{doc['statusDescription']})."
36
+ end
37
+ return []
38
+ end
39
+
40
+ def query_url_params(query)
41
+ {
42
+ :key => configuration.api_key,
43
+ :query => query.reverse_geocode? ? nil : query.sanitized_text
44
+ }.merge(super)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,47 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/freegeoip'
3
+
4
+ module Geocoder::Lookup
5
+ class Freegeoip < Base
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
+
15
+ private # ---------------------------------------------------------------
16
+
17
+ def parse_raw_data(raw_data)
18
+ raw_data.match(/^<html><title>404/) ? nil : super(raw_data)
19
+ end
20
+
21
+ def results(query)
22
+ # don't look up a loopback address, just return the stored result
23
+ return [reserved_result(query.text)] if query.loopback_ip_address?
24
+ begin
25
+ return (doc = fetch_data(query)) ? [doc] : []
26
+ rescue StandardError => err # Freegeoip.net returns HTML on bad request
27
+ raise_error(err)
28
+ return []
29
+ end
30
+ end
31
+
32
+ def reserved_result(ip)
33
+ {
34
+ "ip" => ip,
35
+ "city" => "",
36
+ "region_code" => "",
37
+ "region_name" => "",
38
+ "metrocode" => "",
39
+ "zipcode" => "",
40
+ "latitude" => "0",
41
+ "longitude" => "0",
42
+ "country_name" => "Reserved",
43
+ "country_code" => "RD"
44
+ }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,54 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/geocoder_ca"
3
+
4
+ module Geocoder::Lookup
5
+ class GeocoderCa < Base
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
+
15
+ private # ---------------------------------------------------------------
16
+
17
+ def results(query)
18
+ return [] unless doc = fetch_data(query)
19
+ if doc['error'].nil?
20
+ return [doc]
21
+ elsif doc['error']['code'] == "005"
22
+ # "Postal Code is not in the proper Format" => no results, just shut up
23
+ else
24
+ warn "Geocoder.ca service error: #{doc['error']['code']} (#{doc['error']['description']})."
25
+ end
26
+ return []
27
+ end
28
+
29
+ def query_url_params(query)
30
+ params = {
31
+ :geoit => "xml",
32
+ :jsonp => 1,
33
+ :callback => "test",
34
+ :auth => configuration.api_key
35
+ }.merge(super)
36
+ if query.reverse_geocode?
37
+ lat,lon = query.coordinates
38
+ params[:latt] = lat
39
+ params[:longt] = lon
40
+ params[:corner] = 1
41
+ params[:reverse] = 1
42
+ else
43
+ params[:locate] = query.sanitized_text
44
+ params[:showpostal] = 1
45
+ end
46
+ params
47
+ end
48
+
49
+ def parse_raw_data(raw_data)
50
+ super raw_data[/^test\((.*)\)\;\s*$/, 1]
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,62 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/google"
3
+
4
+ module Geocoder::Lookup
5
+ class Google < Base
6
+
7
+ def name
8
+ "Google"
9
+ end
10
+
11
+ def map_link_url(coordinates)
12
+ "http://maps.google.com/maps?q=#{coordinates.join(',')}"
13
+ end
14
+
15
+ def query_url(query)
16
+ "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + url_query_string(query)
17
+ end
18
+
19
+ private # ---------------------------------------------------------------
20
+
21
+ def results(query)
22
+ return [] unless doc = fetch_data(query)
23
+ case doc['status']; when "OK" # OK status implies >0 results
24
+ return doc['results']
25
+ when "OVER_QUERY_LIMIT"
26
+ raise_error(Geocoder::OverQueryLimitError) ||
27
+ warn("Google Geocoding API error: over query limit.")
28
+ when "REQUEST_DENIED"
29
+ raise_error(Geocoder::RequestDenied) ||
30
+ warn("Google Geocoding API error: request denied.")
31
+ when "INVALID_REQUEST"
32
+ raise_error(Geocoder::InvalidRequest) ||
33
+ warn("Google Geocoding API error: invalid request.")
34
+ end
35
+ return []
36
+ end
37
+
38
+ def query_url_google_params(query)
39
+ params = {
40
+ (query.reverse_geocode? ? :latlng : :address) => query.sanitized_text,
41
+ :sensor => "false",
42
+ :language => configuration.language
43
+ }
44
+ unless (bounds = query.options[:bounds]).nil?
45
+ params[:bounds] = bounds.map{ |point| "%f,%f" % point }.join('|')
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
53
+ params
54
+ end
55
+
56
+ def query_url_params(query)
57
+ query_url_google_params(query).merge(
58
+ :key => configuration.api_key
59
+ ).merge(super)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,47 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+ require 'geocoder/lookups/google'
4
+ require 'geocoder/results/google_premier'
5
+
6
+ module Geocoder::Lookup
7
+ class GooglePremier < Google
8
+
9
+ def name
10
+ "Google Premier"
11
+ end
12
+
13
+ def required_api_key_parts
14
+ ["private key", "client", "channel"]
15
+ end
16
+
17
+ def query_url(query)
18
+ path = "/maps/api/geocode/json?" + url_query_string(query)
19
+ "#{protocol}://maps.googleapis.com#{path}&signature=#{sign(path)}"
20
+ end
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
+
32
+ def sign(string)
33
+ raw_private_key = url_safe_base64_decode(configuration.api_key[0])
34
+ digest = OpenSSL::Digest::Digest.new('sha1')
35
+ raw_signature = OpenSSL::HMAC.digest(digest, raw_private_key, string)
36
+ url_safe_base64_encode(raw_signature)
37
+ end
38
+
39
+ def url_safe_base64_decode(base64_string)
40
+ Base64.decode64(base64_string.tr('-_', '+/'))
41
+ end
42
+
43
+ def url_safe_base64_encode(raw)
44
+ Base64.encode64(raw).tr('+/', '-_').strip
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,43 @@
1
+ require 'cgi'
2
+ require 'geocoder/lookups/base'
3
+ require "geocoder/results/mapquest"
4
+
5
+ module Geocoder::Lookup
6
+ class Mapquest < Base
7
+
8
+ def name
9
+ "Mapquest"
10
+ end
11
+
12
+ def required_api_key_parts
13
+ []
14
+ end
15
+
16
+ def query_url(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)
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
+
42
+ end
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
@@ -0,0 +1,45 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/nominatim"
3
+
4
+ module Geocoder::Lookup
5
+ class Nominatim < Base
6
+
7
+ def name
8
+ "Nominatim"
9
+ end
10
+
11
+ def map_link_url(coordinates)
12
+ "http://www.openstreetmap.org/?lat=#{coordinates[0]}&lon=#{coordinates[1]}&zoom=15&layers=M"
13
+ end
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
+
21
+ private # ---------------------------------------------------------------
22
+
23
+ def results(query)
24
+ return [] unless doc = fetch_data(query)
25
+ doc.is_a?(Array) ? doc : [doc]
26
+ end
27
+
28
+ def query_url_params(query)
29
+ params = {
30
+ :format => "json",
31
+ :polygon => "1",
32
+ :addressdetails => "1",
33
+ :"accept-language" => configuration.language
34
+ }.merge(super)
35
+ if query.reverse_geocode?
36
+ lat,lon = query.coordinates
37
+ params[:lat] = lat
38
+ params[:lon] = lon
39
+ else
40
+ params[:q] = query.sanitized_text
41
+ end
42
+ params
43
+ end
44
+ end
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