geocoder 1.1.4 → 1.1.8

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 (110) hide show
  1. data/.travis.yml +4 -0
  2. data/{CHANGELOG.rdoc → CHANGELOG.md} +120 -39
  3. data/README.md +200 -54
  4. data/examples/autoexpire_cache_dalli.rb +62 -0
  5. data/examples/{autoexpire_cache.rb → autoexpire_cache_redis.rb} +4 -6
  6. data/lib/generators/geocoder/config/templates/initializer.rb +19 -23
  7. data/lib/geocoder/cache.rb +6 -1
  8. data/lib/geocoder/calculations.rb +45 -13
  9. data/lib/geocoder/cli.rb +10 -11
  10. data/lib/geocoder/configuration.rb +67 -43
  11. data/lib/geocoder/configuration_hash.rb +11 -0
  12. data/lib/geocoder/exceptions.rb +3 -0
  13. data/lib/geocoder/lookup.rb +3 -1
  14. data/lib/geocoder/lookups/base.rb +89 -27
  15. data/lib/geocoder/lookups/bing.rb +21 -11
  16. data/lib/geocoder/lookups/esri.rb +48 -0
  17. data/lib/geocoder/lookups/freegeoip.rb +8 -4
  18. data/lib/geocoder/lookups/geocoder_ca.rb +11 -7
  19. data/lib/geocoder/lookups/google.rb +18 -9
  20. data/lib/geocoder/lookups/google_premier.rb +16 -8
  21. data/lib/geocoder/lookups/mapquest.rb +33 -5
  22. data/lib/geocoder/lookups/maxmind.rb +88 -0
  23. data/lib/geocoder/lookups/nominatim.rb +13 -8
  24. data/lib/geocoder/lookups/ovi.rb +52 -0
  25. data/lib/geocoder/lookups/test.rb +10 -0
  26. data/lib/geocoder/lookups/yahoo.rb +51 -38
  27. data/lib/geocoder/lookups/yandex.rb +17 -9
  28. data/lib/geocoder/models/mongoid.rb +1 -1
  29. data/lib/geocoder/query.rb +20 -5
  30. data/lib/geocoder/request.rb +7 -1
  31. data/lib/geocoder/results/base.rb +8 -2
  32. data/lib/geocoder/results/esri.rb +51 -0
  33. data/lib/geocoder/results/google.rb +34 -0
  34. data/lib/geocoder/results/mapquest.rb +46 -2
  35. data/lib/geocoder/results/maxmind.rb +135 -0
  36. data/lib/geocoder/results/nominatim.rb +0 -10
  37. data/lib/geocoder/results/ovi.rb +62 -0
  38. data/lib/geocoder/results/test.rb +2 -1
  39. data/lib/geocoder/results/yahoo.rb +9 -2
  40. data/lib/geocoder/results/yandex.rb +12 -2
  41. data/lib/geocoder/sql.rb +6 -4
  42. data/lib/geocoder/stores/active_record.rb +57 -30
  43. data/lib/geocoder/stores/base.rb +3 -2
  44. data/lib/geocoder/stores/mongo_base.rb +2 -1
  45. data/lib/geocoder/version.rb +1 -1
  46. data/lib/geocoder.rb +2 -4
  47. data/lib/hash_recursive_merge.rb +74 -0
  48. data/lib/oauth_util.rb +112 -0
  49. data/test/cache_test.rb +19 -0
  50. data/test/calculations_test.rb +10 -4
  51. data/test/configuration_test.rb +26 -51
  52. data/test/error_handling_test.rb +8 -4
  53. data/test/fixtures/bing_invalid_key +1 -0
  54. data/test/fixtures/esri_madison_square_garden +59 -0
  55. data/test/fixtures/esri_no_results +8 -0
  56. data/test/fixtures/esri_reverse +21 -0
  57. data/test/fixtures/mapquest_madison_square_garden +52 -0
  58. data/test/fixtures/mapquest_no_results +7 -0
  59. data/test/fixtures/maxmind_24_24_24_21 +1 -0
  60. data/test/fixtures/maxmind_24_24_24_22 +1 -0
  61. data/test/fixtures/maxmind_24_24_24_23 +1 -0
  62. data/test/fixtures/maxmind_24_24_24_24 +1 -0
  63. data/test/fixtures/maxmind_74_200_247_59 +1 -0
  64. data/test/fixtures/maxmind_invalid_key +1 -0
  65. data/test/fixtures/maxmind_no_results +1 -0
  66. data/test/fixtures/ovi_madison_square_garden +72 -0
  67. data/test/fixtures/ovi_no_results +8 -0
  68. data/test/fixtures/yahoo_error +1 -0
  69. data/test/fixtures/yahoo_invalid_key +2 -0
  70. data/test/fixtures/yahoo_madison_square_garden +52 -0
  71. data/test/fixtures/yahoo_no_results +10 -0
  72. data/test/fixtures/yahoo_over_limit +2 -0
  73. data/test/fixtures/yandex_no_city_and_town +112 -0
  74. data/test/https_test.rb +3 -3
  75. data/test/integration/smoke_test.rb +2 -2
  76. data/test/lookup_test.rb +84 -11
  77. data/test/near_test.rb +43 -0
  78. data/test/oauth_util_test.rb +30 -0
  79. data/test/proxy_test.rb +2 -2
  80. data/test/query_test.rb +13 -0
  81. data/test/request_test.rb +29 -0
  82. data/test/result_test.rb +12 -2
  83. data/test/services_test.rb +208 -57
  84. data/test/test_helper.rb +66 -100
  85. data/test/test_mode_test.rb +35 -26
  86. metadata +58 -35
  87. data/test/fixtures/mapquest_madison_square_garden.json +0 -27
  88. data/test/fixtures/mapquest_no_results.json +0 -1
  89. data/test/fixtures/yahoo_madison_square_garden.json +0 -52
  90. data/test/fixtures/yahoo_no_results.json +0 -10
  91. data/test/fixtures/yahoo_v1_madison_square_garden.json +0 -46
  92. data/test/fixtures/yahoo_v1_no_results.json +0 -10
  93. /data/test/fixtures/{bing_madison_square_garden.json → bing_madison_square_garden} +0 -0
  94. /data/test/fixtures/{bing_no_results.json → bing_no_results} +0 -0
  95. /data/test/fixtures/{bing_reverse.json → bing_reverse} +0 -0
  96. /data/test/fixtures/{freegeoip_74_200_247_59.json → freegeoip_74_200_247_59} +0 -0
  97. /data/test/fixtures/{freegeoip_no_results.json → freegeoip_no_results} +0 -0
  98. /data/test/fixtures/{geocoder_ca_madison_square_garden.json → geocoder_ca_madison_square_garden} +0 -0
  99. /data/test/fixtures/{geocoder_ca_no_results.json → geocoder_ca_no_results} +0 -0
  100. /data/test/fixtures/{geocoder_ca_reverse.json → geocoder_ca_reverse} +0 -0
  101. /data/test/fixtures/{google_garbage.json → google_garbage} +0 -0
  102. /data/test/fixtures/{google_madison_square_garden.json → google_madison_square_garden} +0 -0
  103. /data/test/fixtures/{google_no_city_data.json → google_no_city_data} +0 -0
  104. /data/test/fixtures/{google_no_locality.json → google_no_locality} +0 -0
  105. /data/test/fixtures/{google_no_results.json → google_no_results} +0 -0
  106. /data/test/fixtures/{nominatim_madison_square_garden.json → nominatim_madison_square_garden} +0 -0
  107. /data/test/fixtures/{nominatim_no_results.json → nominatim_no_results} +0 -0
  108. /data/test/fixtures/{yandex_invalid_key.json → yandex_invalid_key} +0 -0
  109. /data/test/fixtures/{yandex_kremlin.json → yandex_kremlin} +0 -0
  110. /data/test/fixtures/{yandex_no_results.json → yandex_no_results} +0 -0
@@ -36,11 +36,20 @@ module Geocoder
36
36
  Lookup.get(name)
37
37
  end
38
38
 
39
+ def url
40
+ lookup.query_url(self)
41
+ end
42
+
39
43
  ##
40
- # Is the Query text blank? (ie, should we not bother searching?)
44
+ # Is the Query blank? (ie, should we not bother searching?)
45
+ # A query is considered blank if its text is nil or empty string AND
46
+ # no URL parameters are specified.
41
47
  #
42
48
  def blank?
43
- !!text.to_s.match(/^\s*$/)
49
+ !params_given? and (
50
+ (text.is_a?(Array) and text.compact.size < 2) or
51
+ text.to_s.match(/\A\s*\z/)
52
+ )
44
53
  end
45
54
 
46
55
  ##
@@ -50,14 +59,14 @@ module Geocoder
50
59
  # dot-delimited numbers.
51
60
  #
52
61
  def ip_address?
53
- !!text.to_s.match(/^(::ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)
62
+ !!text.to_s.match(/\A(::ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\z/)
54
63
  end
55
64
 
56
65
  ##
57
66
  # Is the Query text a loopback IP address?
58
67
  #
59
68
  def loopback_ip_address?
60
- !!(text == "0.0.0.0" or text.to_s.match(/^127/))
69
+ !!(self.ip_address? and (text == "0.0.0.0" or text.to_s.match(/\A127/)))
61
70
  end
62
71
 
63
72
  ##
@@ -66,7 +75,7 @@ module Geocoder
66
75
  def coordinates?
67
76
  text.is_a?(Array) or (
68
77
  text.is_a?(String) and
69
- !!text.to_s.match(/^-?[0-9\.]+, *-?[0-9\.]+$/)
78
+ !!text.to_s.match(/\A-?[0-9\.]+, *-?[0-9\.]+\z/)
70
79
  )
71
80
  end
72
81
 
@@ -84,5 +93,11 @@ module Geocoder
84
93
  def reverse_geocode?
85
94
  coordinates?
86
95
  end
96
+
97
+ private # ----------------------------------------------------------------
98
+
99
+ def params_given?
100
+ !!(options[:params].is_a?(Hash) and options[:params].keys.size > 0)
101
+ end
87
102
  end
88
103
  end
@@ -5,7 +5,13 @@ module Geocoder
5
5
 
6
6
  def location
7
7
  unless defined?(@location)
8
- @location = Geocoder.search(ip).first
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
9
15
  end
10
16
  @location
11
17
  end
@@ -1,10 +1,16 @@
1
1
  module Geocoder
2
2
  module Result
3
3
  class Base
4
- attr_accessor :data, :cache_hit
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
5
11
 
6
12
  ##
7
- # Takes a hash of result data from a parsed Google result document.
13
+ # Takes a hash of data from a parsed geocoding service response.
8
14
  #
9
15
  def initialize(data)
10
16
  @data = data
@@ -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']
@@ -53,6 +71,22 @@ module Geocoder::Result
53
71
  end
54
72
  end
55
73
 
74
+ def route
75
+ if route = address_components_of_type(:route).first
76
+ route['long_name']
77
+ end
78
+ end
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
+
56
90
  def types
57
91
  @data['types']
58
92
  end
@@ -1,7 +1,51 @@
1
1
  require 'geocoder/results/base'
2
- require 'geocoder/results/nominatim'
3
2
 
4
3
  module Geocoder::Result
5
- class Mapquest < Nominatim
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
6
50
  end
7
51
  end
@@ -0,0 +1,135 @@
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
+ #
71
+ def service_name
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]
76
+ end
77
+
78
+ def field_names
79
+ self.class.field_names[service_name]
80
+ end
81
+
82
+ def data_hash
83
+ @data_hash ||= Hash[*field_names.zip(@data).flatten]
84
+ end
85
+
86
+ def coordinates
87
+ [data_hash[:latitude].to_f, data_hash[:longitude].to_f]
88
+ end
89
+
90
+ def address(format = :full)
91
+ s = state_code.to_s == "" ? "" : ", #{state_code}"
92
+ "#{city}#{s} #{postal_code}, #{country_code}".sub(/^[ ,]*/, "")
93
+ end
94
+
95
+ def city
96
+ data_hash[:city_name]
97
+ end
98
+
99
+ def state # not given by MaxMind
100
+ data_hash[:region_name] || data_hash[:region_code]
101
+ end
102
+
103
+ def state_code
104
+ data_hash[:region_code]
105
+ end
106
+
107
+ def country #not given by MaxMind
108
+ data_hash[:country_name] || data_hash[:country_code]
109
+ end
110
+
111
+ def country_code
112
+ data_hash[:country_code]
113
+ end
114
+
115
+ def postal_code
116
+ data_hash[:postal_code]
117
+ end
118
+
119
+ def method_missing(method, *args, &block)
120
+ if field_names.include?(method)
121
+ data_hash[method]
122
+ else
123
+ super
124
+ end
125
+ end
126
+
127
+ def respond_to?(method)
128
+ if field_names.include?(method)
129
+ true
130
+ else
131
+ super
132
+ end
133
+ end
134
+ end
135
+ end
@@ -83,16 +83,6 @@ module Geocoder::Result
83
83
  polygonpoints display_name class type stadium]
84
84
  end
85
85
 
86
- def class
87
- warn "DEPRECATION WARNING: The 'class' method of Geocoder::Result::Nominatim objects is deprecated and will be removed in Geocoder version 1.2.0. Please use 'place_class' instead."
88
- @data['class']
89
- end
90
-
91
- def type
92
- warn "DEPRECATION WARNING: The 'type' method of Geocoder::Result::Nominatim objects is deprecated and will be removed in Geocoder version 1.2.0. Please use 'place_type' instead."
93
- @data['type']
94
- end
95
-
96
86
  response_attributes.each do |a|
97
87
  unless method_defined?(a)
98
88
  define_method a do
@@ -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].each do |attr|
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
@@ -31,17 +31,24 @@ module Geocoder::Result
31
31
  @data['postal']
32
32
  end
33
33
 
34
+ def address_hash
35
+ @data['hash']
36
+ end
37
+
34
38
  def self.response_attributes
35
39
  %w[quality offsetlat offsetlon radius boundingbox name
36
40
  line1 line2 line3 line4 cross house street xstreet unittype unit
41
+ city state statecode country countrycode postal
37
42
  neighborhood county countycode
38
43
  level0 level1 level2 level3 level4 level0code level1code level2code
39
44
  timezone areacode uzip hash woeid woetype]
40
45
  end
41
46
 
42
47
  response_attributes.each do |a|
43
- define_method a do
44
- @data[a]
48
+ unless method_defined?(a)
49
+ define_method a do
50
+ @data[a]
51
+ end
45
52
  end
46
53
  end
47
54
  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
- else
20
- address_details['AdministrativeArea']['SubAdministrativeArea']['Locality']['LocalityName']
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
data/lib/geocoder/sql.rb CHANGED
@@ -11,7 +11,8 @@ module Geocoder
11
11
  # http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
12
12
  #
13
13
  def full_distance(latitude, longitude, lat_attr, lon_attr, options = {})
14
- earth = Geocoder::Calculations.earth_radius(options[:units] || :mi)
14
+ units = options[:units] || Geocoder.config.units
15
+ earth = Geocoder::Calculations.earth_radius(units)
15
16
 
16
17
  "#{earth} * 2 * ASIN(SQRT(" +
17
18
  "POWER(SIN((#{latitude.to_f} - #{lat_attr}) * PI() / 180 / 2), 2) + " +
@@ -31,8 +32,9 @@ module Geocoder
31
32
  # are not intended for use in production!
32
33
  #
33
34
  def approx_distance(latitude, longitude, lat_attr, lon_attr, options = {})
34
- dx = Geocoder::Calculations.longitude_degree_distance(30, options[:units] || :mi)
35
- dy = Geocoder::Calculations.latitude_degree_distance(options[:units] || :mi)
35
+ units = options[:units] || Geocoder.config.units
36
+ dx = Geocoder::Calculations.longitude_degree_distance(30, units)
37
+ dy = Geocoder::Calculations.latitude_degree_distance(units)
36
38
 
37
39
  # sin of 45 degrees = average x or y component of vector
38
40
  factor = Math.sin(Math::PI / 4)
@@ -61,7 +63,7 @@ module Geocoder
61
63
  # http://www.beginningspatial.com/calculating_bearing_one_point_another
62
64
  #
63
65
  def full_bearing(latitude, longitude, lat_attr, lon_attr, options = {})
64
- case options[:bearing]
66
+ case options[:bearing] || Geocoder.config.distances
65
67
  when :linear
66
68
  "CAST(" +
67
69
  "DEGREES(ATAN2( " +