geocoder 1.2.6 → 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 (276) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +189 -1
  3. data/LICENSE +1 -1
  4. data/README.md +387 -755
  5. data/examples/autoexpire_cache_redis.rb +5 -3
  6. data/examples/reverse_geocode_job.rb +40 -0
  7. data/lib/generators/geocoder/config/templates/initializer.rb +17 -16
  8. data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +2 -0
  9. data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +2 -0
  10. data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +1 -1
  11. data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +1 -1
  12. data/lib/generators/geocoder/migration_version.rb +15 -0
  13. data/lib/geocoder/cache.rb +6 -2
  14. data/lib/geocoder/calculations.rb +30 -38
  15. data/lib/geocoder/cli.rb +2 -2
  16. data/lib/geocoder/configuration.rb +18 -5
  17. data/lib/geocoder/esri_token.rb +38 -0
  18. data/lib/geocoder/exceptions.rb +19 -0
  19. data/lib/geocoder/ip_address.rb +16 -11
  20. data/lib/geocoder/kernel_logger.rb +25 -0
  21. data/lib/geocoder/logger.rb +47 -0
  22. data/lib/geocoder/lookup.rb +31 -12
  23. data/lib/geocoder/lookups/amap.rb +63 -0
  24. data/lib/geocoder/lookups/baidu.rb +17 -9
  25. data/lib/geocoder/lookups/baidu_ip.rb +7 -31
  26. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +143 -0
  27. data/lib/geocoder/lookups/base.rb +73 -25
  28. data/lib/geocoder/lookups/bing.rb +38 -15
  29. data/lib/geocoder/lookups/db_ip_com.rb +52 -0
  30. data/lib/geocoder/lookups/dstk.rb +4 -2
  31. data/lib/geocoder/lookups/esri.rb +55 -8
  32. data/lib/geocoder/lookups/freegeoip.rb +18 -5
  33. data/lib/geocoder/lookups/geocoder_ca.rb +5 -6
  34. data/lib/geocoder/lookups/geocodio.rb +8 -8
  35. data/lib/geocoder/lookups/geoip2.rb +10 -5
  36. data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
  37. data/lib/geocoder/lookups/google.rb +37 -9
  38. data/lib/geocoder/lookups/google_places_details.rb +9 -9
  39. data/lib/geocoder/lookups/google_places_search.rb +33 -0
  40. data/lib/geocoder/lookups/google_premier.rb +11 -1
  41. data/lib/geocoder/lookups/here.rb +29 -23
  42. data/lib/geocoder/lookups/ip2location.rb +67 -0
  43. data/lib/geocoder/lookups/ipapi_com.rb +82 -0
  44. data/lib/geocoder/lookups/ipdata_co.rb +62 -0
  45. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  46. data/lib/geocoder/lookups/ipinfo_io.rb +44 -0
  47. data/lib/geocoder/lookups/ipregistry.rb +68 -0
  48. data/lib/geocoder/lookups/ipstack.rb +63 -0
  49. data/lib/geocoder/lookups/latlon.rb +59 -0
  50. data/lib/geocoder/lookups/location_iq.rb +50 -0
  51. data/lib/geocoder/lookups/mapbox.rb +59 -0
  52. data/lib/geocoder/lookups/mapquest.rb +7 -9
  53. data/lib/geocoder/lookups/maxmind.rb +7 -7
  54. data/lib/geocoder/lookups/maxmind_geoip2.rb +70 -0
  55. data/lib/geocoder/lookups/maxmind_local.rb +9 -2
  56. data/lib/geocoder/lookups/nominatim.rb +18 -6
  57. data/lib/geocoder/lookups/opencagedata.rb +16 -9
  58. data/lib/geocoder/lookups/osmnames.rb +57 -0
  59. data/lib/geocoder/lookups/pelias.rb +63 -0
  60. data/lib/geocoder/lookups/pickpoint.rb +41 -0
  61. data/lib/geocoder/lookups/pointpin.rb +14 -13
  62. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +7 -8
  63. data/lib/geocoder/lookups/postcodes_io.rb +31 -0
  64. data/lib/geocoder/lookups/smarty_streets.rb +23 -5
  65. data/lib/geocoder/lookups/telize.rb +42 -7
  66. data/lib/geocoder/lookups/tencent.rb +59 -0
  67. data/lib/geocoder/lookups/yandex.rb +17 -9
  68. data/lib/geocoder/models/active_record.rb +4 -3
  69. data/lib/geocoder/models/mongo_base.rb +0 -2
  70. data/lib/geocoder/query.rb +15 -1
  71. data/lib/geocoder/railtie.rb +1 -1
  72. data/lib/geocoder/request.rb +103 -14
  73. data/lib/geocoder/results/amap.rb +87 -0
  74. data/lib/geocoder/results/baidu.rb +10 -14
  75. data/lib/geocoder/results/ban_data_gouv_fr.rb +257 -0
  76. data/lib/geocoder/results/base.rb +13 -1
  77. data/lib/geocoder/results/bing.rb +5 -1
  78. data/lib/geocoder/results/db_ip_com.rb +58 -0
  79. data/lib/geocoder/results/esri.rb +30 -6
  80. data/lib/geocoder/results/freegeoip.rb +2 -7
  81. data/lib/geocoder/results/geocoder_ca.rb +3 -3
  82. data/lib/geocoder/results/geocodio.rb +15 -3
  83. data/lib/geocoder/results/geoip2.rb +37 -25
  84. data/lib/geocoder/results/geoportail_lu.rb +71 -0
  85. data/lib/geocoder/results/google.rb +26 -0
  86. data/lib/geocoder/results/google_places_details.rb +4 -0
  87. data/lib/geocoder/results/google_places_search.rb +52 -0
  88. data/lib/geocoder/results/here.rb +21 -1
  89. data/lib/geocoder/results/ip2location.rb +22 -0
  90. data/lib/geocoder/results/ipapi_com.rb +45 -0
  91. data/lib/geocoder/results/ipdata_co.rb +40 -0
  92. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  93. data/lib/geocoder/results/ipinfo_io.rb +48 -0
  94. data/lib/geocoder/results/ipregistry.rb +308 -0
  95. data/lib/geocoder/results/ipstack.rb +60 -0
  96. data/lib/geocoder/results/latlon.rb +71 -0
  97. data/lib/geocoder/results/location_iq.rb +6 -0
  98. data/lib/geocoder/results/mapbox.rb +57 -0
  99. data/lib/geocoder/results/mapquest.rb +5 -8
  100. data/lib/geocoder/results/maxmind.rb +0 -5
  101. data/lib/geocoder/results/maxmind_geoip2.rb +9 -0
  102. data/lib/geocoder/results/maxmind_local.rb +0 -5
  103. data/lib/geocoder/results/nominatim.rb +18 -3
  104. data/lib/geocoder/results/opencagedata.rb +20 -2
  105. data/lib/geocoder/results/osmnames.rb +56 -0
  106. data/lib/geocoder/results/pelias.rb +58 -0
  107. data/lib/geocoder/results/pickpoint.rb +6 -0
  108. data/lib/geocoder/results/pointpin.rb +0 -4
  109. data/lib/geocoder/results/postcodes_io.rb +40 -0
  110. data/lib/geocoder/results/smarty_streets.rb +55 -19
  111. data/lib/geocoder/results/telize.rb +0 -5
  112. data/lib/geocoder/results/tencent.rb +72 -0
  113. data/lib/geocoder/results/test.rb +1 -1
  114. data/lib/geocoder/results/yandex.rb +57 -7
  115. data/lib/geocoder/sql.rb +9 -6
  116. data/lib/geocoder/stores/active_record.rb +49 -10
  117. data/lib/geocoder/stores/base.rb +2 -14
  118. data/lib/geocoder/stores/mongo_base.rb +0 -31
  119. data/lib/geocoder/version.rb +1 -1
  120. data/lib/geocoder.rb +2 -1
  121. data/lib/hash_recursive_merge.rb +1 -2
  122. data/lib/maxmind_database.rb +4 -4
  123. data/lib/tasks/geocoder.rake +29 -4
  124. metadata +56 -159
  125. data/.gitignore +0 -6
  126. data/.travis.yml +0 -31
  127. data/Rakefile +0 -25
  128. data/gemfiles/Gemfile.mongoid-2.4.x +0 -16
  129. data/lib/geocoder/lookups/geocoder_us.rb +0 -39
  130. data/lib/geocoder/lookups/okf.rb +0 -43
  131. data/lib/geocoder/lookups/ovi.rb +0 -62
  132. data/lib/geocoder/lookups/yahoo.rb +0 -88
  133. data/lib/geocoder/results/geocoder_us.rb +0 -39
  134. data/lib/geocoder/results/okf.rb +0 -106
  135. data/lib/geocoder/results/ovi.rb +0 -62
  136. data/lib/geocoder/results/yahoo.rb +0 -55
  137. data/lib/oauth_util.rb +0 -112
  138. data/test/fixtures/baidu_invalid_key +0 -1
  139. data/test/fixtures/baidu_ip_202_198_16_3 +0 -19
  140. data/test/fixtures/baidu_ip_invalid_key +0 -1
  141. data/test/fixtures/baidu_ip_no_results +0 -1
  142. data/test/fixtures/baidu_no_results +0 -1
  143. data/test/fixtures/baidu_reverse +0 -1
  144. data/test/fixtures/baidu_shanghai_pearl_tower +0 -12
  145. data/test/fixtures/bing_invalid_key +0 -1
  146. data/test/fixtures/bing_madison_square_garden +0 -40
  147. data/test/fixtures/bing_no_results +0 -16
  148. data/test/fixtures/bing_reverse +0 -42
  149. data/test/fixtures/cloudmade_invalid_key +0 -1
  150. data/test/fixtures/cloudmade_madison_square_garden +0 -1
  151. data/test/fixtures/cloudmade_no_results +0 -1
  152. data/test/fixtures/esri_madison_square_garden +0 -59
  153. data/test/fixtures/esri_no_results +0 -8
  154. data/test/fixtures/esri_reverse +0 -21
  155. data/test/fixtures/freegeoip_74_200_247_59 +0 -12
  156. data/test/fixtures/freegeoip_no_results +0 -1
  157. data/test/fixtures/geocoder_ca_madison_square_garden +0 -1
  158. data/test/fixtures/geocoder_ca_no_results +0 -1
  159. data/test/fixtures/geocoder_ca_reverse +0 -34
  160. data/test/fixtures/geocoder_us_madison_square_garden +0 -1
  161. data/test/fixtures/geocoder_us_no_results +0 -1
  162. data/test/fixtures/geocodio_1101_pennsylvania_ave +0 -1
  163. data/test/fixtures/geocodio_bad_api_key +0 -3
  164. data/test/fixtures/geocodio_invalid +0 -4
  165. data/test/fixtures/geocodio_no_results +0 -1
  166. data/test/fixtures/geocodio_over_query_limit +0 -4
  167. data/test/fixtures/google_garbage +0 -456
  168. data/test/fixtures/google_madison_square_garden +0 -57
  169. data/test/fixtures/google_no_city_data +0 -44
  170. data/test/fixtures/google_no_locality +0 -51
  171. data/test/fixtures/google_no_results +0 -4
  172. data/test/fixtures/google_over_limit +0 -4
  173. data/test/fixtures/google_places_details_invalid_request +0 -4
  174. data/test/fixtures/google_places_details_madison_square_garden +0 -120
  175. data/test/fixtures/google_places_details_no_results +0 -4
  176. data/test/fixtures/google_places_details_no_reviews +0 -60
  177. data/test/fixtures/google_places_details_no_types +0 -66
  178. data/test/fixtures/here_madison_square_garden +0 -72
  179. data/test/fixtures/here_no_results +0 -8
  180. data/test/fixtures/mapquest_error +0 -16
  181. data/test/fixtures/mapquest_invalid_api_key +0 -16
  182. data/test/fixtures/mapquest_invalid_request +0 -16
  183. data/test/fixtures/mapquest_madison_square_garden +0 -52
  184. data/test/fixtures/mapquest_no_results +0 -16
  185. data/test/fixtures/maxmind_24_24_24_21 +0 -1
  186. data/test/fixtures/maxmind_24_24_24_22 +0 -1
  187. data/test/fixtures/maxmind_24_24_24_23 +0 -1
  188. data/test/fixtures/maxmind_24_24_24_24 +0 -1
  189. data/test/fixtures/maxmind_74_200_247_59 +0 -1
  190. data/test/fixtures/maxmind_invalid_key +0 -1
  191. data/test/fixtures/maxmind_no_results +0 -1
  192. data/test/fixtures/nominatim_madison_square_garden +0 -150
  193. data/test/fixtures/nominatim_no_results +0 -1
  194. data/test/fixtures/nominatim_over_limit +0 -1
  195. data/test/fixtures/okf_kirstinmaki +0 -67
  196. data/test/fixtures/okf_no_results +0 -4
  197. data/test/fixtures/opencagedata_invalid_api_key +0 -25
  198. data/test/fixtures/opencagedata_invalid_request +0 -26
  199. data/test/fixtures/opencagedata_madison_square_garden +0 -73
  200. data/test/fixtures/opencagedata_no_results +0 -29
  201. data/test/fixtures/opencagedata_over_limit +0 -31
  202. data/test/fixtures/ovi_madison_square_garden +0 -72
  203. data/test/fixtures/ovi_no_results +0 -8
  204. data/test/fixtures/pointpin_10_10_10_10 +0 -1
  205. data/test/fixtures/pointpin_555_555_555_555 +0 -1
  206. data/test/fixtures/pointpin_80_111_555_555 +0 -1
  207. data/test/fixtures/pointpin_no_results +0 -1
  208. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_WR26NJ +0 -1
  209. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_generic_error +0 -1
  210. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_hampshire +0 -1
  211. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_key_limit_exceeded +0 -1
  212. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_no_results +0 -1
  213. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_romsey +0 -1
  214. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_unknown_key +0 -1
  215. data/test/fixtures/smarty_streets_11211 +0 -1
  216. data/test/fixtures/smarty_streets_madison_square_garden +0 -47
  217. data/test/fixtures/smarty_streets_no_results +0 -1
  218. data/test/fixtures/telize_10_10_10_10 +0 -1
  219. data/test/fixtures/telize_555_555_555_555 +0 -4
  220. data/test/fixtures/telize_74_200_247_59 +0 -1
  221. data/test/fixtures/telize_no_results +0 -1
  222. data/test/fixtures/yahoo_error +0 -1
  223. data/test/fixtures/yahoo_invalid_key +0 -2
  224. data/test/fixtures/yahoo_madison_square_garden +0 -52
  225. data/test/fixtures/yahoo_no_results +0 -10
  226. data/test/fixtures/yahoo_over_limit +0 -2
  227. data/test/fixtures/yandex_canada_rue_dupuis_14 +0 -446
  228. data/test/fixtures/yandex_invalid_key +0 -1
  229. data/test/fixtures/yandex_kremlin +0 -48
  230. data/test/fixtures/yandex_new_york +0 -1
  231. data/test/fixtures/yandex_no_city_and_town +0 -112
  232. data/test/fixtures/yandex_no_results +0 -16
  233. data/test/integration/http_client_test.rb +0 -31
  234. data/test/mongoid_test_helper.rb +0 -43
  235. data/test/test_helper.rb +0 -416
  236. data/test/unit/active_record_test.rb +0 -16
  237. data/test/unit/cache_test.rb +0 -37
  238. data/test/unit/calculations_test.rb +0 -220
  239. data/test/unit/configuration_test.rb +0 -55
  240. data/test/unit/error_handling_test.rb +0 -56
  241. data/test/unit/geocoder_test.rb +0 -78
  242. data/test/unit/https_test.rb +0 -17
  243. data/test/unit/ip_address_test.rb +0 -27
  244. data/test/unit/lookup_test.rb +0 -153
  245. data/test/unit/lookups/bing_test.rb +0 -68
  246. data/test/unit/lookups/dstk_test.rb +0 -26
  247. data/test/unit/lookups/esri_test.rb +0 -48
  248. data/test/unit/lookups/freegeoip_test.rb +0 -27
  249. data/test/unit/lookups/geocoder_ca_test.rb +0 -17
  250. data/test/unit/lookups/geocodio_test.rb +0 -55
  251. data/test/unit/lookups/geoip2_test.rb +0 -27
  252. data/test/unit/lookups/google_places_details_test.rb +0 -122
  253. data/test/unit/lookups/google_premier_test.rb +0 -22
  254. data/test/unit/lookups/google_test.rb +0 -84
  255. data/test/unit/lookups/mapquest_test.rb +0 -60
  256. data/test/unit/lookups/maxmind_local_test.rb +0 -28
  257. data/test/unit/lookups/maxmind_test.rb +0 -63
  258. data/test/unit/lookups/nominatim_test.rb +0 -31
  259. data/test/unit/lookups/okf_test.rb +0 -38
  260. data/test/unit/lookups/opencagedata_test.rb +0 -64
  261. data/test/unit/lookups/pointpin_test.rb +0 -30
  262. data/test/unit/lookups/postcode_anywhere_uk_test.rb +0 -70
  263. data/test/unit/lookups/smarty_streets_test.rb +0 -71
  264. data/test/unit/lookups/telize_test.rb +0 -36
  265. data/test/unit/lookups/yahoo_test.rb +0 -35
  266. data/test/unit/method_aliases_test.rb +0 -26
  267. data/test/unit/model_test.rb +0 -38
  268. data/test/unit/mongoid_test.rb +0 -47
  269. data/test/unit/near_test.rb +0 -87
  270. data/test/unit/oauth_util_test.rb +0 -31
  271. data/test/unit/proxy_test.rb +0 -37
  272. data/test/unit/query_test.rb +0 -52
  273. data/test/unit/rake_task_test.rb +0 -21
  274. data/test/unit/request_test.rb +0 -35
  275. data/test/unit/result_test.rb +0 -72
  276. data/test/unit/test_mode_test.rb +0 -70
@@ -0,0 +1,56 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Osmnames < Base
5
+ def address
6
+ @data['display_name']
7
+ end
8
+
9
+ def coordinates
10
+ [@data['lat'].to_f, @data['lon'].to_f]
11
+ end
12
+
13
+ def viewport
14
+ west, south, east, north = @data['boundingbox'].map(&:to_f)
15
+ [south, west, north, east]
16
+ end
17
+
18
+ def state
19
+ @data['state']
20
+ end
21
+ alias_method :state_code, :state
22
+
23
+ def place_class
24
+ @data['class']
25
+ end
26
+
27
+ def place_type
28
+ @data['type']
29
+ end
30
+
31
+ def postal_code
32
+ ''
33
+ end
34
+
35
+ def country_code
36
+ @data['country_code']
37
+ end
38
+
39
+ def country
40
+ @data['country']
41
+ end
42
+
43
+ def self.response_attributes
44
+ %w[house_number street city name osm_id osm_type boundingbox place_rank
45
+ importance county rank name_suffix]
46
+ end
47
+
48
+ response_attributes.each do |a|
49
+ unless method_defined?(a)
50
+ define_method a do
51
+ @data[a]
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,58 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Pelias < Base
5
+ def address(format = :full)
6
+ properties['label']
7
+ end
8
+
9
+ def city
10
+ locality
11
+ end
12
+
13
+ def coordinates
14
+ geometry['coordinates'].reverse
15
+ end
16
+
17
+ def country_code
18
+ properties['country_a']
19
+ end
20
+
21
+ def postal_code
22
+ properties['postalcode'].to_s
23
+ end
24
+
25
+ def province
26
+ state
27
+ end
28
+
29
+ def state
30
+ properties['region']
31
+ end
32
+
33
+ def state_code
34
+ properties['region_a']
35
+ end
36
+
37
+ def self.response_attributes
38
+ %w[county confidence country gid id layer localadmin locality neighborhood]
39
+ end
40
+
41
+ response_attributes.each do |a|
42
+ define_method a do
43
+ properties[a]
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def geometry
50
+ @data.fetch('geometry', {})
51
+ end
52
+
53
+ def properties
54
+ @data.fetch('properties', {})
55
+ end
56
+ end
57
+ end
58
+
@@ -0,0 +1,6 @@
1
+ require 'geocoder/results/nominatim'
2
+
3
+ module Geocoder::Result
4
+ class Pickpoint < Nominatim
5
+ end
6
+ end
@@ -23,10 +23,6 @@ module Geocoder::Result
23
23
  @data['country_name']
24
24
  end
25
25
 
26
- def country_code
27
- @data['country_code']
28
- end
29
-
30
26
  def postal_code
31
27
  @data['postcode']
32
28
  end
@@ -0,0 +1,40 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class PostcodesIo < Base
5
+
6
+ def coordinates
7
+ [@data['latitude'].to_f, @data['longitude'].to_f]
8
+ end
9
+
10
+ def quality
11
+ @data['quality']
12
+ end
13
+
14
+ def postal_code
15
+ @data['postcode']
16
+ end
17
+ alias address postal_code
18
+
19
+ def city
20
+ @data['admin_ward']
21
+ end
22
+
23
+ def county
24
+ @data['admin_county']
25
+ end
26
+ alias state county
27
+
28
+ def state_code
29
+ @data['codes']['admin_county']
30
+ end
31
+
32
+ def country
33
+ 'United Kingdom'
34
+ end
35
+
36
+ def country_code
37
+ 'UK'
38
+ end
39
+ end
40
+ end
@@ -3,57 +3,89 @@ require 'geocoder/lookups/base'
3
3
  module Geocoder::Result
4
4
  class SmartyStreets < Base
5
5
  def coordinates
6
- %w(latitude longitude).map do |i|
6
+ result = %w(latitude longitude).map do |i|
7
7
  zipcode_endpoint? ? zipcodes.first[i] : metadata[i]
8
8
  end
9
+
10
+ if result.compact.empty?
11
+ nil
12
+ else
13
+ result
14
+ end
9
15
  end
10
16
 
11
17
  def address
12
- [
13
- delivery_line_1,
14
- delivery_line_2,
15
- last_line
16
- ].select{ |i| i.to_s != "" }.join(" ")
18
+ parts =
19
+ if international_endpoint?
20
+ (1..12).map { |i| @data["address#{i}"] }
21
+ else
22
+ [
23
+ delivery_line_1,
24
+ delivery_line_2,
25
+ last_line
26
+ ]
27
+ end
28
+ parts.select{ |i| i.to_s != "" }.join(" ")
17
29
  end
18
30
 
19
31
  def state
20
- zipcode_endpoint? ?
21
- city_states.first['state'] :
32
+ if international_endpoint?
33
+ components['administrative_area']
34
+ elsif zipcode_endpoint?
35
+ city_states.first['state']
36
+ else
22
37
  components['state_abbreviation']
38
+ end
23
39
  end
24
40
 
25
41
  def state_code
26
- zipcode_endpoint? ?
27
- city_states.first['state_abbreviation'] :
42
+ if international_endpoint?
43
+ components['administrative_area']
44
+ elsif zipcode_endpoint?
45
+ city_states.first['state_abbreviation']
46
+ else
28
47
  components['state_abbreviation']
48
+ end
29
49
  end
30
50
 
31
51
  def country
32
- # SmartyStreets returns results for USA only
33
- "United States"
52
+ international_endpoint? ?
53
+ components['country_iso_3'] :
54
+ "United States"
34
55
  end
35
56
 
36
57
  def country_code
37
- # SmartyStreets returns results for USA only
38
- "US"
58
+ international_endpoint? ?
59
+ components['country_iso_3'] :
60
+ "US"
39
61
  end
40
62
 
41
63
  ## Extra methods not in base.rb ------------------------
42
64
 
43
65
  def street
44
- components['street_name']
66
+ international_endpoint? ?
67
+ components['thoroughfare_name'] :
68
+ components['street_name']
45
69
  end
46
70
 
47
71
  def city
48
- zipcode_endpoint? ?
49
- city_states.first['city'] :
72
+ if international_endpoint?
73
+ components['locality']
74
+ elsif zipcode_endpoint?
75
+ city_states.first['city']
76
+ else
50
77
  components['city_name']
78
+ end
51
79
  end
52
80
 
53
81
  def zipcode
54
- zipcode_endpoint? ?
55
- zipcodes.first['zipcode'] :
82
+ if international_endpoint?
83
+ components['postal_code']
84
+ elsif zipcode_endpoint?
85
+ zipcodes.first['zipcode']
86
+ else
56
87
  components['zipcode']
88
+ end
57
89
  end
58
90
  alias_method :postal_code, :zipcode
59
91
 
@@ -72,6 +104,10 @@ module Geocoder::Result
72
104
  zipcodes.any?
73
105
  end
74
106
 
107
+ def international_endpoint?
108
+ !@data['address1'].nil?
109
+ end
110
+
75
111
  [
76
112
  :delivery_line_1,
77
113
  :delivery_line_2,
@@ -3,11 +3,6 @@ require 'geocoder/results/base'
3
3
  module Geocoder::Result
4
4
  class Telize < Base
5
5
 
6
- def address(format = :full)
7
- s = state_code.to_s == "" ? "" : ", #{state_code}"
8
- "#{city}#{s} #{postal_code}, #{country}".sub(/^[ ,]*/, "")
9
- end
10
-
11
6
  def city
12
7
  @data['city']
13
8
  end
@@ -0,0 +1,72 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Tencent < Base
5
+
6
+ def coordinates
7
+ ['lat', 'lng'].map{ |i| @data['location'][i] }
8
+ end
9
+
10
+ def address
11
+ "#{province}#{city}#{district}#{street}#{street_number}"
12
+
13
+ #@data['title'] or @data['address']
14
+ end
15
+
16
+ # NOTE: The Tencent reverse geocoding API has the field named
17
+ # 'address_component' compared to 'address_components' in the
18
+ # regular geocoding API.
19
+ def province
20
+ @data['address_components'] and (@data['address_components']['province']) or
21
+ (@data['address_component'] and @data['address_component']['province']) or
22
+ ""
23
+ end
24
+
25
+ alias_method :state, :province
26
+
27
+ def city
28
+ @data['address_components'] and (@data['address_components']['city']) or
29
+ (@data['address_component'] and @data['address_component']['city']) or
30
+ ""
31
+ end
32
+
33
+ def district
34
+ @data['address_components'] and (@data['address_components']['district']) or
35
+ (@data['address_component'] and @data['address_component']['district']) or
36
+ ""
37
+ end
38
+
39
+ def street
40
+ @data['address_components'] and (@data['address_components']['street']) or
41
+ (@data['address_component'] and @data['address_component']['street']) or
42
+ ""
43
+ end
44
+
45
+ def street_number
46
+ @data['address_components'] and (@data['address_components']['street_number']) or
47
+ (@data['address_component'] and @data['address_component']['street_number']) or
48
+ ""
49
+ end
50
+
51
+ def address_components
52
+ @data['address_components'] or @data['address_component']
53
+ end
54
+
55
+ def state_code
56
+ ""
57
+ end
58
+
59
+ def postal_code
60
+ ""
61
+ end
62
+
63
+ def country
64
+ "China"
65
+ end
66
+
67
+ def country_code
68
+ "CN"
69
+ end
70
+
71
+ end
72
+ end
@@ -15,7 +15,7 @@ module Geocoder
15
15
  end
16
16
  end
17
17
 
18
- %w[latitude longitude neighborhood city state state_code sub_state
18
+ %w[coordinates neighborhood city state state_code sub_state
19
19
  sub_state_code province province_code postal_code country
20
20
  country_code address street_address street_number route geometry].each do |attr|
21
21
  add_result_attribute(attr)
@@ -12,9 +12,10 @@ module Geocoder::Result
12
12
  end
13
13
 
14
14
  def city
15
- if state.empty? and address_details.has_key? 'Locality'
15
+ if state.empty? and address_details and address_details.has_key? 'Locality'
16
16
  address_details['Locality']['LocalityName']
17
- elsif sub_state.empty? and address_details['AdministrativeArea'].has_key? 'Locality'
17
+ elsif sub_state.empty? and address_details and address_details.has_key? 'AdministrativeArea' and
18
+ address_details['AdministrativeArea'].has_key? 'Locality'
18
19
  address_details['AdministrativeArea']['Locality']['LocalityName']
19
20
  elsif not sub_state_city.empty?
20
21
  sub_state_city
@@ -24,15 +25,23 @@ module Geocoder::Result
24
25
  end
25
26
 
26
27
  def country
27
- address_details['CountryName']
28
+ if address_details
29
+ address_details['CountryName']
30
+ else
31
+ ""
32
+ end
28
33
  end
29
34
 
30
35
  def country_code
31
- address_details['CountryNameCode']
36
+ if address_details
37
+ address_details['CountryNameCode']
38
+ else
39
+ ""
40
+ end
32
41
  end
33
42
 
34
43
  def state
35
- if address_details['AdministrativeArea']
44
+ if address_details and address_details['AdministrativeArea']
36
45
  address_details['AdministrativeArea']['AdministrativeAreaName']
37
46
  else
38
47
  ""
@@ -40,7 +49,7 @@ module Geocoder::Result
40
49
  end
41
50
 
42
51
  def sub_state
43
- if !state.empty? and address_details['AdministrativeArea']['SubAdministrativeArea']
52
+ if !state.empty? and address_details and address_details['AdministrativeArea']['SubAdministrativeArea']
44
53
  address_details['AdministrativeArea']['SubAdministrativeArea']['SubAdministrativeAreaName']
45
54
  else
46
55
  ""
@@ -59,6 +68,14 @@ module Geocoder::Result
59
68
  address_details['Locality']['Premise']['PremiseName']
60
69
  end
61
70
 
71
+ def street
72
+ thoroughfare_data && thoroughfare_data['ThoroughfareName']
73
+ end
74
+
75
+ def street_number
76
+ thoroughfare_data && thoroughfare_data['Premise'] && thoroughfare_data['Premise']['PremiseNumber']
77
+ end
78
+
62
79
  def kind
63
80
  @data['GeoObject']['metaDataProperty']['GeocoderMetaData']['kind']
64
81
  end
@@ -67,14 +84,47 @@ module Geocoder::Result
67
84
  @data['GeoObject']['metaDataProperty']['GeocoderMetaData']['precision']
68
85
  end
69
86
 
87
+ def viewport
88
+ envelope = @data['GeoObject']['boundedBy']['Envelope'] || fail
89
+ east, north = envelope['upperCorner'].split(' ').map(&:to_f)
90
+ west, south = envelope['lowerCorner'].split(' ').map(&:to_f)
91
+ [south, west, north, east]
92
+ end
93
+
70
94
  private # ----------------------------------------------------------------
71
95
 
96
+ def thoroughfare_data
97
+ locality_data && locality_data['Thoroughfare']
98
+ end
99
+
100
+ def locality_data
101
+ dependent_locality && subadmin_locality && admin_locality
102
+ end
103
+
104
+ def admin_locality
105
+ address_details && address_details['AdministrativeArea'] &&
106
+ address_details['AdministrativeArea']['Locality']
107
+ end
108
+
109
+ def subadmin_locality
110
+ address_details && address_details['AdministrativeArea'] &&
111
+ address_details['AdministrativeArea']['SubAdministrativeArea'] &&
112
+ address_details['AdministrativeArea']['SubAdministrativeArea']['Locality']
113
+ end
114
+
115
+ def dependent_locality
116
+ address_details && address_details['AdministrativeArea'] &&
117
+ address_details['AdministrativeArea']['SubAdministrativeArea'] &&
118
+ address_details['AdministrativeArea']['SubAdministrativeArea']['Locality'] &&
119
+ address_details['AdministrativeArea']['SubAdministrativeArea']['Locality']['DependentLocality']
120
+ end
121
+
72
122
  def address_details
73
123
  @data['GeoObject']['metaDataProperty']['GeocoderMetaData']['AddressDetails']['Country']
74
124
  end
75
125
 
76
126
  def sub_state_city
77
- if !sub_state.empty? and address_details['AdministrativeArea']['SubAdministrativeArea'].has_key? 'Locality'
127
+ if !sub_state.empty? and address_details and address_details['AdministrativeArea']['SubAdministrativeArea'].has_key? 'Locality'
78
128
  address_details['AdministrativeArea']['SubAdministrativeArea']['Locality']['LocalityName'] || ""
79
129
  else
80
130
  ""
data/lib/geocoder/sql.rb CHANGED
@@ -4,8 +4,8 @@ module Geocoder
4
4
 
5
5
  ##
6
6
  # Distance calculation for use with a database that supports POWER(),
7
- # SQRT(), PI(), and trigonometric functions SIN(), COS(), ASIN(),
8
- # ATAN2(), DEGREES(), and RADIANS().
7
+ # SQRT(), PI(), and trigonometric functions SIN(), COS(), ASIN(),
8
+ # ATAN2().
9
9
  #
10
10
  # Based on the excellent tutorial at:
11
11
  # http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
@@ -44,13 +44,13 @@ module Geocoder
44
44
  end
45
45
 
46
46
  def within_bounding_box(sw_lat, sw_lng, ne_lat, ne_lng, lat_attr, lon_attr)
47
- spans = "#{lat_attr} BETWEEN #{sw_lat} AND #{ne_lat} AND "
47
+ spans = "#{lat_attr} BETWEEN #{sw_lat.to_f} AND #{ne_lat.to_f} AND "
48
48
  # handle box that spans 180 longitude
49
49
  if sw_lng.to_f > ne_lng.to_f
50
- spans + "#{lon_attr} BETWEEN #{sw_lng} AND 180 OR " +
51
- "#{lon_attr} BETWEEN -180 AND #{ne_lng}"
50
+ spans + "(#{lon_attr} BETWEEN #{sw_lng.to_f} AND 180 OR " +
51
+ "#{lon_attr} BETWEEN -180 AND #{ne_lng.to_f})"
52
52
  else
53
- spans + "#{lon_attr} BETWEEN #{sw_lng} AND #{ne_lng}"
53
+ spans + "#{lon_attr} BETWEEN #{sw_lng.to_f} AND #{ne_lng.to_f}"
54
54
  end
55
55
  end
56
56
 
@@ -59,6 +59,9 @@ module Geocoder
59
59
  # and an options hash which must include a :bearing value
60
60
  # (:linear or :spherical).
61
61
  #
62
+ # For use with a database that supports MOD() and trigonometric functions
63
+ # SIN(), COS(), ASIN(), ATAN2().
64
+ #
62
65
  # Based on:
63
66
  # http://www.beginningspatial.com/calculating_bearing_one_point_another
64
67
  #
@@ -28,6 +28,11 @@ module Geocoder::Store
28
28
  "OR #{table_name}.#{geocoder_options[:longitude]} IS NULL")
29
29
  }
30
30
 
31
+ # scope: not-reverse geocoded objects
32
+ scope :not_reverse_geocoded, lambda {
33
+ where("#{table_name}.#{geocoder_options[:fetched_address]} IS NULL")
34
+ }
35
+
31
36
  ##
32
37
  # Find all objects within a radius of the given location.
33
38
  # Location may be either a string to geocode or an array of
@@ -55,7 +60,7 @@ module Geocoder::Store
55
60
  # corner followed by the northeast corner of the box
56
61
  # (<tt>[[sw_lat, sw_lon], [ne_lat, ne_lon]]</tt>).
57
62
  #
58
- scope :within_bounding_box, lambda{ |bounds|
63
+ scope :within_bounding_box, lambda{ |*bounds|
59
64
  sw_lat, sw_lng, ne_lat, ne_lng = bounds.flatten if bounds
60
65
  if sw_lat && sw_lng && ne_lat && ne_lng
61
66
  where(Geocoder::Sql.within_bounding_box(
@@ -82,8 +87,6 @@ module Geocoder::Store
82
87
  end
83
88
  end
84
89
 
85
- private # ----------------------------------------------------------------
86
-
87
90
  ##
88
91
  # Get options hash suitable for passing to ActiveRecord.find to get
89
92
  # records within a radius (in kilometers) of the given point.
@@ -126,18 +129,31 @@ module Geocoder::Store
126
129
  distance_column = options.fetch(:distance_column) { 'distance' }
127
130
  bearing_column = options.fetch(:bearing_column) { 'bearing' }
128
131
 
129
- b = Geocoder::Calculations.bounding_box([latitude, longitude], radius, options)
132
+ # If radius is a DB column name, bounding box should include
133
+ # all rows within the maximum radius appearing in that column.
134
+ # Note: performance is dependent on variability of radii.
135
+ bb_radius = radius.is_a?(Symbol) ? maximum(radius) : radius
136
+ b = Geocoder::Calculations.bounding_box([latitude, longitude], bb_radius, options)
130
137
  args = b + [
131
138
  full_column_name(latitude_attribute),
132
139
  full_column_name(longitude_attribute)
133
140
  ]
134
141
  bounding_box_conditions = Geocoder::Sql.within_bounding_box(*args)
135
142
 
136
- if using_sqlite?
143
+ if using_unextended_sqlite?
137
144
  conditions = bounding_box_conditions
138
145
  else
139
146
  min_radius = options.fetch(:min_radius, 0).to_f
140
- conditions = [bounding_box_conditions + " AND (#{distance}) BETWEEN ? AND ?", min_radius, radius]
147
+ # if radius is a DB column name,
148
+ # find rows between min_radius and value in column
149
+ if radius.is_a?(Symbol)
150
+ c = "BETWEEN ? AND #{radius}"
151
+ a = [min_radius]
152
+ else
153
+ c = "BETWEEN ? AND ?"
154
+ a = [min_radius, radius]
155
+ end
156
+ conditions = [bounding_box_conditions + " AND (#{distance}) " + c] + a
141
157
  end
142
158
  {
143
159
  :select => select_clause(options[:select],
@@ -155,7 +171,7 @@ module Geocoder::Store
155
171
  # capabilities (trig functions?).
156
172
  #
157
173
  def distance_sql(latitude, longitude, options = {})
158
- method_prefix = using_sqlite? ? "approx" : "full"
174
+ method_prefix = using_unextended_sqlite? ? "approx" : "full"
159
175
  Geocoder::Sql.send(
160
176
  method_prefix + "_distance",
161
177
  latitude, longitude,
@@ -174,7 +190,7 @@ module Geocoder::Store
174
190
  options[:bearing] = Geocoder.config.distances
175
191
  end
176
192
  if options[:bearing]
177
- method_prefix = using_sqlite? ? "approx" : "full"
193
+ method_prefix = using_unextended_sqlite? ? "approx" : "full"
178
194
  Geocoder::Sql.send(
179
195
  method_prefix + "_bearing",
180
196
  latitude, longitude,
@@ -220,8 +236,20 @@ module Geocoder::Store
220
236
  conditions
221
237
  end
222
238
 
239
+ def using_unextended_sqlite?
240
+ using_sqlite? && !using_sqlite_with_extensions?
241
+ end
242
+
223
243
  def using_sqlite?
224
- connection.adapter_name.match(/sqlite/i)
244
+ !!connection.adapter_name.match(/sqlite/i)
245
+ end
246
+
247
+ def using_sqlite_with_extensions?
248
+ connection.adapter_name.match(/sqlite/i) &&
249
+ defined?(::SqliteExt) &&
250
+ %W(MOD POWER SQRT PI SIN COS ASIN ATAN2).all?{ |fn_name|
251
+ connection.raw_connection.function_created?(fn_name)
252
+ }
225
253
  end
226
254
 
227
255
  def using_postgres?
@@ -239,7 +267,7 @@ module Geocoder::Store
239
267
  # Value which can be passed to where() to produce no results.
240
268
  #
241
269
  def false_condition
242
- using_sqlite? ? 0 : "false"
270
+ using_unextended_sqlite? ? 0 : "false"
243
271
  end
244
272
 
245
273
  ##
@@ -251,6 +279,17 @@ module Geocoder::Store
251
279
  end
252
280
  end
253
281
 
282
+ ##
283
+ # Get nearby geocoded objects.
284
+ # Takes the same options hash as the near class method (scope).
285
+ # Returns nil if the object is not geocoded.
286
+ #
287
+ def nearbys(radius = 20, options = {})
288
+ return nil unless geocoded?
289
+ options.merge!(:exclude => self) unless send(self.class.primary_key).nil?
290
+ self.class.near(self, radius, options)
291
+ end
292
+
254
293
  ##
255
294
  # Look up coordinates and assign to +latitude+ and +longitude+ attributes
256
295
  # (or other as specified in +geocoded_by+). Returns coordinates (array).