rails-geocoder 0.9.10 → 0.9.11
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 +1 -0
- data/CHANGELOG.rdoc +15 -4
- data/LICENSE +1 -1
- data/README.rdoc +118 -31
- data/VERSION +1 -1
- data/lib/geocoder.rb +56 -14
- data/lib/geocoder/cache.rb +70 -0
- data/lib/geocoder/calculations.rb +162 -22
- data/lib/geocoder/configuration.rb +46 -9
- data/lib/geocoder/lookups/base.rb +40 -9
- data/lib/geocoder/lookups/freegeoip.rb +4 -6
- data/lib/geocoder/lookups/geocoder_ca.rb +44 -0
- data/lib/geocoder/lookups/google.rb +8 -5
- data/lib/geocoder/lookups/yahoo.rb +6 -4
- data/lib/geocoder/orms/active_record.rb +85 -39
- data/lib/geocoder/orms/active_record_legacy.rb +8 -4
- data/lib/geocoder/orms/base.rb +24 -21
- data/lib/geocoder/request.rb +1 -1
- data/lib/geocoder/results/base.rb +0 -14
- data/lib/geocoder/results/geocoder_ca.rb +58 -0
- data/lib/geocoder/results/google.rb +16 -4
- data/test/fixtures/geocoder_ca_madison_square_garden.json +1 -0
- data/test/fixtures/geocoder_ca_no_results.json +1 -0
- data/test/fixtures/geocoder_ca_reverse.json +34 -0
- data/test/fixtures/google_no_locality.json +51 -0
- data/test/geocoder_test.rb +220 -64
- data/test/test_helper.rb +48 -9
- metadata +15 -15
- data/rails-geocoder.gemspec +0 -14
@@ -6,10 +6,10 @@ module Geocoder::Lookup
|
|
6
6
|
|
7
7
|
private # ---------------------------------------------------------------
|
8
8
|
|
9
|
-
def
|
10
|
-
doc = fetch_data(query, reverse)
|
9
|
+
def results(query, reverse = false)
|
10
|
+
return [] unless doc = fetch_data(query, reverse)
|
11
11
|
case doc['status']; when "OK" # OK status implies >0 results
|
12
|
-
doc['results']
|
12
|
+
return doc['results']
|
13
13
|
when "OVER_QUERY_LIMIT"
|
14
14
|
warn "Google Geocoding API error: over query limit."
|
15
15
|
when "REQUEST_DENIED"
|
@@ -17,14 +17,17 @@ module Geocoder::Lookup
|
|
17
17
|
when "INVALID_REQUEST"
|
18
18
|
warn "Google Geocoding API error: invalid request."
|
19
19
|
end
|
20
|
+
return []
|
20
21
|
end
|
21
22
|
|
22
23
|
def query_url(query, reverse = false)
|
23
24
|
params = {
|
24
25
|
(reverse ? :latlng : :address) => query,
|
25
|
-
:sensor => "false"
|
26
|
+
:sensor => "false",
|
27
|
+
:language => Geocoder::Configuration.language,
|
28
|
+
:key => Geocoder::Configuration.api_key
|
26
29
|
}
|
27
|
-
"
|
30
|
+
"#{protocol}://maps.google.com/maps/api/geocode/json?" + hash_to_query(params)
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
@@ -6,12 +6,13 @@ module Geocoder::Lookup
|
|
6
6
|
|
7
7
|
private # ---------------------------------------------------------------
|
8
8
|
|
9
|
-
def
|
10
|
-
doc = fetch_data(query, reverse)
|
9
|
+
def results(query, reverse = false)
|
10
|
+
return [] unless doc = fetch_data(query, reverse)
|
11
11
|
if doc = doc['ResultSet'] and doc['Error'] == 0
|
12
|
-
doc['
|
12
|
+
return doc['Found'] > 0 ? doc['Results'] : []
|
13
13
|
else
|
14
14
|
warn "Yahoo Geocoding API error: #{doc['Error']} (#{doc['ErrorMessage']})."
|
15
|
+
return []
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
@@ -20,7 +21,8 @@ module Geocoder::Lookup
|
|
20
21
|
:location => query,
|
21
22
|
:flags => "JXTSR",
|
22
23
|
:gflags => "AC#{'R' if reverse}",
|
23
|
-
:
|
24
|
+
:locale => "#{Geocoder::Configuration.language}_US",
|
25
|
+
:appid => Geocoder::Configuration.api_key
|
24
26
|
}
|
25
27
|
"http://where.yahooapis.com/geocode?" + hash_to_query(params)
|
26
28
|
end
|
@@ -27,9 +27,11 @@ module Geocoder::Orm
|
|
27
27
|
"OR #{geocoder_options[:longitude]} IS NULL"}}
|
28
28
|
|
29
29
|
##
|
30
|
-
# Find all objects within a radius
|
31
|
-
#
|
32
|
-
#
|
30
|
+
# Find all objects within a radius of the given location.
|
31
|
+
# Location may be either a string to geocode or an array of
|
32
|
+
# coordinates (<tt>[lat,lon]</tt>). Also takes an options hash
|
33
|
+
# (see Geocoder::Orm::ActiveRecord::ClassMethods.near_scope_options
|
34
|
+
# for details).
|
33
35
|
#
|
34
36
|
scope :near, lambda{ |location, *args|
|
35
37
|
latitude, longitude = location.is_a?(Array) ?
|
@@ -53,16 +55,22 @@ module Geocoder::Orm
|
|
53
55
|
# records within a radius (in miles) of the given point.
|
54
56
|
# Options hash may include:
|
55
57
|
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
# +
|
60
|
-
#
|
61
|
-
#
|
58
|
+
# * +:units+ - <tt>:mi</tt> (default) or <tt>:km</tt>; to be used
|
59
|
+
# for interpreting radius as well as the +distance+ attribute which
|
60
|
+
# is added to each found nearby object
|
61
|
+
# * +:bearing+ - <tt>:linear</tt> (default) or <tt>:spherical</tt>;
|
62
|
+
# the method to be used for calculating the bearing (direction)
|
63
|
+
# between the given point and each found nearby point;
|
64
|
+
# set to false for no bearing calculation
|
65
|
+
# * +:select+ - string with the SELECT SQL fragment (e.g. “id, name”)
|
66
|
+
# * +:order+ - column(s) for ORDER BY SQL clause
|
67
|
+
# * +:limit+ - number of records to return (for LIMIT SQL clause)
|
68
|
+
# * +:offset+ - number of records to skip (for OFFSET SQL clause)
|
69
|
+
# * +:exclude+ - an object to exclude (used by the +nearbys+ method)
|
62
70
|
#
|
63
71
|
def near_scope_options(latitude, longitude, radius = 20, options = {})
|
64
72
|
radius *= Geocoder::Calculations.km_in_mi if options[:units] == :km
|
65
|
-
if
|
73
|
+
if connection.adapter_name.match /sqlite/i
|
66
74
|
approx_near_scope_options(latitude, longitude, radius, options)
|
67
75
|
else
|
68
76
|
full_near_scope_options(latitude, longitude, radius, options)
|
@@ -74,23 +82,50 @@ module Geocoder::Orm
|
|
74
82
|
|
75
83
|
##
|
76
84
|
# Scope options hash for use with a database that supports POWER(),
|
77
|
-
# SQRT(), PI(), and trigonometric functions
|
85
|
+
# SQRT(), PI(), and trigonometric functions SIN(), COS(), ASIN(),
|
86
|
+
# ATAN2(), DEGREES(), and RADIANS().
|
78
87
|
#
|
79
|
-
#
|
88
|
+
# Distance calculations based on the excellent tutorial at:
|
80
89
|
# http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
|
81
90
|
#
|
91
|
+
# Bearing calculation based on:
|
92
|
+
# http://www.beginningspatial.com/calculating_bearing_one_point_another
|
93
|
+
#
|
82
94
|
def full_near_scope_options(latitude, longitude, radius, options)
|
83
95
|
lat_attr = geocoder_options[:latitude]
|
84
96
|
lon_attr = geocoder_options[:longitude]
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
"
|
89
|
-
|
90
|
-
|
97
|
+
options[:bearing] = :linear unless options.include?(:bearing)
|
98
|
+
bearing = case options[:bearing]
|
99
|
+
when :linear
|
100
|
+
"CAST(" +
|
101
|
+
"DEGREES(ATAN2( " +
|
102
|
+
"RADIANS(#{lon_attr} - #{longitude}), " +
|
103
|
+
"RADIANS(#{lat_attr} - #{latitude})" +
|
104
|
+
")) + 360 " +
|
105
|
+
"AS decimal) % 360"
|
106
|
+
when :spherical
|
107
|
+
"CAST(" +
|
108
|
+
"DEGREES(ATAN2( " +
|
109
|
+
"SIN(RADIANS(#{lon_attr} - #{longitude})) * " +
|
110
|
+
"COS(RADIANS(#{lat_attr})), (" +
|
111
|
+
"COS(RADIANS(#{latitude})) * SIN(RADIANS(#{lat_attr}))" +
|
112
|
+
") - (" +
|
113
|
+
"SIN(RADIANS(#{latitude})) * COS(RADIANS(#{lat_attr})) * " +
|
114
|
+
"COS(RADIANS(#{lon_attr} - #{longitude}))" +
|
115
|
+
")" +
|
116
|
+
")) + 360 " +
|
117
|
+
"AS decimal) % 360"
|
118
|
+
end
|
119
|
+
earth = Geocoder::Calculations.earth_radius(options[:units] || :mi)
|
120
|
+
distance = "#{earth} * 2 * ASIN(SQRT(" +
|
121
|
+
"POWER(SIN((#{latitude} - #{lat_attr}) * PI() / 180 / 2), 2) + " +
|
122
|
+
"COS(#{latitude} * PI() / 180) * COS(#{lat_attr} * PI() / 180) * " +
|
123
|
+
"POWER(SIN((#{longitude} - #{lon_attr}) * PI() / 180 / 2), 2) ))"
|
91
124
|
options[:order] ||= "#{distance} ASC"
|
92
125
|
default_near_scope_options(latitude, longitude, radius, options).merge(
|
93
|
-
:select => "#{options[:select] || '*'},
|
126
|
+
:select => "#{options[:select] || '*'}, " +
|
127
|
+
"#{distance} AS distance" +
|
128
|
+
(bearing ? ", #{bearing} AS bearing" : ""),
|
94
129
|
:having => "#{distance} <= #{radius}"
|
95
130
|
)
|
96
131
|
end
|
@@ -101,9 +136,33 @@ module Geocoder::Orm
|
|
101
136
|
# rather than a circle, so results are very approximate (will include
|
102
137
|
# objects outside the given radius).
|
103
138
|
#
|
139
|
+
# Distance and bearing calculations are *extremely inaccurate*. They
|
140
|
+
# only exist for interface consistency--not intended for production!
|
141
|
+
#
|
104
142
|
def approx_near_scope_options(latitude, longitude, radius, options)
|
143
|
+
lat_attr = geocoder_options[:latitude]
|
144
|
+
lon_attr = geocoder_options[:longitude]
|
145
|
+
options[:bearing] = :linear unless options.include?(:bearing)
|
146
|
+
if options[:bearing]
|
147
|
+
bearing = "CASE " +
|
148
|
+
"WHEN (#{lat_attr} >= #{latitude} AND #{lon_attr} >= #{longitude}) THEN 45.0 " +
|
149
|
+
"WHEN (#{lat_attr} < #{latitude} AND #{lon_attr} >= #{longitude}) THEN 135.0 " +
|
150
|
+
"WHEN (#{lat_attr} < #{latitude} AND #{lon_attr} < #{longitude}) THEN 225.0 " +
|
151
|
+
"WHEN (#{lat_attr} >= #{latitude} AND #{lon_attr} < #{longitude}) THEN 315.0 " +
|
152
|
+
"END"
|
153
|
+
else
|
154
|
+
bearing = false
|
155
|
+
end
|
156
|
+
|
157
|
+
dx = Geocoder::Calculations.longitude_degree_distance(30, options[:units] || :mi)
|
158
|
+
dy = Geocoder::Calculations.latitude_degree_distance(options[:units] || :mi)
|
159
|
+
|
160
|
+
distance = "(#{dy} * ABS(#{lat_attr} - #{latitude}) / 2) + " +
|
161
|
+
"(#{dx} * ABS(#{lon_attr} - #{longitude}) / 2)"
|
105
162
|
default_near_scope_options(latitude, longitude, radius, options).merge(
|
106
|
-
:select => options[:select] ||
|
163
|
+
:select => "#{options[:select] || '*'}, " +
|
164
|
+
"#{distance} AS distance" +
|
165
|
+
(bearing ? ", #{bearing} AS bearing" : "")
|
107
166
|
)
|
108
167
|
end
|
109
168
|
|
@@ -113,9 +172,10 @@ module Geocoder::Orm
|
|
113
172
|
def default_near_scope_options(latitude, longitude, radius, options)
|
114
173
|
lat_attr = geocoder_options[:latitude]
|
115
174
|
lon_attr = geocoder_options[:longitude]
|
175
|
+
b = Geocoder::Calculations.bounding_box(latitude, longitude, radius, options)
|
116
176
|
conditions = \
|
117
177
|
["#{lat_attr} BETWEEN ? AND ? AND #{lon_attr} BETWEEN ? AND ?"] +
|
118
|
-
|
178
|
+
[b[0], b[2], b[1], b[3]]
|
119
179
|
if obj = options[:exclude]
|
120
180
|
conditions[0] << " AND #{table_name}.id != ?"
|
121
181
|
conditions << obj.id
|
@@ -128,22 +188,6 @@ module Geocoder::Orm
|
|
128
188
|
:conditions => conditions
|
129
189
|
}
|
130
190
|
end
|
131
|
-
|
132
|
-
##
|
133
|
-
# Get the rough high/low lat/long bounds for a geographic point and
|
134
|
-
# radius. Returns an array: <tt>[lat_lo, lat_hi, lon_lo, lon_hi]</tt>.
|
135
|
-
# Used to constrain search to a (radius x radius) square.
|
136
|
-
#
|
137
|
-
def coordinate_bounds(latitude, longitude, radius)
|
138
|
-
radius = radius.to_f
|
139
|
-
factor = (Math::cos(latitude * Math::PI / 180.0) * 69.0).abs
|
140
|
-
[
|
141
|
-
latitude - (radius / 69.0),
|
142
|
-
latitude + (radius / 69.0),
|
143
|
-
longitude - (radius / factor),
|
144
|
-
longitude + (radius / factor)
|
145
|
-
]
|
146
|
-
end
|
147
191
|
end
|
148
192
|
|
149
193
|
##
|
@@ -151,7 +195,8 @@ module Geocoder::Orm
|
|
151
195
|
# (or other as specified in +geocoded_by+). Returns coordinates (array).
|
152
196
|
#
|
153
197
|
def geocode
|
154
|
-
do_lookup(false) do |o,
|
198
|
+
do_lookup(false) do |o,rs|
|
199
|
+
r = rs.first
|
155
200
|
unless r.latitude.nil? or r.longitude.nil?
|
156
201
|
o.send :write_attribute, self.class.geocoder_options[:latitude], r.latitude
|
157
202
|
o.send :write_attribute, self.class.geocoder_options[:longitude], r.longitude
|
@@ -167,7 +212,8 @@ module Geocoder::Orm
|
|
167
212
|
# in +reverse_geocoded_by+). Returns address (string).
|
168
213
|
#
|
169
214
|
def reverse_geocode
|
170
|
-
do_lookup(true) do |o,
|
215
|
+
do_lookup(true) do |o,rs|
|
216
|
+
r = rs.first
|
171
217
|
unless r.address.nil?
|
172
218
|
o.send :write_attribute, self.class.geocoder_options[:fetched_address], r.address
|
173
219
|
end
|
@@ -7,7 +7,8 @@ module Geocoder::Orm::ActiveRecord
|
|
7
7
|
def fetch_coordinates!
|
8
8
|
warn "DEPRECATION WARNING: The 'fetch_coordinates!' method is deprecated and will be removed in geocoder v1.0. " +
|
9
9
|
"Please use 'geocode' instead and then save your objects manually."
|
10
|
-
do_lookup(false) do |o,
|
10
|
+
do_lookup(false) do |o,rs|
|
11
|
+
r = rs.first
|
11
12
|
unless r.latitude.nil? or r.longitude.nil?
|
12
13
|
o.send :update_attribute, self.class.geocoder_options[:latitude], r.latitude
|
13
14
|
o.send :update_attribute, self.class.geocoder_options[:longitude], r.longitude
|
@@ -19,7 +20,8 @@ module Geocoder::Orm::ActiveRecord
|
|
19
20
|
def fetch_coordinates(*args)
|
20
21
|
warn "DEPRECATION WARNING: The 'fetch_coordinates' method will cease taking " +
|
21
22
|
"an argument in geocoder v1.0. Please save your objects manually." if args.size > 0
|
22
|
-
do_lookup(false) do |o,
|
23
|
+
do_lookup(false) do |o,rs|
|
24
|
+
r = rs.first
|
23
25
|
unless r.latitude.nil? or r.longitude.nil?
|
24
26
|
method = ((args.size > 0 && args.first) ? "update" : "write" ) + "_attribute"
|
25
27
|
o.send method, self.class.geocoder_options[:latitude], r.latitude
|
@@ -35,7 +37,8 @@ module Geocoder::Orm::ActiveRecord
|
|
35
37
|
def fetch_address!
|
36
38
|
warn "DEPRECATION WARNING: The 'fetch_address!' method is deprecated and will be removed in geocoder v1.0. " +
|
37
39
|
"Please use 'reverse_geocode' instead and then save your objects manually."
|
38
|
-
do_lookup(true) do |o,
|
40
|
+
do_lookup(true) do |o,rs|
|
41
|
+
r = rs.first
|
39
42
|
unless r.address.nil?
|
40
43
|
o.send :update_attribute, self.class.geocoder_options[:fetched_address], r.address
|
41
44
|
end
|
@@ -46,7 +49,8 @@ module Geocoder::Orm::ActiveRecord
|
|
46
49
|
def fetch_address(*args)
|
47
50
|
warn "DEPRECATION WARNING: The 'fetch_address' method will cease taking " +
|
48
51
|
"an argument in geocoder v1.0. Please save your objects manually." if args.size > 0
|
49
|
-
do_lookup(true) do |o,
|
52
|
+
do_lookup(true) do |o,rs|
|
53
|
+
r = rs.first
|
50
54
|
unless r.latitude.nil? or r.longitude.nil?
|
51
55
|
method = ((args.size > 0 && args.first) ? "update" : "write" ) + "_attribute"
|
52
56
|
o.send method, self.class.geocoder_options[:fetched_address], r.address
|
data/lib/geocoder/orms/base.rb
CHANGED
@@ -6,7 +6,14 @@ module Geocoder
|
|
6
6
|
# Is this object geocoded? (Does it have latitude and longitude?)
|
7
7
|
#
|
8
8
|
def geocoded?
|
9
|
-
|
9
|
+
to_coordinates.compact.size > 0
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# Coordinates [lat,lon] of the object.
|
14
|
+
#
|
15
|
+
def to_coordinates
|
16
|
+
[:latitude, :longitude].map{ |i| send self.class.geocoder_options[i] }
|
10
17
|
end
|
11
18
|
|
12
19
|
##
|
@@ -16,20 +23,24 @@ module Geocoder
|
|
16
23
|
#
|
17
24
|
def distance_to(lat, lon, units = :mi)
|
18
25
|
return nil unless geocoded?
|
19
|
-
mylat,mylon =
|
26
|
+
mylat,mylon = to_coordinates
|
20
27
|
Geocoder::Calculations.distance_between(mylat, mylon, lat, lon, :units => units)
|
21
28
|
end
|
22
29
|
|
23
30
|
alias_method :distance_from, :distance_to
|
24
31
|
|
25
32
|
##
|
26
|
-
# Get nearby geocoded objects.
|
27
|
-
#
|
33
|
+
# Get nearby geocoded objects.
|
34
|
+
# Takes the same options hash as the near class method (scope).
|
28
35
|
#
|
29
|
-
def nearbys(radius = 20,
|
36
|
+
def nearbys(radius = 20, options = {})
|
30
37
|
return [] unless geocoded?
|
31
|
-
options
|
32
|
-
|
38
|
+
if options.is_a?(Symbol)
|
39
|
+
options = {:units => options}
|
40
|
+
warn "DEPRECATION WARNING: The units argument to the nearbys method has been replaced with an options hash (same options hash as the near scope). You should instead call: obj.nearbys(#{radius}, :units => #{options[:units]}). The old syntax will not be supported in Geocoder v1.0."
|
41
|
+
end
|
42
|
+
options.merge!(:exclude => self)
|
43
|
+
self.class.near(to_coordinates, radius, options)
|
33
44
|
end
|
34
45
|
|
35
46
|
##
|
@@ -53,10 +64,10 @@ module Geocoder
|
|
53
64
|
|
54
65
|
##
|
55
66
|
# Look up geographic data based on object attributes (configured in
|
56
|
-
# geocoded_by or reverse_geocoded_by) and handle the
|
67
|
+
# geocoded_by or reverse_geocoded_by) and handle the results with the
|
57
68
|
# block (given to geocoded_by or reverse_geocoded_by). The block is
|
58
|
-
# given two-arguments: the object being geocoded and
|
59
|
-
# Geocoder::Result
|
69
|
+
# given two-arguments: the object being geocoded and an array of
|
70
|
+
# Geocoder::Result objects).
|
60
71
|
#
|
61
72
|
def do_lookup(reverse = false)
|
62
73
|
options = self.class.geocoder_options
|
@@ -69,28 +80,20 @@ module Geocoder
|
|
69
80
|
end
|
70
81
|
args.map!{ |a| send(options[a]) }
|
71
82
|
|
72
|
-
if
|
83
|
+
if (results = Geocoder.search(*args)).size > 0
|
73
84
|
|
74
85
|
# execute custom block, if specified in configuration
|
75
86
|
block_key = reverse ? :reverse_block : :geocode_block
|
76
87
|
if custom_block = options[block_key]
|
77
|
-
custom_block.call(self,
|
88
|
+
custom_block.call(self, results)
|
78
89
|
|
79
90
|
# else execute block passed directly to this method,
|
80
91
|
# which generally performs the "auto-assigns"
|
81
92
|
elsif block_given?
|
82
|
-
yield(self,
|
93
|
+
yield(self, results)
|
83
94
|
end
|
84
95
|
end
|
85
96
|
end
|
86
|
-
|
87
|
-
##
|
88
|
-
# Read the coordinates [lat,lon] of the object.
|
89
|
-
# Looks at user config to determine attributes.
|
90
|
-
#
|
91
|
-
def read_coordinates
|
92
|
-
[:latitude, :longitude].map{ |i| send self.class.geocoder_options[i] }
|
93
|
-
end
|
94
97
|
end
|
95
98
|
end
|
96
99
|
end
|
data/lib/geocoder/request.rb
CHANGED
@@ -39,20 +39,6 @@ module Geocoder
|
|
39
39
|
def country_code
|
40
40
|
fail
|
41
41
|
end
|
42
|
-
|
43
|
-
def [](i)
|
44
|
-
if i == 0
|
45
|
-
warn "DEPRECATION WARNING: You called '[0]' on a Geocoder::Result object. Geocoder.search(...) now returns a single result instead of an array so this is no longer necessary. This warning will be removed and an error will result in geocoder 1.0."
|
46
|
-
elsif i.is_a?(Fixnum)
|
47
|
-
warn "DEPRECATION WARNING: You tried to access a Geocoder result but Geocoder.search(...) now returns a single result instead of an array. This warning will be removed and an error will result in geocoder 1.0."
|
48
|
-
end
|
49
|
-
self
|
50
|
-
end
|
51
|
-
|
52
|
-
def first
|
53
|
-
warn "DEPRECATION WARNING: You called '.first' on a Geocoder::Result object. Geocoder.search(...) now returns a single result instead of an array so this is no longer necessary. This warning will be removed and an error will result in geocoder 1.0."
|
54
|
-
self
|
55
|
-
end
|
56
42
|
end
|
57
43
|
end
|
58
44
|
end
|
@@ -0,0 +1,58 @@
|
|
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}"
|
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 :province, :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
|
+
prov = @data['prov']
|
38
|
+
return nil if prov.nil? || prov == ""
|
39
|
+
canadian_province_abbreviations.include?(@data['prov']) ? "CA" : "US"
|
40
|
+
end
|
41
|
+
|
42
|
+
def canadian_province_abbreviations
|
43
|
+
%w[ON QC NS NB MB BC PE SK AB NL]
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.response_attributes
|
47
|
+
%w[latt longt inlatt inlongt betweenRoad1 betweenRoad2 distance
|
48
|
+
stnumber staddress city prov postal
|
49
|
+
NearRoad NearRoadDistance intersection major_intersection]
|
50
|
+
end
|
51
|
+
|
52
|
+
response_attributes.each do |a|
|
53
|
+
define_method a do
|
54
|
+
@data[a]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|