geocoder-sgonyea 1.1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/.travis.yml +23 -0
- data/CHANGELOG.md +298 -0
- data/LICENSE +20 -0
- data/README.md +656 -0
- data/Rakefile +25 -0
- data/bin/geocode +5 -0
- data/examples/autoexpire_cache.rb +28 -0
- data/gemfiles/Gemfile.mongoid-2.4.x +15 -0
- data/lib/generators/geocoder/config/config_generator.rb +14 -0
- data/lib/generators/geocoder/config/templates/initializer.rb +21 -0
- data/lib/geocoder.rb +55 -0
- data/lib/geocoder/cache.rb +85 -0
- data/lib/geocoder/calculations.rb +319 -0
- data/lib/geocoder/cli.rb +114 -0
- data/lib/geocoder/configuration.rb +130 -0
- data/lib/geocoder/configuration_hash.rb +11 -0
- data/lib/geocoder/exceptions.rb +21 -0
- data/lib/geocoder/lookup.rb +82 -0
- data/lib/geocoder/lookups/base.rb +250 -0
- data/lib/geocoder/lookups/bing.rb +47 -0
- data/lib/geocoder/lookups/freegeoip.rb +47 -0
- data/lib/geocoder/lookups/geocoder_ca.rb +54 -0
- data/lib/geocoder/lookups/google.rb +62 -0
- data/lib/geocoder/lookups/google_premier.rb +47 -0
- data/lib/geocoder/lookups/mapquest.rb +43 -0
- data/lib/geocoder/lookups/maxmind.rb +88 -0
- data/lib/geocoder/lookups/nominatim.rb +45 -0
- data/lib/geocoder/lookups/ovi.rb +52 -0
- data/lib/geocoder/lookups/test.rb +38 -0
- data/lib/geocoder/lookups/yahoo.rb +84 -0
- data/lib/geocoder/lookups/yandex.rb +54 -0
- data/lib/geocoder/models/active_record.rb +46 -0
- data/lib/geocoder/models/base.rb +42 -0
- data/lib/geocoder/models/mongo_base.rb +60 -0
- data/lib/geocoder/models/mongo_mapper.rb +26 -0
- data/lib/geocoder/models/mongoid.rb +32 -0
- data/lib/geocoder/query.rb +103 -0
- data/lib/geocoder/railtie.rb +26 -0
- data/lib/geocoder/request.rb +23 -0
- data/lib/geocoder/results/base.rb +67 -0
- data/lib/geocoder/results/bing.rb +48 -0
- data/lib/geocoder/results/freegeoip.rb +45 -0
- data/lib/geocoder/results/geocoder_ca.rb +60 -0
- data/lib/geocoder/results/google.rb +106 -0
- data/lib/geocoder/results/google_premier.rb +6 -0
- data/lib/geocoder/results/mapquest.rb +51 -0
- data/lib/geocoder/results/maxmind.rb +136 -0
- data/lib/geocoder/results/nominatim.rb +94 -0
- data/lib/geocoder/results/ovi.rb +62 -0
- data/lib/geocoder/results/test.rb +16 -0
- data/lib/geocoder/results/yahoo.rb +55 -0
- data/lib/geocoder/results/yandex.rb +80 -0
- data/lib/geocoder/sql.rb +106 -0
- data/lib/geocoder/stores/active_record.rb +259 -0
- data/lib/geocoder/stores/base.rb +120 -0
- data/lib/geocoder/stores/mongo_base.rb +85 -0
- data/lib/geocoder/stores/mongo_mapper.rb +13 -0
- data/lib/geocoder/stores/mongoid.rb +13 -0
- data/lib/geocoder/version.rb +3 -0
- data/lib/hash_recursive_merge.rb +74 -0
- data/lib/oauth_util.rb +112 -0
- data/lib/tasks/geocoder.rake +25 -0
- data/test/active_record_test.rb +15 -0
- data/test/cache_test.rb +19 -0
- data/test/calculations_test.rb +195 -0
- data/test/configuration_test.rb +78 -0
- data/test/custom_block_test.rb +32 -0
- data/test/error_handling_test.rb +43 -0
- data/test/fixtures/bing_invalid_key +1 -0
- data/test/fixtures/bing_madison_square_garden +40 -0
- data/test/fixtures/bing_no_results +16 -0
- data/test/fixtures/bing_reverse +42 -0
- data/test/fixtures/freegeoip_74_200_247_59 +12 -0
- data/test/fixtures/freegeoip_no_results +1 -0
- data/test/fixtures/geocoder_ca_madison_square_garden +1 -0
- data/test/fixtures/geocoder_ca_no_results +1 -0
- data/test/fixtures/geocoder_ca_reverse +34 -0
- data/test/fixtures/google_garbage +456 -0
- data/test/fixtures/google_madison_square_garden +57 -0
- data/test/fixtures/google_no_city_data +44 -0
- data/test/fixtures/google_no_locality +51 -0
- data/test/fixtures/google_no_results +4 -0
- data/test/fixtures/mapquest_madison_square_garden +52 -0
- data/test/fixtures/mapquest_no_results +7 -0
- data/test/fixtures/maxmind_24_24_24_21 +1 -0
- data/test/fixtures/maxmind_24_24_24_22 +1 -0
- data/test/fixtures/maxmind_24_24_24_23 +1 -0
- data/test/fixtures/maxmind_24_24_24_24 +1 -0
- data/test/fixtures/maxmind_74_200_247_59 +1 -0
- data/test/fixtures/maxmind_invalid_key +1 -0
- data/test/fixtures/maxmind_no_results +1 -0
- data/test/fixtures/nominatim_madison_square_garden +150 -0
- data/test/fixtures/nominatim_no_results +1 -0
- data/test/fixtures/ovi_madison_square_garden +72 -0
- data/test/fixtures/ovi_no_results +8 -0
- data/test/fixtures/yahoo_error +1 -0
- data/test/fixtures/yahoo_invalid_key +2 -0
- data/test/fixtures/yahoo_madison_square_garden +52 -0
- data/test/fixtures/yahoo_no_results +10 -0
- data/test/fixtures/yahoo_over_limit +2 -0
- data/test/fixtures/yandex_invalid_key +1 -0
- data/test/fixtures/yandex_kremlin +48 -0
- data/test/fixtures/yandex_no_city_and_town +112 -0
- data/test/fixtures/yandex_no_results +16 -0
- data/test/geocoder_test.rb +59 -0
- data/test/https_test.rb +16 -0
- data/test/integration/smoke_test.rb +26 -0
- data/test/lookup_test.rb +116 -0
- data/test/method_aliases_test.rb +25 -0
- data/test/mongoid_test.rb +39 -0
- data/test/mongoid_test_helper.rb +43 -0
- data/test/near_test.rb +43 -0
- data/test/oauth_util_test.rb +30 -0
- data/test/proxy_test.rb +23 -0
- data/test/query_test.rb +51 -0
- data/test/request_test.rb +29 -0
- data/test/result_test.rb +42 -0
- data/test/services_test.rb +277 -0
- data/test/test_helper.rb +279 -0
- data/test/test_mode_test.rb +50 -0
- metadata +170 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'geocoder'
|
|
2
|
+
require 'geocoder/models/active_record'
|
|
3
|
+
|
|
4
|
+
module Geocoder
|
|
5
|
+
if defined? Rails::Railtie
|
|
6
|
+
require 'rails'
|
|
7
|
+
class Railtie < Rails::Railtie
|
|
8
|
+
initializer 'geocoder.insert_into_active_record' do
|
|
9
|
+
ActiveSupport.on_load :active_record do
|
|
10
|
+
Geocoder::Railtie.insert
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
rake_tasks do
|
|
14
|
+
load "tasks/geocoder.rake"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class Railtie
|
|
20
|
+
def self.insert
|
|
21
|
+
if defined?(::ActiveRecord)
|
|
22
|
+
::ActiveRecord::Base.extend(Model::ActiveRecord)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'geocoder'
|
|
2
|
+
|
|
3
|
+
module Geocoder
|
|
4
|
+
module Request
|
|
5
|
+
|
|
6
|
+
def location
|
|
7
|
+
unless defined?(@location)
|
|
8
|
+
if env.has_key?('HTTP_X_REAL_IP')
|
|
9
|
+
@location = Geocoder.search(env['HTTP_X_REAL_IP']).first
|
|
10
|
+
elsif env.has_key?('HTTP_X_FORWARDED_FOR')
|
|
11
|
+
@location = Geocoder.search(env['HTTP_X_FORWARDED_FOR'].split(/\s*,\s*/)[0]).first
|
|
12
|
+
else
|
|
13
|
+
@location = Geocoder.search(ip).first
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
@location
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
if defined?(Rack) and defined?(Rack::Request)
|
|
22
|
+
Rack::Request.send :include, Geocoder::Request
|
|
23
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module Geocoder
|
|
2
|
+
module Result
|
|
3
|
+
class Base
|
|
4
|
+
|
|
5
|
+
# data (hash) fetched from geocoding service
|
|
6
|
+
attr_accessor :data
|
|
7
|
+
|
|
8
|
+
# true if result came from cache, false if from request to geocoding
|
|
9
|
+
# service; nil if cache is not configured
|
|
10
|
+
attr_accessor :cache_hit
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
# Takes a hash of data from a parsed geocoding service response.
|
|
14
|
+
#
|
|
15
|
+
def initialize(data)
|
|
16
|
+
@data = data
|
|
17
|
+
@cache_hit = nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# A string in the given format.
|
|
22
|
+
#
|
|
23
|
+
def address(format = :full)
|
|
24
|
+
fail
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# A two-element array: [lat, lon].
|
|
29
|
+
#
|
|
30
|
+
def coordinates
|
|
31
|
+
[@data['latitude'].to_f, @data['longitude'].to_f]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def latitude
|
|
35
|
+
coordinates[0]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def longitude
|
|
39
|
+
coordinates[1]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def state
|
|
43
|
+
fail
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def province
|
|
47
|
+
state
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def state_code
|
|
51
|
+
fail
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def province_code
|
|
55
|
+
state_code
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def country
|
|
59
|
+
fail
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def country_code
|
|
63
|
+
fail
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'geocoder/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder::Result
|
|
4
|
+
class Bing < Base
|
|
5
|
+
|
|
6
|
+
def address(format = :full)
|
|
7
|
+
@data['address']['formattedAddress']
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def city
|
|
11
|
+
@data['address']['locality']
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def state_code
|
|
15
|
+
@data['address']['adminDistrict']
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
alias_method :state, :state_code
|
|
19
|
+
|
|
20
|
+
def country
|
|
21
|
+
@data['address']['countryRegion']
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
alias_method :country_code, :country
|
|
25
|
+
|
|
26
|
+
def postal_code
|
|
27
|
+
@data['address']['postalCode']
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def coordinates
|
|
31
|
+
@data['point']['coordinates']
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def address_data
|
|
35
|
+
@data['address']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.response_attributes
|
|
39
|
+
%w[bbox name confidence entityType]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
response_attributes.each do |a|
|
|
43
|
+
define_method a do
|
|
44
|
+
@data[a]
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'geocoder/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder::Result
|
|
4
|
+
class Freegeoip < Base
|
|
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
|
+
def city
|
|
12
|
+
@data['city']
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def state
|
|
16
|
+
@data['region_name']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def state_code
|
|
20
|
+
@data['region_code']
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def country
|
|
24
|
+
@data['country_name']
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def country_code
|
|
28
|
+
@data['country_code']
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def postal_code
|
|
32
|
+
@data['zipcode']
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.response_attributes
|
|
36
|
+
%w[metrocode ip]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
response_attributes.each do |a|
|
|
40
|
+
define_method a do
|
|
41
|
+
@data[a]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'geocoder/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder::Result
|
|
4
|
+
class GeocoderCa < Base
|
|
5
|
+
|
|
6
|
+
def coordinates
|
|
7
|
+
[@data['latt'].to_f, @data['longt'].to_f]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def address(format = :full)
|
|
11
|
+
"#{street_address}, #{city}, #{state} #{postal_code}, #{country}".sub(/^[ ,]*/, "")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def street_address
|
|
15
|
+
"#{@data['stnumber']} #{@data['staddress']}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def city
|
|
19
|
+
@data['city']
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def state
|
|
23
|
+
@data['prov']
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
alias_method :state_code, :state
|
|
27
|
+
|
|
28
|
+
def postal_code
|
|
29
|
+
@data['postal']
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def country
|
|
33
|
+
country_code == 'CA' ? 'Canada' : 'United States'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def country_code
|
|
37
|
+
return nil if state.nil? || state == ""
|
|
38
|
+
canadian_province_abbreviations.include?(state) ? "CA" : "US"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.response_attributes
|
|
42
|
+
%w[latt longt inlatt inlongt distance stnumber staddress prov
|
|
43
|
+
NearRoad NearRoadDistance betweenRoad1 betweenRoad2
|
|
44
|
+
intersection major_intersection]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
response_attributes.each do |a|
|
|
48
|
+
define_method a do
|
|
49
|
+
@data[a]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
private # ----------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
def canadian_province_abbreviations
|
|
57
|
+
%w[ON QC NS NB MB BC PE SK AB NL]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
require 'geocoder/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder::Result
|
|
4
|
+
class Google < 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
|
+
if state = address_components_of_type(:administrative_area_level_1).first
|
|
28
|
+
state['long_name']
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def state_code
|
|
33
|
+
if state = address_components_of_type(:administrative_area_level_1).first
|
|
34
|
+
state['short_name']
|
|
35
|
+
end
|
|
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
|
+
[street_number, route].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,51 @@
|
|
|
1
|
+
require 'geocoder/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder::Result
|
|
4
|
+
class Mapquest < Base
|
|
5
|
+
def latitude
|
|
6
|
+
@data["latLng"]["lat"]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def longitude
|
|
10
|
+
@data["latLng"]["lng"]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def coordinates
|
|
14
|
+
[latitude, longitude]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def city
|
|
18
|
+
@data['adminArea5']
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def street
|
|
22
|
+
@data['street']
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def state
|
|
26
|
+
@data['adminArea3']
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
alias_method :state_code, :state
|
|
30
|
+
|
|
31
|
+
#FIXME: these might not be right, unclear with MQ documentation
|
|
32
|
+
alias_method :province, :state
|
|
33
|
+
alias_method :province_code, :state
|
|
34
|
+
|
|
35
|
+
def postal_code
|
|
36
|
+
@data['postalCode'].to_s
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def country
|
|
40
|
+
@data['adminArea1']
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def country_code
|
|
44
|
+
country
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def address
|
|
48
|
+
[street, city, state, postal_code, country].reject{|s| s.length == 0 }.join(", ")
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
require 'geocoder/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder::Result
|
|
4
|
+
class Maxmind < Base
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# Hash mapping service names to names of returned fields.
|
|
8
|
+
#
|
|
9
|
+
def self.field_names
|
|
10
|
+
{
|
|
11
|
+
:country => [
|
|
12
|
+
:country_code,
|
|
13
|
+
:error
|
|
14
|
+
],
|
|
15
|
+
|
|
16
|
+
:city => [
|
|
17
|
+
:country_code,
|
|
18
|
+
:region_code,
|
|
19
|
+
:city_name,
|
|
20
|
+
:latitude,
|
|
21
|
+
:longitude,
|
|
22
|
+
:error
|
|
23
|
+
],
|
|
24
|
+
|
|
25
|
+
:city_isp_org => [
|
|
26
|
+
:country_code,
|
|
27
|
+
:region_code,
|
|
28
|
+
:city_name,
|
|
29
|
+
:postal_code,
|
|
30
|
+
:latitude,
|
|
31
|
+
:longitude,
|
|
32
|
+
:metro_code,
|
|
33
|
+
:area_code,
|
|
34
|
+
:isp_name,
|
|
35
|
+
:organization_name,
|
|
36
|
+
:error
|
|
37
|
+
],
|
|
38
|
+
|
|
39
|
+
:omni => [
|
|
40
|
+
:country_code,
|
|
41
|
+
:country_name,
|
|
42
|
+
:region_code,
|
|
43
|
+
:region_name,
|
|
44
|
+
:city_name,
|
|
45
|
+
:latitude,
|
|
46
|
+
:longitude,
|
|
47
|
+
:metro_code,
|
|
48
|
+
:area_code,
|
|
49
|
+
:time_zone,
|
|
50
|
+
:continent_code,
|
|
51
|
+
:postal_code,
|
|
52
|
+
:isp_name,
|
|
53
|
+
:organization_name,
|
|
54
|
+
:domain,
|
|
55
|
+
:as_number,
|
|
56
|
+
:netspeed,
|
|
57
|
+
:user_type,
|
|
58
|
+
:accuracy_radius,
|
|
59
|
+
:country_confidence_factor,
|
|
60
|
+
:city_confidence_factor,
|
|
61
|
+
:region_confidence_factor,
|
|
62
|
+
:postal_confidence_factor,
|
|
63
|
+
:error
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
# Name of the MaxMind service being used.
|
|
70
|
+
# Inferred from format of @data.
|
|
71
|
+
#
|
|
72
|
+
def service_name
|
|
73
|
+
self.class.field_names.to_a.each do |n,f|
|
|
74
|
+
return n if (@data.size..@data.size+1).include?(f.size)
|
|
75
|
+
end
|
|
76
|
+
nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def field_names
|
|
80
|
+
self.class.field_names[service_name]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def data_hash
|
|
84
|
+
@data_hash ||= Hash[*field_names.zip(@data).flatten]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def coordinates
|
|
88
|
+
[data_hash[:latitude].to_f, data_hash[:longitude].to_f]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def address(format = :full)
|
|
92
|
+
s = state_code.to_s == "" ? "" : ", #{state_code}"
|
|
93
|
+
"#{city}#{s} #{postal_code}, #{country_code}".sub(/^[ ,]*/, "")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def city
|
|
97
|
+
data_hash[:city_name]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def state # not given by MaxMind
|
|
101
|
+
data_hash[:region_name] || data_hash[:region_code]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def state_code
|
|
105
|
+
data_hash[:region_code]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def country #not given by MaxMind
|
|
109
|
+
data_hash[:country_name] || data_hash[:country_code]
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def country_code
|
|
113
|
+
data_hash[:country_code]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def postal_code
|
|
117
|
+
data_hash[:postal_code]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def method_missing(method, *args, &block)
|
|
121
|
+
if field_names.include?(method)
|
|
122
|
+
data_hash[method]
|
|
123
|
+
else
|
|
124
|
+
super
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def respond_to?(method)
|
|
129
|
+
if field_names.include?(method)
|
|
130
|
+
true
|
|
131
|
+
else
|
|
132
|
+
super
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|