geocoder 1.1.6 → 1.1.7
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.
- data/CHANGELOG.md +15 -1
- data/README.md +82 -2
- data/examples/autoexpire_cache_dalli.rb +62 -0
- data/examples/{autoexpire_cache.rb → autoexpire_cache_redis.rb} +4 -4
- data/lib/generators/geocoder/config/templates/initializer.rb +1 -1
- data/lib/geocoder.rb +1 -1
- data/lib/geocoder/cache.rb +4 -0
- data/lib/geocoder/calculations.rb +33 -1
- data/lib/geocoder/lookup.rb +2 -0
- data/lib/geocoder/lookups/base.rb +10 -10
- data/lib/geocoder/lookups/esri.rb +52 -0
- data/lib/geocoder/lookups/mapquest.rb +1 -1
- data/lib/geocoder/lookups/maxmind.rb +19 -3
- data/lib/geocoder/lookups/ovi.rb +52 -0
- data/lib/geocoder/lookups/test.rb +6 -0
- data/lib/geocoder/lookups/yahoo.rb +4 -2
- data/lib/geocoder/query.rb +4 -4
- data/lib/geocoder/request.rb +1 -1
- data/lib/geocoder/results/esri.rb +51 -0
- data/lib/geocoder/results/google.rb +28 -0
- data/lib/geocoder/results/mapquest.rb +1 -1
- data/lib/geocoder/results/maxmind.rb +4 -5
- data/lib/geocoder/results/ovi.rb +62 -0
- data/lib/geocoder/results/test.rb +2 -1
- data/lib/geocoder/results/yandex.rb +12 -2
- data/lib/geocoder/stores/active_record.rb +38 -16
- data/lib/geocoder/stores/mongo_base.rb +2 -1
- data/lib/geocoder/version.rb +1 -1
- data/test/calculations_test.rb +6 -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/maxmind_24_24_24_21 +1 -1
- data/test/fixtures/maxmind_24_24_24_22 +1 -1
- data/test/fixtures/maxmind_24_24_24_23 +1 -1
- data/test/fixtures/maxmind_24_24_24_24 +1 -1
- data/test/fixtures/ovi_madison_square_garden +72 -0
- data/test/fixtures/ovi_no_results +8 -0
- data/test/fixtures/yandex_no_city_and_town +112 -0
- data/test/lookup_test.rb +1 -0
- data/test/near_test.rb +32 -0
- data/test/query_test.rb +5 -0
- data/test/request_test.rb +29 -0
- data/test/result_test.rb +9 -0
- data/test/services_test.rb +59 -5
- data/test/test_helper.rb +1 -1
- data/test/test_mode_test.rb +32 -23
- metadata +15 -3
@@ -15,9 +15,12 @@ module Geocoder::Lookup
|
|
15
15
|
|
16
16
|
private # ---------------------------------------------------------------
|
17
17
|
|
18
|
-
|
18
|
+
##
|
19
|
+
# Return the name of the configured service, or raise an exception.
|
20
|
+
#
|
21
|
+
def configured_service!
|
19
22
|
if s = configuration[:service] and services.keys.include?(s)
|
20
|
-
|
23
|
+
return s
|
21
24
|
else
|
22
25
|
raise(
|
23
26
|
Geocoder::ConfigurationError,
|
@@ -28,6 +31,19 @@ module Geocoder::Lookup
|
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
34
|
+
def service_code
|
35
|
+
services[configured_service!]
|
36
|
+
end
|
37
|
+
|
38
|
+
def service_response_fields_count
|
39
|
+
Geocoder::Result::Maxmind.field_names[configured_service!].size
|
40
|
+
end
|
41
|
+
|
42
|
+
def data_contains_error?(parsed_data)
|
43
|
+
# if all fields given then there is an error
|
44
|
+
parsed_data.size == service_response_fields_count and !parsed_data.last.nil?
|
45
|
+
end
|
46
|
+
|
31
47
|
##
|
32
48
|
# Service names mapped to code used in URL.
|
33
49
|
#
|
@@ -45,7 +61,7 @@ module Geocoder::Lookup
|
|
45
61
|
return [reserved_result] if query.loopback_ip_address?
|
46
62
|
doc = fetch_data(query)
|
47
63
|
if doc and doc.is_a?(Array)
|
48
|
-
if doc
|
64
|
+
if !data_contains_error?(doc)
|
49
65
|
return [doc]
|
50
66
|
elsif doc.last == "INVALID_LICENSE_KEY"
|
51
67
|
raise_error(Geocoder::InvalidApiKey) || warn("Invalid MaxMind API key.")
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/ovi'
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class Ovi < Base
|
6
|
+
|
7
|
+
def name
|
8
|
+
"Ovi"
|
9
|
+
end
|
10
|
+
|
11
|
+
def required_api_key_parts
|
12
|
+
[]
|
13
|
+
end
|
14
|
+
|
15
|
+
def query_url(query)
|
16
|
+
"#{protocol}://lbs.ovi.com/search/6.2/geocode.json?" + url_query_string(query)
|
17
|
+
end
|
18
|
+
|
19
|
+
private # ---------------------------------------------------------------
|
20
|
+
|
21
|
+
def results(query)
|
22
|
+
return [] unless doc = fetch_data(query)
|
23
|
+
return [] unless doc['Response'] && doc['Response']['View']
|
24
|
+
if r=doc['Response']['View']
|
25
|
+
return [] if r.nil? || !r.is_a?(Array) || r.empty?
|
26
|
+
return r.first['Result']
|
27
|
+
end
|
28
|
+
[]
|
29
|
+
end
|
30
|
+
|
31
|
+
def query_url_params(query)
|
32
|
+
super.merge(
|
33
|
+
:searchtext=>query.sanitized_text,
|
34
|
+
:gen=>1,
|
35
|
+
:app_id=>api_key,
|
36
|
+
:app_code=>api_code
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def api_key
|
41
|
+
if a=configuration.api_key
|
42
|
+
return a.first if a.is_a?(Array)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def api_code
|
47
|
+
if a=configuration.api_key
|
48
|
+
return a.last if a.is_a?(Array)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -13,8 +13,13 @@ module Geocoder
|
|
13
13
|
stubs[query_text] = results
|
14
14
|
end
|
15
15
|
|
16
|
+
def self.set_default_stub(results)
|
17
|
+
@default_stub = results
|
18
|
+
end
|
19
|
+
|
16
20
|
def self.read_stub(query_text)
|
17
21
|
stubs.fetch(query_text) {
|
22
|
+
return @default_stub unless @default_stub.nil?
|
18
23
|
raise ArgumentError, "unknown stub request #{query_text}"
|
19
24
|
}
|
20
25
|
end
|
@@ -25,6 +30,7 @@ module Geocoder
|
|
25
30
|
|
26
31
|
def self.reset
|
27
32
|
@stubs = {}
|
33
|
+
@default_stub = nil
|
28
34
|
end
|
29
35
|
|
30
36
|
private
|
@@ -46,13 +46,15 @@ module Geocoder::Lookup
|
|
46
46
|
# Yahoo returns errors as XML even when JSON format is specified.
|
47
47
|
# Handle that here, without parsing the XML
|
48
48
|
# (which would add unnecessary complexity).
|
49
|
+
# Yahoo auth errors can also be cryptic, so add raw error desc
|
50
|
+
# to warning message.
|
49
51
|
#
|
50
52
|
def parse_raw_data(raw_data)
|
51
53
|
if raw_data.match /^<\?xml/
|
52
54
|
if raw_data.include?("Rate Limit Exceeded")
|
53
55
|
raise_error(Geocoder::OverQueryLimitError) || warn("Over API query limit.")
|
54
|
-
elsif raw_data
|
55
|
-
raise_error(Geocoder::InvalidApiKey) || warn("Invalid API key.")
|
56
|
+
elsif raw_data =~ /<yahoo:description>(Please provide valid credentials.*)<\/yahoo:description>/i
|
57
|
+
raise_error(Geocoder::InvalidApiKey) || warn("Invalid API key. Error response: #{$1}")
|
56
58
|
end
|
57
59
|
else
|
58
60
|
super(raw_data)
|
data/lib/geocoder/query.rb
CHANGED
@@ -48,7 +48,7 @@ module Geocoder
|
|
48
48
|
def blank?
|
49
49
|
!params_given? and (
|
50
50
|
(text.is_a?(Array) and text.compact.size < 2) or
|
51
|
-
text.to_s.match(
|
51
|
+
text.to_s.match(/\A\s*\z/)
|
52
52
|
)
|
53
53
|
end
|
54
54
|
|
@@ -59,14 +59,14 @@ module Geocoder
|
|
59
59
|
# dot-delimited numbers.
|
60
60
|
#
|
61
61
|
def ip_address?
|
62
|
-
!!text.to_s.match(
|
62
|
+
!!text.to_s.match(/\A(::ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\z/)
|
63
63
|
end
|
64
64
|
|
65
65
|
##
|
66
66
|
# Is the Query text a loopback IP address?
|
67
67
|
#
|
68
68
|
def loopback_ip_address?
|
69
|
-
!!(text == "0.0.0.0" or text.to_s.match(
|
69
|
+
!!(self.ip_address? and (text == "0.0.0.0" or text.to_s.match(/\A127/)))
|
70
70
|
end
|
71
71
|
|
72
72
|
##
|
@@ -75,7 +75,7 @@ module Geocoder
|
|
75
75
|
def coordinates?
|
76
76
|
text.is_a?(Array) or (
|
77
77
|
text.is_a?(String) and
|
78
|
-
!!text.to_s.match(
|
78
|
+
!!text.to_s.match(/\A-?[0-9\.]+, *-?[0-9\.]+\z/)
|
79
79
|
)
|
80
80
|
end
|
81
81
|
|
data/lib/geocoder/request.rb
CHANGED
@@ -8,7 +8,7 @@ module Geocoder
|
|
8
8
|
if env.has_key?('HTTP_X_REAL_IP')
|
9
9
|
@location = Geocoder.search(env['HTTP_X_REAL_IP']).first
|
10
10
|
elsif env.has_key?('HTTP_X_FORWARDED_FOR')
|
11
|
-
@location = Geocoder.search(env['HTTP_X_FORWARDED_FOR']).first
|
11
|
+
@location = Geocoder.search(env['HTTP_X_FORWARDED_FOR'].split(/\s*,\s*/)[0]).first
|
12
12
|
else
|
13
13
|
@location = Geocoder.search(ip).first
|
14
14
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'geocoder/results/base'
|
2
|
+
|
3
|
+
module Geocoder::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
|
@@ -11,6 +11,12 @@ module Geocoder::Result
|
|
11
11
|
formatted_address
|
12
12
|
end
|
13
13
|
|
14
|
+
def neighborhood
|
15
|
+
if neighborhood = address_components_of_type(:neighborhood).first
|
16
|
+
neighborhood['long_name']
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
14
20
|
def city
|
15
21
|
fields = [:locality, :sublocality,
|
16
22
|
:administrative_area_level_3,
|
@@ -35,6 +41,18 @@ module Geocoder::Result
|
|
35
41
|
end
|
36
42
|
end
|
37
43
|
|
44
|
+
def sub_state
|
45
|
+
if state = address_components_of_type(:administrative_area_level_2).first
|
46
|
+
state['long_name']
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def sub_state_code
|
51
|
+
if state = address_components_of_type(:administrative_area_level_2).first
|
52
|
+
state['short_name']
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
38
56
|
def country
|
39
57
|
if country = address_components_of_type(:country).first
|
40
58
|
country['long_name']
|
@@ -59,6 +77,16 @@ module Geocoder::Result
|
|
59
77
|
end
|
60
78
|
end
|
61
79
|
|
80
|
+
def street_number
|
81
|
+
if street_number = address_components_of_type(:street_number).first
|
82
|
+
street_number['long_name']
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def street_address
|
87
|
+
[street_number, route].compact.join(' ')
|
88
|
+
end
|
89
|
+
|
62
90
|
def types
|
63
91
|
@data['types']
|
64
92
|
end
|
@@ -67,13 +67,12 @@ module Geocoder::Result
|
|
67
67
|
|
68
68
|
##
|
69
69
|
# Name of the MaxMind service being used.
|
70
|
-
# Inferred from format of @data.
|
71
70
|
#
|
72
71
|
def service_name
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
72
|
+
# it would be much better to infer this from the length of the @data
|
73
|
+
# array, but MaxMind seems to send inconsistent and wide-ranging response
|
74
|
+
# lengths (see https://github.com/alexreisner/geocoder/issues/396)
|
75
|
+
Geocoder.config.maxmind[:service]
|
77
76
|
end
|
78
77
|
|
79
78
|
def field_names
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'geocoder/results/base'
|
2
|
+
|
3
|
+
module Geocoder::Result
|
4
|
+
class Ovi < Base
|
5
|
+
|
6
|
+
##
|
7
|
+
# A string in the given format.
|
8
|
+
#
|
9
|
+
def address(format = :full)
|
10
|
+
address_data['Label']
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# A two-element array: [lat, lon].
|
15
|
+
#
|
16
|
+
def coordinates
|
17
|
+
fail unless d = @data['Location']['DisplayPosition']
|
18
|
+
[d['Latitude'].to_f, d['Longitude'].to_f]
|
19
|
+
end
|
20
|
+
|
21
|
+
def state
|
22
|
+
address_data['County']
|
23
|
+
end
|
24
|
+
|
25
|
+
def province
|
26
|
+
address_data['County']
|
27
|
+
end
|
28
|
+
|
29
|
+
def postal_code
|
30
|
+
address_data['PostalCode']
|
31
|
+
end
|
32
|
+
|
33
|
+
def city
|
34
|
+
address_data['City']
|
35
|
+
end
|
36
|
+
|
37
|
+
def state_code
|
38
|
+
address_data['State']
|
39
|
+
end
|
40
|
+
|
41
|
+
def province_code
|
42
|
+
address_data['State']
|
43
|
+
end
|
44
|
+
|
45
|
+
def country
|
46
|
+
fail unless d = address_data['AdditionalData']
|
47
|
+
if v = d.find{|ad| ad['key']=='CountryName'}
|
48
|
+
return v['value']
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def country_code
|
53
|
+
address_data['Country']
|
54
|
+
end
|
55
|
+
|
56
|
+
private # ----------------------------------------------------------------
|
57
|
+
|
58
|
+
def address_data
|
59
|
+
@data['Location']['Address'] || fail
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -5,7 +5,8 @@ module Geocoder
|
|
5
5
|
class Test < Base
|
6
6
|
|
7
7
|
%w[latitude longitude city state state_code province
|
8
|
-
province_code postal_code country country_code address
|
8
|
+
province_code postal_code country country_code address
|
9
|
+
street_address street_number route].each do |attr|
|
9
10
|
define_method(attr) do
|
10
11
|
@data[attr.to_s] || @data[attr.to_sym]
|
11
12
|
end
|
@@ -16,8 +16,10 @@ module Geocoder::Result
|
|
16
16
|
address_details['Locality']['LocalityName']
|
17
17
|
elsif sub_state.empty?
|
18
18
|
address_details['AdministrativeArea']['Locality']['LocalityName']
|
19
|
-
|
20
|
-
|
19
|
+
elsif not sub_state_city.empty?
|
20
|
+
sub_state_city
|
21
|
+
else
|
22
|
+
""
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
@@ -66,5 +68,13 @@ module Geocoder::Result
|
|
66
68
|
def address_details
|
67
69
|
@data['GeoObject']['metaDataProperty']['GeocoderMetaData']['AddressDetails']['Country']
|
68
70
|
end
|
71
|
+
|
72
|
+
def sub_state_city
|
73
|
+
if sub_state && sub_state["Locality"]
|
74
|
+
sub_state['Locality']['LocalityName']
|
75
|
+
else
|
76
|
+
""
|
77
|
+
end
|
78
|
+
end
|
69
79
|
end
|
70
80
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require 'geocoder/sql'
|
2
3
|
require 'geocoder/stores/base'
|
3
4
|
|
@@ -17,13 +18,15 @@ module Geocoder::Store
|
|
17
18
|
|
18
19
|
# scope: geocoded objects
|
19
20
|
scope :geocoded, lambda {
|
20
|
-
|
21
|
-
"AND #{geocoder_options[:longitude]} IS NOT NULL"
|
21
|
+
where("#{geocoder_options[:latitude]} IS NOT NULL " +
|
22
|
+
"AND #{geocoder_options[:longitude]} IS NOT NULL")
|
23
|
+
}
|
22
24
|
|
23
25
|
# scope: not-geocoded objects
|
24
26
|
scope :not_geocoded, lambda {
|
25
|
-
|
26
|
-
"OR #{geocoder_options[:longitude]} IS NULL"
|
27
|
+
where("#{geocoder_options[:latitude]} IS NULL " +
|
28
|
+
"OR #{geocoder_options[:longitude]} IS NULL")
|
29
|
+
}
|
27
30
|
|
28
31
|
##
|
29
32
|
# Find all objects within a radius of the given location.
|
@@ -35,7 +38,9 @@ module Geocoder::Store
|
|
35
38
|
scope :near, lambda{ |location, *args|
|
36
39
|
latitude, longitude = Geocoder::Calculations.extract_coordinates(location)
|
37
40
|
if Geocoder::Calculations.coordinates_present?(latitude, longitude)
|
38
|
-
near_scope_options(latitude, longitude, *args)
|
41
|
+
options = near_scope_options(latitude, longitude, *args)
|
42
|
+
select(options[:select]).where(options[:conditions]).
|
43
|
+
order(options[:order])
|
39
44
|
else
|
40
45
|
# If no lat/lon given we don't want any results, but we still
|
41
46
|
# need distance and bearing columns so you can add, for example:
|
@@ -53,11 +58,11 @@ module Geocoder::Store
|
|
53
58
|
scope :within_bounding_box, lambda{ |bounds|
|
54
59
|
sw_lat, sw_lng, ne_lat, ne_lng = bounds.flatten if bounds
|
55
60
|
if sw_lat && sw_lng && ne_lat && ne_lng
|
56
|
-
|
61
|
+
where(Geocoder::Sql.within_bounding_box(
|
57
62
|
sw_lat, sw_lng, ne_lat, ne_lng,
|
58
63
|
full_column_name(geocoder_options[:latitude]),
|
59
64
|
full_column_name(geocoder_options[:longitude])
|
60
|
-
)
|
65
|
+
))
|
61
66
|
else
|
62
67
|
select(select_clause(nil, "NULL", "NULL")).where(false_condition)
|
63
68
|
end
|
@@ -93,13 +98,22 @@ module Geocoder::Store
|
|
93
98
|
# between the given point and each found nearby point;
|
94
99
|
# set to false for no bearing calculation. Use
|
95
100
|
# Geocoder.configure[:distances] to configure default calculation method.
|
96
|
-
# * +:select+
|
97
|
-
# * +:
|
98
|
-
#
|
99
|
-
# * +:
|
101
|
+
# * +:select+ - string with the SELECT SQL fragment (e.g. “id, name”)
|
102
|
+
# * +:select_distance+ - whether to include the distance alias in the
|
103
|
+
# SELECT SQL fragment (e.g. <formula> AS distance)
|
104
|
+
# * +:select_bearing+ - like +:select_distance+ but for bearing.
|
105
|
+
# * +:order+ - column(s) for ORDER BY SQL clause; default is distance;
|
106
|
+
# set to false or nil to omit the ORDER BY clause
|
107
|
+
# * +:exclude+ - an object to exclude (used by the +nearbys+ method)
|
100
108
|
#
|
101
109
|
def near_scope_options(latitude, longitude, radius = 20, options = {})
|
110
|
+
if options[:units]
|
111
|
+
options[:units] = options[:units].to_sym
|
112
|
+
end
|
102
113
|
options[:units] ||= (geocoder_options[:units] || Geocoder.config.units)
|
114
|
+
select_distance = options.fetch(:select_distance, true)
|
115
|
+
options[:order] = "" if !select_distance && !options.include?(:order)
|
116
|
+
select_bearing = options.fetch(:select_bearing, true)
|
103
117
|
bearing = bearing_sql(latitude, longitude, options)
|
104
118
|
distance = distance_sql(latitude, longitude, options)
|
105
119
|
|
@@ -116,7 +130,9 @@ module Geocoder::Store
|
|
116
130
|
conditions = [bounding_box_conditions + " AND #{distance} <= ?", radius]
|
117
131
|
end
|
118
132
|
{
|
119
|
-
:select => select_clause(options[:select],
|
133
|
+
:select => select_clause(options[:select],
|
134
|
+
select_distance ? distance : nil,
|
135
|
+
select_bearing ? bearing : nil),
|
120
136
|
:conditions => add_exclude_condition(conditions, options[:exclude]),
|
121
137
|
:order => options.include?(:order) ? options[:order] : "distance ASC"
|
122
138
|
}
|
@@ -166,10 +182,17 @@ module Geocoder::Store
|
|
166
182
|
elsif columns == :geo_only
|
167
183
|
clause = ""
|
168
184
|
else
|
169
|
-
clause = (columns || full_column_name("*"))
|
185
|
+
clause = (columns || full_column_name("*"))
|
170
186
|
end
|
171
|
-
|
172
|
-
|
187
|
+
if distance
|
188
|
+
clause += ", " unless clause.empty?
|
189
|
+
clause += "#{distance} AS distance"
|
190
|
+
end
|
191
|
+
if bearing
|
192
|
+
clause += ", " unless clause.empty?
|
193
|
+
clause += "#{bearing} AS bearing"
|
194
|
+
end
|
195
|
+
clause
|
173
196
|
end
|
174
197
|
|
175
198
|
##
|
@@ -241,4 +264,3 @@ module Geocoder::Store
|
|
241
264
|
alias_method :fetch_address, :reverse_geocode
|
242
265
|
end
|
243
266
|
end
|
244
|
-
|