geocoder2 0.1.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.
- data/.gitignore +5 -0
- data/.travis.yml +27 -0
- data/CHANGELOG.md +329 -0
- data/LICENSE +20 -0
- data/README.md +796 -0
- data/Rakefile +25 -0
- data/bin/geocode2 +5 -0
- data/examples/autoexpire_cache_dalli.rb +62 -0
- data/examples/autoexpire_cache_redis.rb +28 -0
- data/examples/cache_bypass.rb +48 -0
- data/gemfiles/Gemfile.mongoid-2.4.x +15 -0
- data/json?address=26+leonard+street%2C+Belmont&key=AIzaSyDoltU6YL8XeIQrSLFGk6ZfpKaWkPukwYQ&language=en +68 -0
- data/lib/generators/geocoder2/config/config_generator.rb +14 -0
- data/lib/generators/geocoder2/config/templates/initializer.rb +21 -0
- data/lib/geocoder2/cache.rb +89 -0
- data/lib/geocoder2/calculations.rb +389 -0
- data/lib/geocoder2/cli.rb +121 -0
- data/lib/geocoder2/configuration.rb +130 -0
- data/lib/geocoder2/configuration_hash.rb +11 -0
- data/lib/geocoder2/exceptions.rb +21 -0
- data/lib/geocoder2/lookup.rb +86 -0
- data/lib/geocoder2/lookups/baidu.rb +54 -0
- data/lib/geocoder2/lookups/base.rb +266 -0
- data/lib/geocoder2/lookups/bing.rb +47 -0
- data/lib/geocoder2/lookups/dstk.rb +20 -0
- data/lib/geocoder2/lookups/esri.rb +48 -0
- data/lib/geocoder2/lookups/freegeoip.rb +43 -0
- data/lib/geocoder2/lookups/geocoder_ca.rb +54 -0
- data/lib/geocoder2/lookups/geocoder_us.rb +39 -0
- data/lib/geocoder2/lookups/google.rb +69 -0
- data/lib/geocoder2/lookups/google_premier.rb +47 -0
- data/lib/geocoder2/lookups/mapquest.rb +59 -0
- data/lib/geocoder2/lookups/maxmind.rb +88 -0
- data/lib/geocoder2/lookups/nominatim.rb +44 -0
- data/lib/geocoder2/lookups/ovi.rb +62 -0
- data/lib/geocoder2/lookups/test.rb +44 -0
- data/lib/geocoder2/lookups/yahoo.rb +86 -0
- data/lib/geocoder2/lookups/yandex.rb +54 -0
- data/lib/geocoder2/models/active_record.rb +46 -0
- data/lib/geocoder2/models/base.rb +42 -0
- data/lib/geocoder2/models/mongo_base.rb +60 -0
- data/lib/geocoder2/models/mongo_mapper.rb +26 -0
- data/lib/geocoder2/models/mongoid.rb +32 -0
- data/lib/geocoder2/query.rb +107 -0
- data/lib/geocoder2/railtie.rb +26 -0
- data/lib/geocoder2/request.rb +23 -0
- data/lib/geocoder2/results/baidu.rb +79 -0
- data/lib/geocoder2/results/base.rb +67 -0
- data/lib/geocoder2/results/bing.rb +48 -0
- data/lib/geocoder2/results/dstk.rb +6 -0
- data/lib/geocoder2/results/esri.rb +51 -0
- data/lib/geocoder2/results/freegeoip.rb +45 -0
- data/lib/geocoder2/results/geocoder_ca.rb +60 -0
- data/lib/geocoder2/results/geocoder_us.rb +39 -0
- data/lib/geocoder2/results/google.rb +124 -0
- data/lib/geocoder2/results/google_premier.rb +6 -0
- data/lib/geocoder2/results/mapquest.rb +51 -0
- data/lib/geocoder2/results/maxmind.rb +135 -0
- data/lib/geocoder2/results/nominatim.rb +94 -0
- data/lib/geocoder2/results/ovi.rb +62 -0
- data/lib/geocoder2/results/test.rb +16 -0
- data/lib/geocoder2/results/yahoo.rb +55 -0
- data/lib/geocoder2/results/yandex.rb +80 -0
- data/lib/geocoder2/sql.rb +106 -0
- data/lib/geocoder2/stores/active_record.rb +272 -0
- data/lib/geocoder2/stores/base.rb +120 -0
- data/lib/geocoder2/stores/mongo_base.rb +89 -0
- data/lib/geocoder2/stores/mongo_mapper.rb +13 -0
- data/lib/geocoder2/stores/mongoid.rb +13 -0
- data/lib/geocoder2/version.rb +3 -0
- data/lib/geocoder2.rb +55 -0
- data/lib/hash_recursive_merge.rb +74 -0
- data/lib/oauth_util.rb +112 -0
- data/lib/tasks/geocoder2.rake +27 -0
- data/test/active_record_test.rb +15 -0
- data/test/cache_test.rb +35 -0
- data/test/calculations_test.rb +211 -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/baidu_invalid_key +1 -0
- data/test/fixtures/baidu_no_results +1 -0
- data/test/fixtures/baidu_reverse +1 -0
- data/test/fixtures/baidu_shanghai_pearl_tower +12 -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/esri_madison_square_garden +59 -0
- data/test/fixtures/esri_no_results +8 -0
- data/test/fixtures/esri_reverse +21 -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/geocoder_us_madison_square_garden +1 -0
- data/test/fixtures/geocoder_us_no_results +1 -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/google_over_limit +4 -0
- data/test/fixtures/mapquest_error +16 -0
- data/test/fixtures/mapquest_invalid_api_key +16 -0
- data/test/fixtures/mapquest_invalid_request +16 -0
- data/test/fixtures/mapquest_madison_square_garden +52 -0
- data/test/fixtures/mapquest_no_results +16 -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 +117 -0
- data/test/method_aliases_test.rb +25 -0
- data/test/mongoid_test.rb +46 -0
- data/test/mongoid_test_helper.rb +43 -0
- data/test/near_test.rb +61 -0
- data/test/oauth_util_test.rb +30 -0
- data/test/proxy_test.rb +36 -0
- data/test/query_test.rb +52 -0
- data/test/request_test.rb +29 -0
- data/test/result_test.rb +42 -0
- data/test/services_test.rb +393 -0
- data/test/test_helper.rb +289 -0
- data/test/test_mode_test.rb +59 -0
- metadata +213 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'geocoder2'
|
|
2
|
+
|
|
3
|
+
module Geocoder2
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# Methods for invoking Geocoder2 in a model.
|
|
7
|
+
#
|
|
8
|
+
module Model
|
|
9
|
+
module MongoBase
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Set attribute names and include the Geocoder2 module.
|
|
13
|
+
#
|
|
14
|
+
def geocoded_by(address_attr, options = {}, &block)
|
|
15
|
+
geocoder2_init(
|
|
16
|
+
:geocode => true,
|
|
17
|
+
:user_address => address_attr,
|
|
18
|
+
:coordinates => options[:coordinates] || :coordinates,
|
|
19
|
+
:geocode_block => block,
|
|
20
|
+
:units => options[:units],
|
|
21
|
+
:method => options[:method],
|
|
22
|
+
:skip_index => options[:skip_index] || false
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Set attribute names and include the Geocoder2 module.
|
|
28
|
+
#
|
|
29
|
+
def reverse_geocoded_by(coordinates_attr, options = {}, &block)
|
|
30
|
+
geocoder2_init(
|
|
31
|
+
:reverse_geocode => true,
|
|
32
|
+
:fetched_address => options[:address] || :address,
|
|
33
|
+
:coordinates => coordinates_attr,
|
|
34
|
+
:reverse_block => block,
|
|
35
|
+
:units => options[:units],
|
|
36
|
+
:method => options[:method],
|
|
37
|
+
:skip_index => options[:skip_index] || false
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private # ----------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
def geocoder2_init(options)
|
|
44
|
+
unless geocoder2_initialized?
|
|
45
|
+
@geocoder2_options = { }
|
|
46
|
+
require "geocoder2/stores/#{geocoder2_file_name}"
|
|
47
|
+
include Geocoder2::Store.const_get(geocoder2_module_name)
|
|
48
|
+
end
|
|
49
|
+
@geocoder2_options.merge! options
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def geocoder2_initialized?
|
|
53
|
+
included_modules.include? Geocoder2::Store.const_get(geocoder2_module_name)
|
|
54
|
+
rescue NameError
|
|
55
|
+
false
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'geocoder2/models/base'
|
|
2
|
+
require 'geocoder2/models/mongo_base'
|
|
3
|
+
|
|
4
|
+
module Geocoder2
|
|
5
|
+
module Model
|
|
6
|
+
module MongoMapper
|
|
7
|
+
include Base
|
|
8
|
+
include MongoBase
|
|
9
|
+
|
|
10
|
+
def self.included(base); base.extend(self); end
|
|
11
|
+
|
|
12
|
+
private # --------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
def geocoder2_file_name; "mongo_mapper"; end
|
|
15
|
+
def geocoder2_module_name; "MongoMapper"; end
|
|
16
|
+
|
|
17
|
+
def geocoder2_init(options)
|
|
18
|
+
super(options)
|
|
19
|
+
if options[:skip_index] == false
|
|
20
|
+
ensure_index [[ geocoder2_options[:coordinates], Mongo::GEO2D ]],
|
|
21
|
+
:min => -180, :max => 180 # create 2d index
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'geocoder2/models/base'
|
|
2
|
+
require 'geocoder2/models/mongo_base'
|
|
3
|
+
|
|
4
|
+
module Geocoder2
|
|
5
|
+
module Model
|
|
6
|
+
module Mongoid
|
|
7
|
+
include Base
|
|
8
|
+
include MongoBase
|
|
9
|
+
|
|
10
|
+
def self.included(base); base.extend(self); end
|
|
11
|
+
|
|
12
|
+
private # --------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
def geocoder2_file_name; "mongoid"; end
|
|
15
|
+
def geocoder2_module_name; "Mongoid"; end
|
|
16
|
+
|
|
17
|
+
def geocoder2_init(options)
|
|
18
|
+
super(options)
|
|
19
|
+
if options[:skip_index] == false
|
|
20
|
+
# create 2d index
|
|
21
|
+
if defined?(::Mongoid::VERSION) && ::Mongoid::VERSION >= "3"
|
|
22
|
+
index({ geocoder2_options[:coordinates].to_sym => '2d' },
|
|
23
|
+
{:min => -180, :max => 180})
|
|
24
|
+
else
|
|
25
|
+
index [[ geocoder2_options[:coordinates], '2d' ]],
|
|
26
|
+
:min => -180, :max => 180
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
module Geocoder2
|
|
2
|
+
class Query
|
|
3
|
+
attr_accessor :text, :options
|
|
4
|
+
|
|
5
|
+
def initialize(text, options = {})
|
|
6
|
+
self.text = text
|
|
7
|
+
self.options = options
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def execute
|
|
11
|
+
lookup.search(text, options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_s
|
|
15
|
+
text
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def sanitized_text
|
|
19
|
+
if coordinates?
|
|
20
|
+
if text.is_a?(Array)
|
|
21
|
+
text.join(',')
|
|
22
|
+
else
|
|
23
|
+
text.split(/\s*,\s*/).join(',')
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
text
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# Get a Lookup object (which communicates with the remote geocoding API)
|
|
32
|
+
# appropriate to the Query text.
|
|
33
|
+
#
|
|
34
|
+
def lookup
|
|
35
|
+
if ip_address?
|
|
36
|
+
name = Configuration.ip_lookup || Geocoder2::Lookup.ip_services.first
|
|
37
|
+
else
|
|
38
|
+
name = Configuration.lookup || Geocoder2::Lookup.street_services.first
|
|
39
|
+
end
|
|
40
|
+
Lookup.get(name)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def url
|
|
44
|
+
lookup.query_url(self)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
##
|
|
48
|
+
# Is the Query blank? (ie, should we not bother searching?)
|
|
49
|
+
# A query is considered blank if its text is nil or empty string AND
|
|
50
|
+
# no URL parameters are specified.
|
|
51
|
+
#
|
|
52
|
+
def blank?
|
|
53
|
+
!params_given? and (
|
|
54
|
+
(text.is_a?(Array) and text.compact.size < 2) or
|
|
55
|
+
text.to_s.match(/\A\s*\z/)
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
##
|
|
60
|
+
# Does the Query text look like an IP address?
|
|
61
|
+
#
|
|
62
|
+
# Does not check for actual validity, just the appearance of four
|
|
63
|
+
# dot-delimited numbers.
|
|
64
|
+
#
|
|
65
|
+
def ip_address?
|
|
66
|
+
!!text.to_s.match(/\A(::ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\z/)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
##
|
|
70
|
+
# Is the Query text a loopback IP address?
|
|
71
|
+
#
|
|
72
|
+
def loopback_ip_address?
|
|
73
|
+
!!(self.ip_address? and (text == "0.0.0.0" or text.to_s.match(/\A127/)))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
##
|
|
77
|
+
# Does the given string look like latitude/longitude coordinates?
|
|
78
|
+
#
|
|
79
|
+
def coordinates?
|
|
80
|
+
text.is_a?(Array) or (
|
|
81
|
+
text.is_a?(String) and
|
|
82
|
+
!!text.to_s.match(/\A-?[0-9\.]+, *-?[0-9\.]+\z/)
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
##
|
|
87
|
+
# Return the latitude/longitude coordinates specified in the query,
|
|
88
|
+
# or nil if none.
|
|
89
|
+
#
|
|
90
|
+
def coordinates
|
|
91
|
+
sanitized_text.split(',') if coordinates?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
##
|
|
95
|
+
# Should reverse geocoding be performed for this query?
|
|
96
|
+
#
|
|
97
|
+
def reverse_geocode?
|
|
98
|
+
coordinates?
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private # ----------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
def params_given?
|
|
104
|
+
!!(options[:params].is_a?(Hash) and options[:params].keys.size > 0)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'geocoder2'
|
|
2
|
+
require 'geocoder2/models/active_record'
|
|
3
|
+
|
|
4
|
+
module Geocoder2
|
|
5
|
+
if defined? Rails::Railtie
|
|
6
|
+
require 'rails'
|
|
7
|
+
class Railtie < Rails::Railtie
|
|
8
|
+
initializer 'geocoder2.insert_into_active_record' do
|
|
9
|
+
ActiveSupport.on_load :active_record do
|
|
10
|
+
Geocoder2::Railtie.insert
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
rake_tasks do
|
|
14
|
+
load "tasks/geocoder2.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 'geocoder2'
|
|
2
|
+
|
|
3
|
+
module Geocoder2
|
|
4
|
+
module Request
|
|
5
|
+
|
|
6
|
+
def location
|
|
7
|
+
unless defined?(@location)
|
|
8
|
+
if env.has_key?('HTTP_X_REAL_IP')
|
|
9
|
+
@location = Geocoder2.search(env['HTTP_X_REAL_IP']).first
|
|
10
|
+
elsif env.has_key?('HTTP_X_FORWARDED_FOR')
|
|
11
|
+
@location = Geocoder2.search(env['HTTP_X_FORWARDED_FOR'].split(/\s*,\s*/)[0]).first
|
|
12
|
+
else
|
|
13
|
+
@location = Geocoder2.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, Geocoder2::Request
|
|
23
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require 'geocoder2/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder2::Result
|
|
4
|
+
class Baidu < Base
|
|
5
|
+
|
|
6
|
+
def coordinates
|
|
7
|
+
['lat', 'lng'].map{ |i| @data['location'][i] }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def address
|
|
11
|
+
@data['formatted_address']
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def state
|
|
15
|
+
province
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def province
|
|
19
|
+
@data['addressComponent']['province']
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def city
|
|
23
|
+
@data['addressComponent']['city']
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def district
|
|
27
|
+
@data['addressComponent']['district']
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def street
|
|
31
|
+
@data['addressComponent']['street']
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def street_number
|
|
35
|
+
@data['addressComponent']['street_number']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def formatted_address
|
|
39
|
+
@data['formatted_address']
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def address_components
|
|
43
|
+
@data['addressComponent']
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def state_code
|
|
47
|
+
""
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def postal_code
|
|
51
|
+
""
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def country
|
|
55
|
+
"China"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def country_code
|
|
59
|
+
"CN"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
##
|
|
63
|
+
# Get address components of a given type. Valid types are defined in
|
|
64
|
+
# Baidu's Geocoding API documentation and include (among others):
|
|
65
|
+
#
|
|
66
|
+
# :business
|
|
67
|
+
# :cityCode
|
|
68
|
+
#
|
|
69
|
+
def self.response_attributes
|
|
70
|
+
%w[business cityCode]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
response_attributes.each do |a|
|
|
74
|
+
define_method a do
|
|
75
|
+
@data[a]
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module Geocoder2
|
|
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 'geocoder2/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder2::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,51 @@
|
|
|
1
|
+
require 'geocoder2/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder2::Result
|
|
4
|
+
class Esri < Base
|
|
5
|
+
|
|
6
|
+
def address
|
|
7
|
+
address = reverse_geocode? ? 'Address' : 'Match_addr'
|
|
8
|
+
attributes[address]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def city
|
|
12
|
+
attributes['City']
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def state_code
|
|
16
|
+
attributes['Region']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
alias_method :state, :state_code
|
|
20
|
+
|
|
21
|
+
def country
|
|
22
|
+
country = reverse_geocode? ? "CountryCode" : "Country"
|
|
23
|
+
attributes[country]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
alias_method :country_code, :country
|
|
27
|
+
|
|
28
|
+
def postal_code
|
|
29
|
+
attributes['Postal']
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def coordinates
|
|
33
|
+
[geometry["y"], geometry["x"]]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def attributes
|
|
39
|
+
reverse_geocode? ? @data['address'] : @data['locations'].first['feature']['attributes']
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def geometry
|
|
43
|
+
reverse_geocode? ? @data["location"] : @data['locations'].first['feature']["geometry"]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def reverse_geocode?
|
|
47
|
+
@data['locations'].nil?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'geocoder2/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder2::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 'geocoder2/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder2::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,39 @@
|
|
|
1
|
+
require 'geocoder2/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder2::Result
|
|
4
|
+
class GeocoderUs < Base
|
|
5
|
+
def coordinates
|
|
6
|
+
[@data[0].to_f, @data[1].to_f]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def address(format = :full)
|
|
10
|
+
"#{street_address}, #{city}, #{state} #{postal_code}, #{country}".sub(/^[ ,]*/, "")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def street_address
|
|
14
|
+
@data[2]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def city
|
|
18
|
+
@data[3]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def state
|
|
22
|
+
@data[4]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
alias_method :state_code, :state
|
|
26
|
+
|
|
27
|
+
def postal_code
|
|
28
|
+
@data[5]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def country
|
|
32
|
+
'United States'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def country_code
|
|
36
|
+
'US'
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|