geocoder 1.2.5 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of geocoder might be problematic. Click here for more details.

Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/README.md +83 -8
  4. data/lib/geocoder/ip_address.rb +11 -2
  5. data/lib/geocoder/lookup.rb +4 -0
  6. data/lib/geocoder/lookups/geoip2.rb +40 -0
  7. data/lib/geocoder/lookups/google_places_details.rb +50 -0
  8. data/lib/geocoder/lookups/maxmind_local.rb +1 -1
  9. data/lib/geocoder/lookups/okf.rb +43 -0
  10. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +51 -0
  11. data/lib/geocoder/lookups/smarty_streets.rb +1 -1
  12. data/lib/geocoder/results/geoip2.rb +64 -0
  13. data/lib/geocoder/results/google_places_details.rb +35 -0
  14. data/lib/geocoder/results/okf.rb +106 -0
  15. data/lib/geocoder/results/postcode_anywhere_uk.rb +42 -0
  16. data/lib/geocoder/results/test.rb +1 -1
  17. data/lib/geocoder/stores/active_record.rb +22 -11
  18. data/lib/geocoder/version.rb +1 -1
  19. data/test/fixtures/google_places_details_invalid_request +4 -0
  20. data/test/fixtures/google_places_details_madison_square_garden +120 -0
  21. data/test/fixtures/google_places_details_no_results +4 -0
  22. data/test/fixtures/google_places_details_no_reviews +60 -0
  23. data/test/fixtures/google_places_details_no_types +66 -0
  24. data/test/fixtures/okf_kirstinmaki +67 -0
  25. data/test/fixtures/okf_no_results +4 -0
  26. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_WR26NJ +1 -0
  27. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_generic_error +1 -0
  28. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_hampshire +1 -0
  29. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_key_limit_exceeded +1 -0
  30. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_no_results +1 -0
  31. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_romsey +1 -0
  32. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_unknown_key +1 -0
  33. data/test/test_helper.rb +44 -0
  34. data/test/unit/cache_test.rb +1 -1
  35. data/test/unit/error_handling_test.rb +3 -3
  36. data/test/unit/ip_address_test.rb +3 -0
  37. data/test/unit/lookup_test.rb +1 -1
  38. data/test/unit/lookups/geoip2_test.rb +27 -0
  39. data/test/unit/lookups/google_places_details_test.rb +122 -0
  40. data/test/unit/lookups/okf_test.rb +38 -0
  41. data/test/unit/lookups/postcode_anywhere_uk_test.rb +70 -0
  42. data/test/unit/query_test.rb +1 -0
  43. data/test/unit/test_mode_test.rb +1 -1
  44. metadata +28 -2
@@ -0,0 +1,35 @@
1
+ require "geocoder/results/google"
2
+
3
+ module Geocoder
4
+ module Result
5
+ class GooglePlacesDetails < Google
6
+ def place_id
7
+ @data["place_id"]
8
+ end
9
+
10
+ def types
11
+ @data["types"] || []
12
+ end
13
+
14
+ def reviews
15
+ @data["reviews"] || []
16
+ end
17
+
18
+ def rating
19
+ @data["rating"]
20
+ end
21
+
22
+ def rating_count
23
+ @data["user_ratings_total"]
24
+ end
25
+
26
+ def phone_number
27
+ @data["international_phone_number"]
28
+ end
29
+
30
+ def website
31
+ @data["website"]
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,106 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Okf < Base
5
+
6
+ def coordinates
7
+ ['lat', 'lng'].map{ |i| geometry['location'][i] }
8
+ end
9
+
10
+ def address(format = :full)
11
+ formatted_address
12
+ end
13
+
14
+ def city
15
+ fields = [:locality, :sublocality,
16
+ :administrative_area_level_3,
17
+ :administrative_area_level_2]
18
+ fields.each do |f|
19
+ if entity = address_components_of_type(f).first
20
+ return entity['long_name']
21
+ end
22
+ end
23
+ return nil # no appropriate components found
24
+ end
25
+
26
+ def state
27
+ ""
28
+ end
29
+
30
+ def sub_state
31
+ ""
32
+ end
33
+
34
+ def state_code
35
+ ""
36
+ end
37
+
38
+ def country
39
+ if country = address_components_of_type(:country).first
40
+ country['long_name']
41
+ end
42
+ end
43
+
44
+ def country_code
45
+ if country = address_components_of_type(:country).first
46
+ country['short_name']
47
+ end
48
+ end
49
+
50
+ def postal_code
51
+ if postal = address_components_of_type(:postal_code).first
52
+ postal['long_name']
53
+ end
54
+ end
55
+
56
+ def route
57
+ if route = address_components_of_type(:route).first
58
+ route['long_name']
59
+ end
60
+ end
61
+
62
+ def street_number
63
+ if street_number = address_components_of_type(:street_number).first
64
+ street_number['long_name']
65
+ end
66
+ end
67
+
68
+ def street_address
69
+ [route, street_number].compact.join(' ')
70
+ end
71
+
72
+ def types
73
+ @data['types']
74
+ end
75
+
76
+ def formatted_address
77
+ @data['formatted_address']
78
+ end
79
+
80
+ def address_components
81
+ @data['address_components']
82
+ end
83
+
84
+ ##
85
+ # Get address components of a given type. Valid types are defined in
86
+ # Google's Geocoding API documentation and include (among others):
87
+ #
88
+ # :street_number
89
+ # :locality
90
+ # :neighborhood
91
+ # :route
92
+ # :postal_code
93
+ #
94
+ def address_components_of_type(type)
95
+ address_components.select{ |c| c['types'].include?(type.to_s) }
96
+ end
97
+
98
+ def geometry
99
+ @data['geometry']
100
+ end
101
+
102
+ def precision
103
+ geometry['location_type'] if geometry
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,42 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class PostcodeAnywhereUk < Base
5
+
6
+ def coordinates
7
+ [@data['Latitude'].to_f, @data['Longitude'].to_f]
8
+ end
9
+
10
+ def blank_result
11
+ ''
12
+ end
13
+ alias_method :state, :blank_result
14
+ alias_method :state_code, :blank_result
15
+ alias_method :postal_code, :blank_result
16
+
17
+ def address
18
+ @data['Location']
19
+ end
20
+
21
+ def city
22
+ # is this too big a jump to assume that the API always
23
+ # returns a City, County as the last elements?
24
+ city = @data['Location'].split(',')[-2] || blank_result
25
+ city.strip
26
+ end
27
+
28
+ def os_grid
29
+ @data['OsGrid']
30
+ end
31
+
32
+ # This is a UK only API; all results are UK specific and
33
+ # so ommitted from API response.
34
+ def country
35
+ 'United Kingdom'
36
+ end
37
+
38
+ def country_code
39
+ 'UK'
40
+ end
41
+ end
42
+ end
@@ -22,7 +22,7 @@ module Geocoder
22
22
  end
23
23
 
24
24
  def initialize(data)
25
- data.keys.each do |attr|
25
+ data.each_key do |attr|
26
26
  Test.add_result_attribute(attr)
27
27
  end
28
28
 
@@ -18,14 +18,14 @@ module Geocoder::Store
18
18
 
19
19
  # scope: geocoded objects
20
20
  scope :geocoded, lambda {
21
- where("#{geocoder_options[:latitude]} IS NOT NULL " +
22
- "AND #{geocoder_options[:longitude]} IS NOT NULL")
21
+ where("#{table_name}.#{geocoder_options[:latitude]} IS NOT NULL " +
22
+ "AND #{table_name}.#{geocoder_options[:longitude]} IS NOT NULL")
23
23
  }
24
24
 
25
25
  # scope: not-geocoded objects
26
26
  scope :not_geocoded, lambda {
27
- where("#{geocoder_options[:latitude]} IS NULL " +
28
- "OR #{geocoder_options[:longitude]} IS NULL")
27
+ where("#{table_name}.#{geocoder_options[:latitude]} IS NULL " +
28
+ "OR #{table_name}.#{geocoder_options[:longitude]} IS NULL")
29
29
  }
30
30
 
31
31
  ##
@@ -45,7 +45,7 @@ module Geocoder::Store
45
45
  # If no lat/lon given we don't want any results, but we still
46
46
  # need distance and bearing columns so you can add, for example:
47
47
  # .order("distance")
48
- select(select_clause(nil, "NULL", "NULL")).where(false_condition)
48
+ select(select_clause(nil, null_value, null_value)).where(false_condition)
49
49
  end
50
50
  }
51
51
 
@@ -64,7 +64,7 @@ module Geocoder::Store
64
64
  full_column_name(geocoder_options[:longitude])
65
65
  ))
66
66
  else
67
- select(select_clause(nil, "NULL", "NULL")).where(false_condition)
67
+ select(select_clause(nil, null_value, null_value)).where(false_condition)
68
68
  end
69
69
  }
70
70
  end
@@ -107,7 +107,7 @@ module Geocoder::Store
107
107
  # * +:exclude+ - an object to exclude (used by the +nearbys+ method)
108
108
  # * +:distance_column+ - used to set the column name of the calculated distance.
109
109
  # * +:bearing_column+ - used to set the column name of the calculated bearing.
110
- # * +:min_radius+ - the value to use as the minimum radius.
110
+ # * +:min_radius+ - the value to use as the minimum radius.
111
111
  # ignored if database is sqlite.
112
112
  # default is 0.0
113
113
  #
@@ -118,13 +118,13 @@ module Geocoder::Store
118
118
  latitude_attribute = options[:latitude] || geocoder_options[:latitude]
119
119
  longitude_attribute = options[:longitude] || geocoder_options[:longitude]
120
120
  options[:units] ||= (geocoder_options[:units] || Geocoder.config.units)
121
- select_distance = options.fetch(:select_distance, true)
121
+ select_distance = options.fetch(:select_distance) { true }
122
122
  options[:order] = "" if !select_distance && !options.include?(:order)
123
- select_bearing = options.fetch(:select_bearing, true)
123
+ select_bearing = options.fetch(:select_bearing) { true }
124
124
  bearing = bearing_sql(latitude, longitude, options)
125
125
  distance = distance_sql(latitude, longitude, options)
126
- distance_column = options.fetch(:distance_column, 'distance')
127
- bearing_column = options.fetch(:bearing_column, 'bearing')
126
+ distance_column = options.fetch(:distance_column) { 'distance' }
127
+ bearing_column = options.fetch(:bearing_column) { 'bearing' }
128
128
 
129
129
  b = Geocoder::Calculations.bounding_box([latitude, longitude], radius, options)
130
130
  args = b + [
@@ -224,6 +224,17 @@ module Geocoder::Store
224
224
  connection.adapter_name.match(/sqlite/i)
225
225
  end
226
226
 
227
+ def using_postgres?
228
+ connection.adapter_name.match(/postgres/i)
229
+ end
230
+
231
+ ##
232
+ # Use OID type when running in PosgreSQL
233
+ #
234
+ def null_value
235
+ using_postgres? ? 'NULL::text' : 'NULL'
236
+ end
237
+
227
238
  ##
228
239
  # Value which can be passed to where() to produce no results.
229
240
  #
@@ -1,3 +1,3 @@
1
1
  module Geocoder
2
- VERSION = "1.2.5"
2
+ VERSION = "1.2.6"
3
3
  end
@@ -0,0 +1,4 @@
1
+ {
2
+ "html_attributions" : [],
3
+ "status" : "INVALID_REQUEST"
4
+ }
@@ -0,0 +1,120 @@
1
+ {
2
+ "html_attributions" : [],
3
+ "result" : {
4
+ "address_components" : [
5
+ {
6
+ "long_name" : "4",
7
+ "short_name" : "4",
8
+ "types" : [ "street_number" ]
9
+ },
10
+ {
11
+ "long_name" : "Pennsylvania Plaza",
12
+ "short_name" : "Pennsylvania Plaza",
13
+ "types" : [ "route" ]
14
+ },
15
+ {
16
+ "long_name" : "Chelsea",
17
+ "short_name" : "Chelsea",
18
+ "types" : [ "neighborhood", "political" ]
19
+ },
20
+ {
21
+ "long_name" : "Manhattan",
22
+ "short_name" : "Manhattan",
23
+ "types" : [ "sublocality_level_1", "sublocality", "political" ]
24
+ },
25
+ {
26
+ "long_name" : "New York",
27
+ "short_name" : "New York",
28
+ "types" : [ "locality", "political" ]
29
+ },
30
+ {
31
+ "long_name" : "New York County",
32
+ "short_name" : "New York County",
33
+ "types" : [ "administrative_area_level_2", "political" ]
34
+ },
35
+ {
36
+ "long_name" : "NY",
37
+ "short_name" : "NY",
38
+ "types" : [ "administrative_area_level_1", "political" ]
39
+ },
40
+ {
41
+ "long_name" : "United States",
42
+ "short_name" : "US",
43
+ "types" : [ "country", "political" ]
44
+ },
45
+ {
46
+ "long_name" : "10001",
47
+ "short_name" : "10001",
48
+ "types" : [ "postal_code" ]
49
+ }
50
+ ],
51
+ "adr_address" : "\u003cspan class=\"street-address\"\u003e4 Pennsylvania Plaza\u003c/span\u003e, \u003cspan class=\"locality\"\u003eNew York\u003c/span\u003e, \u003cspan class=\"region\"\u003eNY\u003c/span\u003e \u003cspan class=\"postal-code\"\u003e10001\u003c/span\u003e, \u003cspan class=\"country-name\"\u003eUnited States\u003c/span\u003e",
52
+ "formatted_address" : "4 Pennsylvania Plaza, New York, NY, United States",
53
+ "formatted_phone_number" : "(212) 465-6741",
54
+ "geometry" : {
55
+ "location" : {
56
+ "lat" : 40.750504,
57
+ "lng" : -73.993439
58
+ }
59
+ },
60
+ "icon" : "http://maps.gstatic.com/mapfiles/place_api/icons/stadium-71.png",
61
+ "id" : "55e3174d410b31da010030a7dfc0c9819027445a",
62
+ "international_phone_number" : "+1 212-465-6741",
63
+ "name" : "Madison Square Garden",
64
+ "photos" : [
65
+ {
66
+ "height" : 267,
67
+ "html_attributions" : [ "Someone" ],
68
+ "photo_reference" : "CnRoAAAAB1lz_vOkA1Ffaf7vJ1xcjzVsII-873Z_f8_v3EyW4XbEvlR3VkW_HvNfwF6AwDA0U-ont7fIUqEMyDcovCTWN8RSYN3ibEhqgJPvXxBjeYVi0cc-t-3KfkB_LpV7chPAqhOsdMG56kyzTKIo4lISHxIQqru7QXV6xU11jLaLpi4FNRoUhutg9aq027NghW1d-o9GGE8N3yM",
69
+ "width" : 400
70
+ },
71
+ {
72
+ "height" : 732,
73
+ "html_attributions" : [ "Someone else" ],
74
+ "photo_reference" : "CoQBfwAAADbYj554hM1BgVbBOs6rDjO9UtQ63ecU1P8tI3PfaHame3MB4ipgcNRlv9N2iUa-tXoMq9iXAaDStWgCJ3f48WIuIRbz-Xv-HzSJ0hMCrFiZMRs7kLgaBO7eDJwioTySWcoyAwojretq4mZKF_AcRSUhkqOokBhOstmshWWpSAyyEhAdpL2yp42xDNq2YRiFrx4DGhRZIdt7mochSwZcgSdjESea27Qy9Q",
75
+ "width" : 929
76
+ }
77
+ ],
78
+ "place_id" : "ChIJhRwB-yFawokR5Phil-QQ3zM",
79
+ "rating" : 4.4,
80
+ "reference" : "CnRuAAAArSB-mFxXRjm0ERZIC4c_1gbXwxqmyxUrxws_PQUrz9Y3xZstEwm7_8dLw7zM8hV3vWkPF4RkkZQQ_X01ikDALx2VgV60YwiSX7k3TXxkWnzyFcX0fnHCQLerlYttk_usL7UALQQgMeuf25_eFx3SnhIQxN95Ek3bQVuLVM16yb99ehoU7djcL3cjllohLZ6oJ6X3Tzb9MJQ",
81
+ "reviews" : [
82
+ {
83
+ "aspects" : [
84
+ {
85
+ "rating" : 5,
86
+ "type" : "overall"
87
+ }
88
+ ],
89
+ "author_name" : "John Smith",
90
+ "author_url" : "https://plus.google.com/john.smith",
91
+ "language" : "en",
92
+ "rating" : 5,
93
+ "text" : "It's nice.",
94
+ "time" : 1407266916
95
+ },
96
+ {
97
+ "aspects" : [
98
+ {
99
+ "rating" : 2,
100
+ "type" : "overall"
101
+ }
102
+ ],
103
+ "author_name" : "Jane Smith",
104
+ "author_url" : "https://plus.google.com/jane.smith",
105
+ "language" : "en",
106
+ "rating" : 2,
107
+ "text" : "Not so nice.",
108
+ "time" : 1398779079
109
+ }
110
+ ],
111
+ "scope" : "GOOGLE",
112
+ "types" : [ "stadium", "establishment" ],
113
+ "url" : "https://plus.google.com/112180896421099179463/about?hl=en-US",
114
+ "user_ratings_total" : 382,
115
+ "utc_offset" : -240,
116
+ "vicinity" : "4 Pennsylvania Plaza, New York",
117
+ "website" : "http://www.thegarden.com/"
118
+ },
119
+ "status" : "OK"
120
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "html_attributions" : [],
3
+ "result": {}
4
+ }
@@ -0,0 +1,60 @@
1
+ {
2
+ "html_attributions" : [],
3
+ "result" : {
4
+ "address_components" : [
5
+ {
6
+ "long_name" : "25",
7
+ "short_name" : "25",
8
+ "types" : [ "street_number" ]
9
+ },
10
+ {
11
+ "long_name" : "Oranienstraße",
12
+ "short_name" : "Oranienstraße",
13
+ "types" : [ "route" ]
14
+ },
15
+ {
16
+ "long_name" : "Friedrichshain-Kreuzberg",
17
+ "short_name" : "Friedrichshain-Kreuzberg",
18
+ "types" : [ "sublocality_level_1", "sublocality", "political" ]
19
+ },
20
+ {
21
+ "long_name" : "Berlin",
22
+ "short_name" : "Berlin",
23
+ "types" : [ "locality", "political" ]
24
+ },
25
+ {
26
+ "long_name" : "Berlin",
27
+ "short_name" : "Berlin",
28
+ "types" : [ "administrative_area_level_1", "political" ]
29
+ },
30
+ {
31
+ "long_name" : "Germany",
32
+ "short_name" : "DE",
33
+ "types" : [ "country", "political" ]
34
+ },
35
+ {
36
+ "long_name" : "10999",
37
+ "short_name" : "10999",
38
+ "types" : [ "postal_code" ]
39
+ }
40
+ ],
41
+ "adr_address" : "\u003cspan class=\"street-address\"\u003eOranienstraße 25\u003c/span\u003e, \u003cspan class=\"postal-code\"\u003e10999\u003c/span\u003e \u003cspan class=\"locality\"\u003eBerlin\u003c/span\u003e, \u003cspan class=\"country-name\"\u003eGermany\u003c/span\u003e",
42
+ "formatted_address" : "Oranienstraße 25, 10999 Berlin, Germany",
43
+ "geometry" : {
44
+ "location" : {
45
+ "lat" : 52.5010652,
46
+ "lng" : 13.4206563
47
+ }
48
+ },
49
+ "icon" : "http://maps.gstatic.com/mapfiles/place_api/icons/geocode-71.png",
50
+ "id" : "b49e917abd41c247425645a6ac3e5a6756ad80f8",
51
+ "name" : "Oranienstraße 25",
52
+ "place_id" : "ChIJQ8-HeTROqEcRGdCTErYy5D0",
53
+ "reference" : "CpQBjAAAAKrbnaAglhQLI6KPs3EbRp1lVh5UkB4xLEyzOmvvGmtpmwD2EAnlokKcx1VU5PvvB7moRGw6lHTlMTScpGL3GTCC_WM2pzDxgeaAtoB-SR4YQ7PRhHkT2eqxACbaP_70Z9Wyb2J31tG66xBrYASAuBzXgEXYaFpo8dhRBY4xMTfexvMziw6rHs01SxLhCFh-uBIQBQcGVz70_HtaG_g6ZZ5omhoUdIDDSVApRiVoIh61NiCzStYa-x0",
54
+ "scope" : "GOOGLE",
55
+ "types" : [ "street_address" ],
56
+ "url" : "https://maps.google.com/maps/place?q=Oranienstra%C3%9Fe+25,+10999+Berlin,+Germany&ftid=0x47a84e347987cf43:0x3de432b61293d019",
57
+ "vicinity" : "Friedrichshain-Kreuzberg"
58
+ },
59
+ "status" : "OK"
60
+ }