geocoder-kb 1.2.6

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 (248) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.travis.yml +31 -0
  4. data/CHANGELOG.md +384 -0
  5. data/LICENSE +20 -0
  6. data/README.md +1085 -0
  7. data/Rakefile +25 -0
  8. data/bin/geocode +5 -0
  9. data/examples/autoexpire_cache_dalli.rb +62 -0
  10. data/examples/autoexpire_cache_redis.rb +28 -0
  11. data/examples/cache_bypass.rb +48 -0
  12. data/examples/sidekiq_worker.rb +16 -0
  13. data/gemfiles/Gemfile.mongoid-2.4.x +16 -0
  14. data/lib/generators/geocoder/config/config_generator.rb +14 -0
  15. data/lib/generators/geocoder/config/templates/initializer.rb +21 -0
  16. data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +28 -0
  17. data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +28 -0
  18. data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +30 -0
  19. data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +17 -0
  20. data/lib/geocoder.rb +47 -0
  21. data/lib/geocoder/cache.rb +90 -0
  22. data/lib/geocoder/calculations.rb +428 -0
  23. data/lib/geocoder/cli.rb +121 -0
  24. data/lib/geocoder/configuration.rb +124 -0
  25. data/lib/geocoder/configuration_hash.rb +11 -0
  26. data/lib/geocoder/exceptions.rb +21 -0
  27. data/lib/geocoder/ip_address.rb +21 -0
  28. data/lib/geocoder/lookup.rb +102 -0
  29. data/lib/geocoder/lookups/amap.rb +55 -0
  30. data/lib/geocoder/lookups/baidu.rb +55 -0
  31. data/lib/geocoder/lookups/baidu_ip.rb +54 -0
  32. data/lib/geocoder/lookups/base.rb +302 -0
  33. data/lib/geocoder/lookups/bing.rb +59 -0
  34. data/lib/geocoder/lookups/dstk.rb +20 -0
  35. data/lib/geocoder/lookups/esri.rb +48 -0
  36. data/lib/geocoder/lookups/freegeoip.rb +47 -0
  37. data/lib/geocoder/lookups/geocoder_ca.rb +54 -0
  38. data/lib/geocoder/lookups/geocoder_us.rb +39 -0
  39. data/lib/geocoder/lookups/geocodio.rb +42 -0
  40. data/lib/geocoder/lookups/geoip2.rb +40 -0
  41. data/lib/geocoder/lookups/google.rb +67 -0
  42. data/lib/geocoder/lookups/google_places_details.rb +50 -0
  43. data/lib/geocoder/lookups/google_premier.rb +47 -0
  44. data/lib/geocoder/lookups/here.rb +62 -0
  45. data/lib/geocoder/lookups/mapquest.rb +60 -0
  46. data/lib/geocoder/lookups/maxmind.rb +90 -0
  47. data/lib/geocoder/lookups/maxmind_local.rb +58 -0
  48. data/lib/geocoder/lookups/nominatim.rb +52 -0
  49. data/lib/geocoder/lookups/okf.rb +43 -0
  50. data/lib/geocoder/lookups/opencagedata.rb +58 -0
  51. data/lib/geocoder/lookups/ovi.rb +62 -0
  52. data/lib/geocoder/lookups/pointpin.rb +68 -0
  53. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +51 -0
  54. data/lib/geocoder/lookups/smarty_streets.rb +45 -0
  55. data/lib/geocoder/lookups/telize.rb +40 -0
  56. data/lib/geocoder/lookups/test.rb +44 -0
  57. data/lib/geocoder/lookups/yahoo.rb +88 -0
  58. data/lib/geocoder/lookups/yandex.rb +54 -0
  59. data/lib/geocoder/models/active_record.rb +50 -0
  60. data/lib/geocoder/models/base.rb +39 -0
  61. data/lib/geocoder/models/mongo_base.rb +64 -0
  62. data/lib/geocoder/models/mongo_mapper.rb +26 -0
  63. data/lib/geocoder/models/mongoid.rb +32 -0
  64. data/lib/geocoder/query.rb +111 -0
  65. data/lib/geocoder/railtie.rb +26 -0
  66. data/lib/geocoder/request.rb +25 -0
  67. data/lib/geocoder/results/amap.rb +85 -0
  68. data/lib/geocoder/results/baidu.rb +79 -0
  69. data/lib/geocoder/results/baidu_ip.rb +62 -0
  70. data/lib/geocoder/results/base.rb +67 -0
  71. data/lib/geocoder/results/bing.rb +48 -0
  72. data/lib/geocoder/results/dstk.rb +6 -0
  73. data/lib/geocoder/results/esri.rb +51 -0
  74. data/lib/geocoder/results/freegeoip.rb +45 -0
  75. data/lib/geocoder/results/geocoder_ca.rb +60 -0
  76. data/lib/geocoder/results/geocoder_us.rb +39 -0
  77. data/lib/geocoder/results/geocodio.rb +66 -0
  78. data/lib/geocoder/results/geoip2.rb +64 -0
  79. data/lib/geocoder/results/google.rb +124 -0
  80. data/lib/geocoder/results/google_places_details.rb +35 -0
  81. data/lib/geocoder/results/google_premier.rb +6 -0
  82. data/lib/geocoder/results/here.rb +62 -0
  83. data/lib/geocoder/results/mapquest.rb +51 -0
  84. data/lib/geocoder/results/maxmind.rb +135 -0
  85. data/lib/geocoder/results/maxmind_local.rb +49 -0
  86. data/lib/geocoder/results/nominatim.rb +94 -0
  87. data/lib/geocoder/results/okf.rb +106 -0
  88. data/lib/geocoder/results/opencagedata.rb +82 -0
  89. data/lib/geocoder/results/ovi.rb +62 -0
  90. data/lib/geocoder/results/pointpin.rb +44 -0
  91. data/lib/geocoder/results/postcode_anywhere_uk.rb +42 -0
  92. data/lib/geocoder/results/smarty_streets.rb +106 -0
  93. data/lib/geocoder/results/telize.rb +45 -0
  94. data/lib/geocoder/results/test.rb +33 -0
  95. data/lib/geocoder/results/yahoo.rb +55 -0
  96. data/lib/geocoder/results/yandex.rb +84 -0
  97. data/lib/geocoder/sql.rb +107 -0
  98. data/lib/geocoder/stores/active_record.rb +289 -0
  99. data/lib/geocoder/stores/base.rb +127 -0
  100. data/lib/geocoder/stores/mongo_base.rb +89 -0
  101. data/lib/geocoder/stores/mongo_mapper.rb +13 -0
  102. data/lib/geocoder/stores/mongoid.rb +13 -0
  103. data/lib/geocoder/version.rb +3 -0
  104. data/lib/hash_recursive_merge.rb +74 -0
  105. data/lib/maxmind_database.rb +109 -0
  106. data/lib/oauth_util.rb +112 -0
  107. data/lib/tasks/geocoder.rake +29 -0
  108. data/lib/tasks/maxmind.rake +73 -0
  109. data/test/fixtures/baidu_invalid_key +1 -0
  110. data/test/fixtures/baidu_ip_202_198_16_3 +19 -0
  111. data/test/fixtures/baidu_ip_invalid_key +1 -0
  112. data/test/fixtures/baidu_ip_no_results +1 -0
  113. data/test/fixtures/baidu_no_results +1 -0
  114. data/test/fixtures/baidu_reverse +1 -0
  115. data/test/fixtures/baidu_shanghai_pearl_tower +12 -0
  116. data/test/fixtures/bing_invalid_key +1 -0
  117. data/test/fixtures/bing_madison_square_garden +40 -0
  118. data/test/fixtures/bing_no_results +16 -0
  119. data/test/fixtures/bing_reverse +42 -0
  120. data/test/fixtures/cloudmade_invalid_key +1 -0
  121. data/test/fixtures/cloudmade_madison_square_garden +1 -0
  122. data/test/fixtures/cloudmade_no_results +1 -0
  123. data/test/fixtures/esri_madison_square_garden +59 -0
  124. data/test/fixtures/esri_no_results +8 -0
  125. data/test/fixtures/esri_reverse +21 -0
  126. data/test/fixtures/freegeoip_74_200_247_59 +12 -0
  127. data/test/fixtures/freegeoip_no_results +1 -0
  128. data/test/fixtures/geocoder_ca_madison_square_garden +1 -0
  129. data/test/fixtures/geocoder_ca_no_results +1 -0
  130. data/test/fixtures/geocoder_ca_reverse +34 -0
  131. data/test/fixtures/geocoder_us_madison_square_garden +1 -0
  132. data/test/fixtures/geocoder_us_no_results +1 -0
  133. data/test/fixtures/geocodio_1101_pennsylvania_ave +1 -0
  134. data/test/fixtures/geocodio_bad_api_key +3 -0
  135. data/test/fixtures/geocodio_invalid +4 -0
  136. data/test/fixtures/geocodio_no_results +1 -0
  137. data/test/fixtures/geocodio_over_query_limit +4 -0
  138. data/test/fixtures/google_garbage +456 -0
  139. data/test/fixtures/google_madison_square_garden +57 -0
  140. data/test/fixtures/google_no_city_data +44 -0
  141. data/test/fixtures/google_no_locality +51 -0
  142. data/test/fixtures/google_no_results +4 -0
  143. data/test/fixtures/google_over_limit +4 -0
  144. data/test/fixtures/google_places_details_invalid_request +4 -0
  145. data/test/fixtures/google_places_details_madison_square_garden +120 -0
  146. data/test/fixtures/google_places_details_no_results +4 -0
  147. data/test/fixtures/google_places_details_no_reviews +60 -0
  148. data/test/fixtures/google_places_details_no_types +66 -0
  149. data/test/fixtures/here_madison_square_garden +72 -0
  150. data/test/fixtures/here_no_results +8 -0
  151. data/test/fixtures/mapquest_error +16 -0
  152. data/test/fixtures/mapquest_invalid_api_key +16 -0
  153. data/test/fixtures/mapquest_invalid_request +16 -0
  154. data/test/fixtures/mapquest_madison_square_garden +52 -0
  155. data/test/fixtures/mapquest_no_results +16 -0
  156. data/test/fixtures/maxmind_24_24_24_21 +1 -0
  157. data/test/fixtures/maxmind_24_24_24_22 +1 -0
  158. data/test/fixtures/maxmind_24_24_24_23 +1 -0
  159. data/test/fixtures/maxmind_24_24_24_24 +1 -0
  160. data/test/fixtures/maxmind_74_200_247_59 +1 -0
  161. data/test/fixtures/maxmind_invalid_key +1 -0
  162. data/test/fixtures/maxmind_no_results +1 -0
  163. data/test/fixtures/nominatim_madison_square_garden +150 -0
  164. data/test/fixtures/nominatim_no_results +1 -0
  165. data/test/fixtures/nominatim_over_limit +1 -0
  166. data/test/fixtures/okf_kirstinmaki +67 -0
  167. data/test/fixtures/okf_no_results +4 -0
  168. data/test/fixtures/opencagedata_invalid_api_key +25 -0
  169. data/test/fixtures/opencagedata_invalid_request +26 -0
  170. data/test/fixtures/opencagedata_madison_square_garden +73 -0
  171. data/test/fixtures/opencagedata_no_results +29 -0
  172. data/test/fixtures/opencagedata_over_limit +31 -0
  173. data/test/fixtures/ovi_madison_square_garden +72 -0
  174. data/test/fixtures/ovi_no_results +8 -0
  175. data/test/fixtures/pointpin_10_10_10_10 +1 -0
  176. data/test/fixtures/pointpin_555_555_555_555 +1 -0
  177. data/test/fixtures/pointpin_80_111_555_555 +1 -0
  178. data/test/fixtures/pointpin_no_results +1 -0
  179. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_WR26NJ +1 -0
  180. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_generic_error +1 -0
  181. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_hampshire +1 -0
  182. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_key_limit_exceeded +1 -0
  183. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_no_results +1 -0
  184. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_romsey +1 -0
  185. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_unknown_key +1 -0
  186. data/test/fixtures/smarty_streets_11211 +1 -0
  187. data/test/fixtures/smarty_streets_madison_square_garden +47 -0
  188. data/test/fixtures/smarty_streets_no_results +1 -0
  189. data/test/fixtures/telize_10_10_10_10 +1 -0
  190. data/test/fixtures/telize_555_555_555_555 +4 -0
  191. data/test/fixtures/telize_74_200_247_59 +1 -0
  192. data/test/fixtures/telize_no_results +1 -0
  193. data/test/fixtures/yahoo_error +1 -0
  194. data/test/fixtures/yahoo_invalid_key +2 -0
  195. data/test/fixtures/yahoo_madison_square_garden +52 -0
  196. data/test/fixtures/yahoo_no_results +10 -0
  197. data/test/fixtures/yahoo_over_limit +2 -0
  198. data/test/fixtures/yandex_canada_rue_dupuis_14 +446 -0
  199. data/test/fixtures/yandex_invalid_key +1 -0
  200. data/test/fixtures/yandex_kremlin +48 -0
  201. data/test/fixtures/yandex_new_york +1 -0
  202. data/test/fixtures/yandex_no_city_and_town +112 -0
  203. data/test/fixtures/yandex_no_results +16 -0
  204. data/test/integration/http_client_test.rb +31 -0
  205. data/test/mongoid_test_helper.rb +43 -0
  206. data/test/test_helper.rb +416 -0
  207. data/test/unit/active_record_test.rb +16 -0
  208. data/test/unit/cache_test.rb +37 -0
  209. data/test/unit/calculations_test.rb +220 -0
  210. data/test/unit/configuration_test.rb +55 -0
  211. data/test/unit/error_handling_test.rb +56 -0
  212. data/test/unit/geocoder_test.rb +78 -0
  213. data/test/unit/https_test.rb +17 -0
  214. data/test/unit/ip_address_test.rb +27 -0
  215. data/test/unit/lookup_test.rb +153 -0
  216. data/test/unit/lookups/bing_test.rb +68 -0
  217. data/test/unit/lookups/dstk_test.rb +26 -0
  218. data/test/unit/lookups/esri_test.rb +48 -0
  219. data/test/unit/lookups/freegeoip_test.rb +27 -0
  220. data/test/unit/lookups/geocoder_ca_test.rb +17 -0
  221. data/test/unit/lookups/geocodio_test.rb +55 -0
  222. data/test/unit/lookups/geoip2_test.rb +27 -0
  223. data/test/unit/lookups/google_places_details_test.rb +122 -0
  224. data/test/unit/lookups/google_premier_test.rb +22 -0
  225. data/test/unit/lookups/google_test.rb +84 -0
  226. data/test/unit/lookups/mapquest_test.rb +60 -0
  227. data/test/unit/lookups/maxmind_local_test.rb +28 -0
  228. data/test/unit/lookups/maxmind_test.rb +63 -0
  229. data/test/unit/lookups/nominatim_test.rb +31 -0
  230. data/test/unit/lookups/okf_test.rb +38 -0
  231. data/test/unit/lookups/opencagedata_test.rb +64 -0
  232. data/test/unit/lookups/pointpin_test.rb +30 -0
  233. data/test/unit/lookups/postcode_anywhere_uk_test.rb +70 -0
  234. data/test/unit/lookups/smarty_streets_test.rb +71 -0
  235. data/test/unit/lookups/telize_test.rb +36 -0
  236. data/test/unit/lookups/yahoo_test.rb +35 -0
  237. data/test/unit/method_aliases_test.rb +26 -0
  238. data/test/unit/model_test.rb +38 -0
  239. data/test/unit/mongoid_test.rb +47 -0
  240. data/test/unit/near_test.rb +87 -0
  241. data/test/unit/oauth_util_test.rb +31 -0
  242. data/test/unit/proxy_test.rb +37 -0
  243. data/test/unit/query_test.rb +52 -0
  244. data/test/unit/rake_task_test.rb +21 -0
  245. data/test/unit/request_test.rb +35 -0
  246. data/test/unit/result_test.rb +72 -0
  247. data/test/unit/test_mode_test.rb +70 -0
  248. metadata +294 -0
@@ -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,39 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/geocoder_us"
3
+
4
+ module Geocoder::Lookup
5
+ class GeocoderUs < Base
6
+
7
+ def name
8
+ "Geocoder.us"
9
+ end
10
+
11
+ def query_url(query)
12
+ if configuration.api_key
13
+ "http://#{configuration.api_key}@geocoder.us/member/service/csv/geocode?" + url_query_string(query)
14
+ else
15
+ "http://geocoder.us/service/csv/geocode?" + url_query_string(query)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def results(query)
22
+ return [] unless doc = fetch_data(query)
23
+ if doc[0].to_s =~ /^(\d+)\:/
24
+ return []
25
+ else
26
+ return [doc.size == 5 ? ((doc[0..1] << nil) + doc[2..4]) : doc]
27
+ end
28
+ end
29
+
30
+ def query_url_params(query)
31
+ (query.text =~ /^\d{5}(?:-\d{4})?$/ ? {:zip => query} : {:address => query.sanitized_text}).merge(super)
32
+ end
33
+
34
+ def parse_raw_data(raw_data)
35
+ raw_data.chomp.split(',')
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,42 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/geocodio"
3
+
4
+ module Geocoder::Lookup
5
+ class Geocodio < Base
6
+
7
+ def name
8
+ "Geocodio"
9
+ end
10
+
11
+ def query_url(query)
12
+ path = query.reverse_geocode? ? "reverse" : "geocode"
13
+ "#{protocol}://api.geocod.io/v1/#{path}?#{url_query_string(query)}"
14
+ end
15
+
16
+ def results(query)
17
+ return [] unless doc = fetch_data(query)
18
+ return doc["results"] if doc['error'].nil?
19
+
20
+ if doc['error'] == 'Invalid API key'
21
+ raise_error(Geocoder::InvalidApiKey) ||
22
+ warn("Geocodio service error: invalid API key.")
23
+ elsif doc['error'].match(/You have reached your daily maximum/)
24
+ raise_error(Geocoder::OverQueryLimitError, doc['error']) ||
25
+ warn("Geocodio service error: #{doc['error']}.")
26
+ else
27
+ raise_error(Geocoder::InvalidRequest, doc['error']) ||
28
+ warn("Geocodio service error: #{doc['error']}.")
29
+ end
30
+ []
31
+ end
32
+
33
+ private # ---------------------------------------------------------------
34
+
35
+ def query_url_params(query)
36
+ {
37
+ :api_key => configuration.api_key,
38
+ :q => query.sanitized_text
39
+ }.merge(super)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,40 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/geoip2'
3
+
4
+ module Geocoder
5
+ module Lookup
6
+ class Geoip2 < Base
7
+ def initialize
8
+ unless configuration[:file].nil?
9
+ begin
10
+ @gem_name = configuration[:lib] || 'maxminddb'
11
+ require @gem_name
12
+ rescue LoadError
13
+ raise "Could not load Maxmind DB dependency. To use the GeoIP2 lookup you must add the #{@gem_name} gem to your Gemfile or have it installed in your system."
14
+ end
15
+ end
16
+ super
17
+ end
18
+
19
+ def name
20
+ 'GeoIP2'
21
+ end
22
+
23
+ def required_api_key_parts
24
+ []
25
+ end
26
+
27
+ private
28
+
29
+ def results(query)
30
+ return [] unless configuration[:file]
31
+ if @gem_name == 'hive_geoip2'
32
+ result = Hive::GeoIP2.lookup(query.to_s, configuration[:file].to_s)
33
+ else
34
+ result = MaxMindDB.new(configuration[:file].to_s).lookup(query.to_s)
35
+ end
36
+ result.nil? ? [] : [result]
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,67 @@
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 valid_response?(response)
22
+ status = parse_json(response.body)["status"]
23
+ super(response) and ['OK', 'ZERO_RESULTS'].include?(status)
24
+ end
25
+
26
+ def results(query)
27
+ return [] unless doc = fetch_data(query)
28
+ case doc['status']; when "OK" # OK status implies >0 results
29
+ return doc['results']
30
+ when "OVER_QUERY_LIMIT"
31
+ raise_error(Geocoder::OverQueryLimitError) ||
32
+ warn("Google Geocoding API error: over query limit.")
33
+ when "REQUEST_DENIED"
34
+ raise_error(Geocoder::RequestDenied) ||
35
+ warn("Google Geocoding API error: request denied.")
36
+ when "INVALID_REQUEST"
37
+ raise_error(Geocoder::InvalidRequest) ||
38
+ warn("Google Geocoding API error: invalid request.")
39
+ end
40
+ return []
41
+ end
42
+
43
+ def query_url_google_params(query)
44
+ params = {
45
+ (query.reverse_geocode? ? :latlng : :address) => query.sanitized_text,
46
+ :sensor => "false",
47
+ :language => (query.language || configuration.language)
48
+ }
49
+ unless (bounds = query.options[:bounds]).nil?
50
+ params[:bounds] = bounds.map{ |point| "%f,%f" % point }.join('|')
51
+ end
52
+ unless (region = query.options[:region]).nil?
53
+ params[:region] = region
54
+ end
55
+ unless (components = query.options[:components]).nil?
56
+ params[:components] = components.is_a?(Array) ? components.join("|") : components
57
+ end
58
+ params
59
+ end
60
+
61
+ def query_url_params(query)
62
+ query_url_google_params(query).merge(
63
+ :key => configuration.api_key
64
+ ).merge(super)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,50 @@
1
+ require "geocoder/lookups/google"
2
+ require "geocoder/results/google_places_details"
3
+
4
+ module Geocoder
5
+ module Lookup
6
+ class GooglePlacesDetails < Google
7
+ def name
8
+ "Google Places Details"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ["key"]
13
+ end
14
+
15
+ def use_ssl?
16
+ true
17
+ end
18
+
19
+ def query_url(query)
20
+ "#{protocol}://maps.googleapis.com/maps/api/place/details/json?#{url_query_string(query)}"
21
+ end
22
+
23
+ private
24
+
25
+ def results(query)
26
+ return [] unless doc = fetch_data(query)
27
+
28
+ case doc["status"]
29
+ when "OK"
30
+ return [doc["result"]]
31
+ when "OVER_QUERY_LIMIT"
32
+ raise_error(Geocoder::OverQueryLimitError) || warn("Google Places Details API error: over query limit.")
33
+ when "REQUEST_DENIED"
34
+ raise_error(Geocoder::RequestDenied) || warn("Google Places Details API error: request denied.")
35
+ when "INVALID_REQUEST"
36
+ raise_error(Geocoder::InvalidRequest) || warn("Google Places Details API error: invalid request.")
37
+ end
38
+
39
+ []
40
+ end
41
+
42
+ def query_url_google_params(query)
43
+ {
44
+ placeid: query.text,
45
+ language: query.language || configuration.language
46
+ }
47
+ end
48
+ end
49
+ end
50
+ 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.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,62 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/here'
3
+
4
+ module Geocoder::Lookup
5
+ class Here < Base
6
+
7
+ def name
8
+ "Here"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ []
13
+ end
14
+
15
+ def query_url(query)
16
+ "#{protocol}://#{if query.reverse_geocode? then 'reverse.' end}geocoder.api.here.com/6.2/#{if query.reverse_geocode? then 'reverse' end}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
+ options = {
33
+ :gen=>4,
34
+ :app_id=>api_key,
35
+ :app_code=>api_code
36
+ }
37
+
38
+ if query.reverse_geocode?
39
+ super.merge(options).merge(
40
+ :prox=>query.sanitized_text,
41
+ :mode=>:retrieveAddresses
42
+ )
43
+ else
44
+ super.merge(options).merge(
45
+ :searchtext=>query.sanitized_text
46
+ )
47
+ end
48
+ end
49
+
50
+ def api_key
51
+ if a=configuration.api_key
52
+ return a.first if a.is_a?(Array)
53
+ end
54
+ end
55
+
56
+ def api_code
57
+ if a=configuration.api_key
58
+ return a.last if a.is_a?(Array)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,60 @@
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
+ ["key"]
14
+ end
15
+
16
+ def query_url(query)
17
+ domain = configuration[:open] ? "open" : "www"
18
+ version = configuration[:version] || 1
19
+ url = "#{protocol}://#{domain}.mapquestapi.com/geocoding/v#{version}/#{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
+ # http://www.mapquestapi.com/geocoding/status_codes.html
38
+ # http://open.mapquestapi.com/geocoding/status_codes.html
39
+ def results(query)
40
+ return [] unless doc = fetch_data(query)
41
+ return doc["results"][0]['locations'] if doc['info']['statuscode'] == 0 # A successful geocode call
42
+
43
+ messages = doc['info']['messages'].join
44
+
45
+ case doc['info']['statuscode']
46
+ when 400 # Error with input
47
+ raise_error(Geocoder::InvalidRequest, messages) ||
48
+ warn("Mapquest Geocoding API error: #{messages}")
49
+ when 403 # Key related error
50
+ raise_error(Geocoder::InvalidApiKey, messages) ||
51
+ warn("Mapquest Geocoding API error: #{messages}")
52
+ when 500 # Unknown error
53
+ raise_error(Geocoder::Error, messages) ||
54
+ warn("Mapquest Geocoding API error: #{messages}")
55
+ end
56
+ []
57
+ end
58
+
59
+ end
60
+ end