geocoder 1.4.3 → 1.5.0

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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -0
  3. data/README.md +364 -880
  4. data/examples/autoexpire_cache_redis.rb +3 -3
  5. data/lib/generators/geocoder/config/templates/initializer.rb +3 -2
  6. data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +2 -0
  7. data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +2 -0
  8. data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +1 -1
  9. data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +1 -1
  10. data/lib/generators/geocoder/migration_version.rb +15 -0
  11. data/lib/geocoder/cache.rb +6 -2
  12. data/lib/geocoder/cli.rb +2 -2
  13. data/lib/geocoder/configuration.rb +2 -2
  14. data/lib/geocoder/exceptions.rb +1 -1
  15. data/lib/geocoder/ip_address.rb +1 -1
  16. data/lib/geocoder/lookup.rb +9 -4
  17. data/lib/geocoder/lookups/amap.rb +63 -0
  18. data/lib/geocoder/lookups/baidu.rb +14 -10
  19. data/lib/geocoder/lookups/baidu_ip.rb +6 -35
  20. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +4 -4
  21. data/lib/geocoder/lookups/base.rb +22 -4
  22. data/lib/geocoder/lookups/bing.rb +13 -12
  23. data/lib/geocoder/lookups/db_ip_com.rb +52 -0
  24. data/lib/geocoder/lookups/dstk.rb +4 -2
  25. data/lib/geocoder/lookups/esri.rb +1 -16
  26. data/lib/geocoder/lookups/freegeoip.rb +11 -2
  27. data/lib/geocoder/lookups/geocoder_ca.rb +4 -4
  28. data/lib/geocoder/lookups/geocoder_us.rb +17 -9
  29. data/lib/geocoder/lookups/geocodio.rb +5 -5
  30. data/lib/geocoder/lookups/geoportail_lu.rb +7 -7
  31. data/lib/geocoder/lookups/google.rb +13 -9
  32. data/lib/geocoder/lookups/google_places_details.rb +4 -4
  33. data/lib/geocoder/lookups/google_places_search.rb +4 -4
  34. data/lib/geocoder/lookups/google_premier.rb +11 -1
  35. data/lib/geocoder/lookups/here.rb +4 -4
  36. data/lib/geocoder/lookups/ip2location.rb +74 -0
  37. data/lib/geocoder/lookups/ipapi_com.rb +7 -12
  38. data/lib/geocoder/lookups/ipdata_co.rb +61 -0
  39. data/lib/geocoder/lookups/ipinfo_io.rb +10 -19
  40. data/lib/geocoder/lookups/ipstack.rb +63 -0
  41. data/lib/geocoder/lookups/latlon.rb +4 -4
  42. data/lib/geocoder/lookups/location_iq.rb +26 -8
  43. data/lib/geocoder/lookups/mapbox.rb +12 -6
  44. data/lib/geocoder/lookups/mapquest.rb +4 -5
  45. data/lib/geocoder/lookups/maxmind.rb +4 -4
  46. data/lib/geocoder/lookups/maxmind_geoip2.rb +4 -0
  47. data/lib/geocoder/lookups/nominatim.rb +17 -5
  48. data/lib/geocoder/lookups/opencagedata.rb +7 -6
  49. data/lib/geocoder/lookups/pelias.rb +6 -6
  50. data/lib/geocoder/lookups/pickpoint.rb +41 -0
  51. data/lib/geocoder/lookups/pointpin.rb +7 -6
  52. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +4 -5
  53. data/lib/geocoder/lookups/postcodes_io.rb +31 -0
  54. data/lib/geocoder/lookups/smarty_streets.rb +8 -8
  55. data/lib/geocoder/lookups/telize.rb +24 -4
  56. data/lib/geocoder/lookups/yandex.rb +10 -6
  57. data/lib/geocoder/models/active_record.rb +4 -3
  58. data/lib/geocoder/request.rb +32 -0
  59. data/lib/geocoder/results/amap.rb +87 -0
  60. data/lib/geocoder/results/baidu.rb +10 -10
  61. data/lib/geocoder/results/base.rb +13 -1
  62. data/lib/geocoder/results/bing.rb +1 -1
  63. data/lib/geocoder/results/db_ip_com.rb +58 -0
  64. data/lib/geocoder/results/freegeoip.rb +0 -5
  65. data/lib/geocoder/results/geocoder_ca.rb +3 -3
  66. data/lib/geocoder/results/geoip2.rb +24 -10
  67. data/lib/geocoder/results/geoportail_lu.rb +5 -3
  68. data/lib/geocoder/results/google.rb +16 -5
  69. data/lib/geocoder/results/here.rb +8 -0
  70. data/lib/geocoder/results/ip2location.rb +22 -0
  71. data/lib/geocoder/results/ipdata_co.rb +40 -0
  72. data/lib/geocoder/results/ipstack.rb +60 -0
  73. data/lib/geocoder/results/maxmind.rb +0 -5
  74. data/lib/geocoder/results/maxmind_local.rb +0 -5
  75. data/lib/geocoder/results/nominatim.rb +12 -0
  76. data/lib/geocoder/results/opencagedata.rb +12 -2
  77. data/lib/geocoder/results/pickpoint.rb +6 -0
  78. data/lib/geocoder/results/postcodes_io.rb +40 -0
  79. data/lib/geocoder/results/smarty_streets.rb +7 -1
  80. data/lib/geocoder/results/telize.rb +0 -5
  81. data/lib/geocoder/results/test.rb +1 -1
  82. data/lib/geocoder/sql.rb +2 -2
  83. data/lib/geocoder/stores/active_record.rb +15 -4
  84. data/lib/geocoder/stores/base.rb +1 -2
  85. data/lib/geocoder/version.rb +1 -1
  86. data/lib/tasks/geocoder.rake +11 -3
  87. metadata +27 -10
  88. data/lib/geocoder/lookups/okf.rb +0 -44
  89. data/lib/geocoder/lookups/ovi.rb +0 -62
  90. data/lib/geocoder/results/okf.rb +0 -106
  91. data/lib/geocoder/results/ovi.rb +0 -71
@@ -9,16 +9,28 @@ module Geocoder::Lookup
9
9
  end
10
10
 
11
11
  def map_link_url(coordinates)
12
- "http://www.openstreetmap.org/?lat=#{coordinates[0]}&lon=#{coordinates[1]}&zoom=15&layers=M"
12
+ "https://www.openstreetmap.org/?lat=#{coordinates[0]}&lon=#{coordinates[1]}&zoom=15&layers=M"
13
13
  end
14
14
 
15
- def query_url(query)
15
+ private # ---------------------------------------------------------------
16
+
17
+ def base_query_url(query)
16
18
  method = query.reverse_geocode? ? "reverse" : "search"
17
- host = configuration[:host] || "nominatim.openstreetmap.org"
18
- "#{protocol}://#{host}/#{method}?" + url_query_string(query)
19
+ "#{protocol}://#{configured_host}/#{method}?"
19
20
  end
20
21
 
21
- private # ---------------------------------------------------------------
22
+ def configured_host
23
+ configuration[:host] || "nominatim.openstreetmap.org"
24
+ end
25
+
26
+ def use_ssl?
27
+ # nominatim.openstreetmap.org redirects HTTP requests to HTTPS
28
+ if configured_host == "nominatim.openstreetmap.org"
29
+ true
30
+ else
31
+ super
32
+ end
33
+ end
22
34
 
23
35
  def results(query)
24
36
  return [] unless doc = fetch_data(query)
@@ -8,15 +8,15 @@ module Geocoder::Lookup
8
8
  "OpenCageData"
9
9
  end
10
10
 
11
- def query_url(query)
12
- "#{protocol}://api.opencagedata.com/geocode/v1/json?key=#{configuration.api_key}&#{url_query_string(query)}"
13
- end
14
-
15
11
  def required_api_key_parts
16
12
  ["key"]
17
13
  end
18
14
 
19
- private
15
+ private # ----------------------------------------------------------------
16
+
17
+ def base_query_url(query)
18
+ "#{protocol}://api.opencagedata.com/geocode/v1/json?"
19
+ end
20
20
 
21
21
  def results(query)
22
22
  return [] unless doc = fetch_data(query)
@@ -44,10 +44,11 @@ module Geocoder::Lookup
44
44
  def query_url_params(query)
45
45
  params = {
46
46
  :q => query.sanitized_text,
47
+ :key => configuration.api_key,
47
48
  :language => (query.language || configuration.language)
48
49
  }.merge(super)
49
50
 
50
- [:countrycode, :min_confidence, :no_dedupe, :no_annotations, :no_record, :limit].each do |option|
51
+ [:abbrv, :countrycode, :min_confidence, :no_dedupe, :no_annotations, :no_record, :limit].each do |option|
51
52
  unless (option_value = query.options[option]).nil?
52
53
  params[option] = option_value
53
54
  end
@@ -11,16 +11,16 @@ module Geocoder::Lookup
11
11
  configuration[:endpoint] || 'localhost'
12
12
  end
13
13
 
14
- def query_url(query)
15
- query_type = query.reverse_geocode? ? 'reverse' : 'search'
16
- "#{protocol}://#{endpoint}/v1/#{query_type}?" + url_query_string(query)
17
- end
18
-
19
14
  def required_api_key_parts
20
15
  ['search-XXXX']
21
16
  end
22
17
 
23
- private
18
+ private # ----------------------------------------------------------------
19
+
20
+ def base_query_url(query)
21
+ query_type = query.reverse_geocode? ? 'reverse' : 'search'
22
+ "#{protocol}://#{endpoint}/v1/#{query_type}?"
23
+ end
24
24
 
25
25
  def query_url_params(query)
26
26
  params = {
@@ -0,0 +1,41 @@
1
+ require "geocoder/lookups/nominatim"
2
+ require "geocoder/results/pickpoint"
3
+
4
+ module Geocoder::Lookup
5
+ class Pickpoint < Nominatim
6
+ def name
7
+ "Pickpoint"
8
+ end
9
+
10
+ def supported_protocols
11
+ [:https]
12
+ end
13
+
14
+ def required_api_key_parts
15
+ ["api_key"]
16
+ end
17
+
18
+ private # ----------------------------------------------------------------
19
+
20
+ def base_query_url(query)
21
+ method = query.reverse_geocode? ? "reverse" : "forward"
22
+ "#{protocol}://api.pickpoint.io/v1/#{method}?"
23
+ end
24
+
25
+ def query_url_params(query)
26
+ params = {
27
+ key: configuration.api_key
28
+ }.merge(super)
29
+ end
30
+
31
+ def results(query)
32
+ return [] unless doc = fetch_data(query)
33
+
34
+ if !doc.is_a?(Array) && doc['message'] == 'Unauthorized'
35
+ raise_error(Geocoder::InvalidApiKey, 'Unauthorized')
36
+ end
37
+
38
+ doc.is_a?(Array) ? doc : [doc]
39
+ end
40
+ end
41
+ end
@@ -13,10 +13,14 @@ module Geocoder::Lookup
13
13
  end
14
14
 
15
15
  def query_url(query)
16
- "#{ protocol }://geo.pointp.in/#{ api_key }/json/#{ query.sanitized_text }"
16
+ "#{protocol}://geo.pointp.in/#{configuration.api_key}/json/#{query.sanitized_text}"
17
17
  end
18
18
 
19
- private
19
+ private # ----------------------------------------------------------------
20
+
21
+ def cache_key(query)
22
+ "#{protocol}://geo.pointp.in/json/#{query.sanitized_text}"
23
+ end
20
24
 
21
25
  def results(query)
22
26
  # don't look up a loopback address, just return the stored result
@@ -46,6 +50,7 @@ module Geocoder::Lookup
46
50
  parsed_data.keys.include?('error')
47
51
  end
48
52
 
53
+ # TODO: replace this hash with what's actually returned by Pointpin
49
54
  def reserved_result(ip)
50
55
  {
51
56
  "ip" => ip,
@@ -60,9 +65,5 @@ module Geocoder::Lookup
60
65
  "country_code" => "RD"
61
66
  }
62
67
  end
63
-
64
- def api_key
65
- configuration.api_key
66
- end
67
68
  end
68
69
  end
@@ -4,7 +4,6 @@ require 'geocoder/results/postcode_anywhere_uk'
4
4
  module Geocoder::Lookup
5
5
  class PostcodeAnywhereUk < Base
6
6
  # API documentation: http://www.postcodeanywhere.co.uk/Support/WebService/Geocoding/UK/Geocode/2/
7
- BASE_URL_GEOCODE_V2_00 = 'services.postcodeanywhere.co.uk/Geocoding/UK/Geocode/v2.00/json.ws'
8
7
  DAILY_LIMIT_EXEEDED_ERROR_CODES = ['8', '17'] # api docs say these two codes are the same error
9
8
  INVALID_API_KEY_ERROR_CODE = '2'
10
9
 
@@ -16,11 +15,11 @@ module Geocoder::Lookup
16
15
  %w(key)
17
16
  end
18
17
 
19
- def query_url(query)
20
- format('%s://%s?%s', protocol, BASE_URL_GEOCODE_V2_00, url_query_string(query))
21
- end
18
+ private # ----------------------------------------------------------------
22
19
 
23
- private
20
+ def base_query_url(query)
21
+ "#{protocol}://services.postcodeanywhere.co.uk/Geocoding/UK/Geocode/v2.00/json.ws?"
22
+ end
24
23
 
25
24
  def results(query)
26
25
  response = fetch_data(query)
@@ -0,0 +1,31 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/postcodes_io'
3
+
4
+ module Geocoder::Lookup
5
+ class PostcodesIo < Base
6
+ def name
7
+ 'Postcodes.io'
8
+ end
9
+
10
+ def query_url(query)
11
+ "#{protocol}://api.postcodes.io/postcodes/#{query.sanitized_text.gsub(/\s/, '')}"
12
+ end
13
+
14
+ def supported_protocols
15
+ [:https]
16
+ end
17
+
18
+ private # ----------------------------------------------------------------
19
+
20
+ def cache_key(query)
21
+ query_url(query)
22
+ end
23
+
24
+ def results(query)
25
+ response = fetch_data(query)
26
+ return [] if response.nil? || response['status'] != 200 || response.empty?
27
+
28
+ [response['result']]
29
+ end
30
+ end
31
+ end
@@ -11,14 +11,6 @@ module Geocoder::Lookup
11
11
  %w(auti-id auth-token)
12
12
  end
13
13
 
14
- def query_url(query)
15
- if zipcode_only?(query)
16
- "#{protocol}://us-zipcode.api.smartystreets.com/lookup?#{url_query_string(query)}"
17
- else
18
- "#{protocol}://us-street.api.smartystreets.com/street-address?#{url_query_string(query)}"
19
- end
20
- end
21
-
22
14
  # required by API as of 26 March 2015
23
15
  def supported_protocols
24
16
  [:https]
@@ -26,6 +18,14 @@ module Geocoder::Lookup
26
18
 
27
19
  private # ---------------------------------------------------------------
28
20
 
21
+ def base_query_url(query)
22
+ if zipcode_only?(query)
23
+ "#{protocol}://us-zipcode.api.smartystreets.com/lookup?"
24
+ else
25
+ "#{protocol}://us-street.api.smartystreets.com/street-address?"
26
+ end
27
+ end
28
+
29
29
  def zipcode_only?(query)
30
30
  !query.text.is_a?(Array) and query.to_s.strip =~ /\A\d{5}(-\d{4})?\Z/
31
31
  end
@@ -14,9 +14,9 @@ module Geocoder::Lookup
14
14
 
15
15
  def query_url(query)
16
16
  if configuration[:host]
17
- "#{protocol}://#{configuration[:host]}/geoip/#{query.sanitized_text}"
17
+ "#{protocol}://#{configuration[:host]}/location/#{query.sanitized_text}"
18
18
  else
19
- "#{protocol}://telize-v1.p.mashape.com/geoip/#{query.sanitized_text}?mashape-key=#{api_key}"
19
+ "#{protocol}://telize-v1.p.mashape.com/location/#{query.sanitized_text}?mashape-key=#{api_key}"
20
20
  end
21
21
  end
22
22
 
@@ -29,6 +29,10 @@ module Geocoder::Lookup
29
29
 
30
30
  private # ---------------------------------------------------------------
31
31
 
32
+ def cache_key(query)
33
+ query_url(query)[/(.*)\?.*/, 1]
34
+ end
35
+
32
36
  def results(query)
33
37
  # don't look up a loopback address, just return the stored result
34
38
  return [reserved_result(query.text)] if query.loopback_ip_address?
@@ -44,12 +48,28 @@ module Geocoder::Lookup
44
48
  end
45
49
 
46
50
  def reserved_result(ip)
47
- {"message" => "Input string is not a valid IP address", "code" => 401}
51
+ {
52
+ "ip" => ip,
53
+ "latitude" => 0,
54
+ "longitude" => 0,
55
+ "city" => "",
56
+ "timezone" => "",
57
+ "asn" => 0,
58
+ "region" => "",
59
+ "offset" => 0,
60
+ "organization" => "",
61
+ "country_code" => "",
62
+ "country_code3" => "",
63
+ "postal_code" => "",
64
+ "continent_code" => "",
65
+ "country" => "",
66
+ "region_code" => ""
67
+ }
48
68
  end
49
69
 
50
70
  def api_key
51
71
  configuration.api_key
52
72
  end
53
-
73
+
54
74
  end
55
75
  end
@@ -12,16 +12,16 @@ module Geocoder::Lookup
12
12
  "http://maps.yandex.ru/?ll=#{coordinates.reverse.join(',')}"
13
13
  end
14
14
 
15
- def query_url(query)
16
- "#{protocol}://geocode-maps.yandex.ru/1.x/?" + url_query_string(query)
17
- end
18
-
19
15
  def supported_protocols
20
16
  [:https]
21
17
  end
22
18
 
23
19
  private # ---------------------------------------------------------------
24
20
 
21
+ def base_query_url(query)
22
+ "#{protocol}://geocode-maps.yandex.ru/1.x/?"
23
+ end
24
+
25
25
  def results(query)
26
26
  return [] unless doc = fetch_data(query)
27
27
  if err = doc['error']
@@ -47,12 +47,16 @@ module Geocoder::Lookup
47
47
  else
48
48
  q = query.sanitized_text
49
49
  end
50
- {
50
+ params = {
51
51
  :geocode => q,
52
52
  :format => "json",
53
53
  :plng => "#{query.language || configuration.language}", # supports ru, uk, be
54
54
  :key => configuration.api_key
55
- }.merge(super)
55
+ }
56
+ unless (bounds = query.options[:bounds]).nil?
57
+ params[:bbox] = bounds.map{ |point| "%f,%f" % point }.join('~')
58
+ end
59
+ params.merge(super)
56
60
  end
57
61
  end
58
62
  end
@@ -18,7 +18,8 @@ module Geocoder
18
18
  :units => options[:units],
19
19
  :method => options[:method],
20
20
  :lookup => options[:lookup],
21
- :language => options[:language]
21
+ :language => options[:language],
22
+ :params => options[:params]
22
23
  )
23
24
  end
24
25
 
@@ -35,7 +36,8 @@ module Geocoder
35
36
  :units => options[:units],
36
37
  :method => options[:method],
37
38
  :lookup => options[:lookup],
38
- :language => options[:language]
39
+ :language => options[:language],
40
+ :params => options[:params]
39
41
  )
40
42
  end
41
43
 
@@ -47,4 +49,3 @@ module Geocoder
47
49
  end
48
50
  end
49
51
  end
50
-
@@ -1,3 +1,5 @@
1
+ require 'ipaddr'
2
+
1
3
  module Geocoder
2
4
  module Request
3
5
 
@@ -54,6 +56,8 @@ module Geocoder
54
56
  GEOCODER_CANDIDATE_HEADERS.each do |header|
55
57
  if @env.has_key? header
56
58
  addrs = geocoder_split_ip_addresses(@env[header])
59
+ addrs = geocoder_remove_port_from_addresses(addrs)
60
+ addrs = geocoder_reject_non_ipv4_addresses(addrs)
57
61
  addrs = geocoder_reject_trusted_ip_addresses(addrs)
58
62
  return addrs.first if addrs.any?
59
63
  end
@@ -75,6 +79,34 @@ module Geocoder
75
79
  def geocoder_reject_trusted_ip_addresses(ip_addresses)
76
80
  ip_addresses.reject { |ip| trusted_proxy?(ip) }
77
81
  end
82
+
83
+ def geocoder_remove_port_from_addresses(ip_addresses)
84
+ ip_addresses.map do |ip|
85
+ # IPv4
86
+ if ip.count('.') > 0
87
+ ip.split(':').first
88
+ # IPv6 bracket notation
89
+ elsif match = ip.match(/\[(\S+)\]/)
90
+ match.captures.first
91
+ # IPv6 bare notation
92
+ else
93
+ ip
94
+ end
95
+ end
96
+ end
97
+
98
+ def geocoder_reject_non_ipv4_addresses(ip_addresses)
99
+ ips = []
100
+ for ip in ip_addresses
101
+ begin
102
+ valid_ip = IPAddr.new(ip)
103
+ rescue
104
+ valid_ip = false
105
+ end
106
+ ips << valid_ip.to_s if valid_ip
107
+ end
108
+ return ips.any? ? ips : ip_addresses
109
+ end
78
110
  end
79
111
  end
80
112
 
@@ -0,0 +1,87 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Amap < Base
5
+
6
+ def coordinates
7
+ location = @data['location'] || @data['roadinters'].try(:first).try(:[], 'location') \
8
+ || address_components.try(:[], 'streetNumber').try(:[], 'location')
9
+ location.to_s.split(",").reverse.map(&:to_f)
10
+ end
11
+
12
+ def address
13
+ formatted_address
14
+ end
15
+
16
+ def state
17
+ province
18
+ end
19
+
20
+ def province
21
+ address_components['province']
22
+ end
23
+
24
+ def city
25
+ address_components['city'] == [] ? province : address_components["city"]
26
+ end
27
+
28
+ def district
29
+ address_components['district']
30
+ end
31
+
32
+ def street
33
+ if address_components["neighborhood"]["name"] != []
34
+ return address_components["neighborhood"]["name"]
35
+ elsif address_components['township'] != []
36
+ return address_components["township"]
37
+ else
38
+ return @data['street'] || address_components['streetNumber'].try(:[], 'street')
39
+ end
40
+ end
41
+
42
+ def street_number
43
+ @data['number'] || address_components['streetNumber'].try(:[], 'number')
44
+ end
45
+
46
+ def formatted_address
47
+ @data['formatted_address']
48
+ end
49
+
50
+ def address_components
51
+ @data['addressComponent'] || @data
52
+ end
53
+
54
+ def state_code
55
+ ""
56
+ end
57
+
58
+ def postal_code
59
+ ""
60
+ end
61
+
62
+ def country
63
+ "China"
64
+ end
65
+
66
+ def country_code
67
+ "CN"
68
+ end
69
+
70
+ ##
71
+ # Get address components of a given type. Valid types are defined in
72
+ # Baidu's Geocoding API documentation and include (among others):
73
+ #
74
+ # :business
75
+ # :cityCode
76
+ #
77
+ def self.response_attributes
78
+ %w[roads pois roadinters]
79
+ end
80
+
81
+ response_attributes.each do |a|
82
+ define_method a do
83
+ @data[a]
84
+ end
85
+ end
86
+ end
87
+ end
@@ -11,34 +11,34 @@ module Geocoder::Result
11
11
  @data['formatted_address']
12
12
  end
13
13
 
14
- def state
15
- province
16
- end
17
-
18
14
  def province
19
- @data['addressComponent']['province']
15
+ @data['addressComponent'] and @data['addressComponent']['province'] or ""
20
16
  end
21
17
 
18
+ alias_method :state, :province
19
+
22
20
  def city
23
- @data['addressComponent']['city']
21
+ @data['addressComponent'] and @data['addressComponent']['city'] or ""
24
22
  end
25
23
 
26
24
  def district
27
- @data['addressComponent']['district']
25
+ @data['addressComponent'] and @data['addressComponent']['district'] or ""
28
26
  end
29
27
 
30
28
  def street
31
- @data['addressComponent']['street']
29
+ @data['addressComponent'] and @data['addressComponent']['street'] or ""
32
30
  end
33
31
 
34
32
  def street_number
35
- @data['addressComponent']['street_number']
33
+ @data['addressComponent'] and @data['addressComponent']['street_number']
36
34
  end
37
35
 
38
36
  def formatted_address
39
- @data['formatted_address']
37
+ @data['formatted_address'] or ""
40
38
  end
41
39
 
40
+ alias_method :address, :formatted_address
41
+
42
42
  def address_components
43
43
  @data['addressComponent']
44
44
  end
@@ -20,8 +20,20 @@ module Geocoder
20
20
  ##
21
21
  # A string in the given format.
22
22
  #
23
+ # This default implementation dumbly follows the United States address
24
+ # format and will return incorrect results for most countries. Some APIs
25
+ # return properly formatted addresses and those should be funneled
26
+ # through this method.
27
+ #
23
28
  def address(format = :full)
24
- fail
29
+ if state_code.to_s != ""
30
+ s = ", #{state_code}"
31
+ elsif state.to_s != ""
32
+ s = ", #{state}"
33
+ else
34
+ s = ""
35
+ end
36
+ "#{city}#{s} #{postal_code}, #{country}".sub(/^[ ,]*/, '')
25
37
  end
26
38
 
27
39
  ##
@@ -24,7 +24,7 @@ module Geocoder::Result
24
24
  alias_method :country_code, :country
25
25
 
26
26
  def postal_code
27
- @data['address']['postalCode']
27
+ @data['address']['postalCode'].to_s
28
28
  end
29
29
 
30
30
  def coordinates
@@ -0,0 +1,58 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class DbIpCom < Base
5
+
6
+ def coordinates
7
+ ['latitude', 'longitude'].map{ |coordinate_name| @data[coordinate_name] }
8
+ end
9
+
10
+ def city
11
+ @data['city']
12
+ end
13
+
14
+ def district
15
+ @data['district']
16
+ end
17
+
18
+ def state_code
19
+ @data['stateProv']
20
+ end
21
+ alias_method :state, :state_code
22
+
23
+ def zip_code
24
+ @data['zipCode']
25
+ end
26
+ alias_method :postal_code, :zip_code
27
+
28
+ def country_name
29
+ @data['countryName']
30
+ end
31
+ alias_method :country, :country_name
32
+
33
+ def country_code
34
+ @data['countryCode']
35
+ end
36
+
37
+ def continent_name
38
+ @data['continentName']
39
+ end
40
+ alias_method :continent, :continent_name
41
+
42
+ def continent_code
43
+ @data['continentCode']
44
+ end
45
+
46
+ def time_zone
47
+ @data['timeZone']
48
+ end
49
+
50
+ def gmt_offset
51
+ @data['gmtOffset']
52
+ end
53
+
54
+ def currency_code
55
+ @data['currencyCode']
56
+ end
57
+ end
58
+ end
@@ -3,11 +3,6 @@ require 'geocoder/results/base'
3
3
  module Geocoder::Result
4
4
  class Freegeoip < 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
@@ -16,17 +16,17 @@ module Geocoder::Result
16
16
  end
17
17
 
18
18
  def city
19
- @data['city']
19
+ @data['city'] or (@data['standard'] and @data['standard']['city']) or ""
20
20
  end
21
21
 
22
22
  def state
23
- @data['prov']
23
+ @data['prov'] or (@data['standard'] and @data['standard']['prov']) or ""
24
24
  end
25
25
 
26
26
  alias_method :state_code, :state
27
27
 
28
28
  def postal_code
29
- @data['postal']
29
+ @data['postal'] or (@data['standard'] and @data['standard']['postal']) or ""
30
30
  end
31
31
 
32
32
  def country