geocoder-sgonyea 1.1.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/.gitignore +5 -0
  2. data/.travis.yml +23 -0
  3. data/CHANGELOG.md +298 -0
  4. data/LICENSE +20 -0
  5. data/README.md +656 -0
  6. data/Rakefile +25 -0
  7. data/bin/geocode +5 -0
  8. data/examples/autoexpire_cache.rb +28 -0
  9. data/gemfiles/Gemfile.mongoid-2.4.x +15 -0
  10. data/lib/generators/geocoder/config/config_generator.rb +14 -0
  11. data/lib/generators/geocoder/config/templates/initializer.rb +21 -0
  12. data/lib/geocoder.rb +55 -0
  13. data/lib/geocoder/cache.rb +85 -0
  14. data/lib/geocoder/calculations.rb +319 -0
  15. data/lib/geocoder/cli.rb +114 -0
  16. data/lib/geocoder/configuration.rb +130 -0
  17. data/lib/geocoder/configuration_hash.rb +11 -0
  18. data/lib/geocoder/exceptions.rb +21 -0
  19. data/lib/geocoder/lookup.rb +82 -0
  20. data/lib/geocoder/lookups/base.rb +250 -0
  21. data/lib/geocoder/lookups/bing.rb +47 -0
  22. data/lib/geocoder/lookups/freegeoip.rb +47 -0
  23. data/lib/geocoder/lookups/geocoder_ca.rb +54 -0
  24. data/lib/geocoder/lookups/google.rb +62 -0
  25. data/lib/geocoder/lookups/google_premier.rb +47 -0
  26. data/lib/geocoder/lookups/mapquest.rb +43 -0
  27. data/lib/geocoder/lookups/maxmind.rb +88 -0
  28. data/lib/geocoder/lookups/nominatim.rb +45 -0
  29. data/lib/geocoder/lookups/ovi.rb +52 -0
  30. data/lib/geocoder/lookups/test.rb +38 -0
  31. data/lib/geocoder/lookups/yahoo.rb +84 -0
  32. data/lib/geocoder/lookups/yandex.rb +54 -0
  33. data/lib/geocoder/models/active_record.rb +46 -0
  34. data/lib/geocoder/models/base.rb +42 -0
  35. data/lib/geocoder/models/mongo_base.rb +60 -0
  36. data/lib/geocoder/models/mongo_mapper.rb +26 -0
  37. data/lib/geocoder/models/mongoid.rb +32 -0
  38. data/lib/geocoder/query.rb +103 -0
  39. data/lib/geocoder/railtie.rb +26 -0
  40. data/lib/geocoder/request.rb +23 -0
  41. data/lib/geocoder/results/base.rb +67 -0
  42. data/lib/geocoder/results/bing.rb +48 -0
  43. data/lib/geocoder/results/freegeoip.rb +45 -0
  44. data/lib/geocoder/results/geocoder_ca.rb +60 -0
  45. data/lib/geocoder/results/google.rb +106 -0
  46. data/lib/geocoder/results/google_premier.rb +6 -0
  47. data/lib/geocoder/results/mapquest.rb +51 -0
  48. data/lib/geocoder/results/maxmind.rb +136 -0
  49. data/lib/geocoder/results/nominatim.rb +94 -0
  50. data/lib/geocoder/results/ovi.rb +62 -0
  51. data/lib/geocoder/results/test.rb +16 -0
  52. data/lib/geocoder/results/yahoo.rb +55 -0
  53. data/lib/geocoder/results/yandex.rb +80 -0
  54. data/lib/geocoder/sql.rb +106 -0
  55. data/lib/geocoder/stores/active_record.rb +259 -0
  56. data/lib/geocoder/stores/base.rb +120 -0
  57. data/lib/geocoder/stores/mongo_base.rb +85 -0
  58. data/lib/geocoder/stores/mongo_mapper.rb +13 -0
  59. data/lib/geocoder/stores/mongoid.rb +13 -0
  60. data/lib/geocoder/version.rb +3 -0
  61. data/lib/hash_recursive_merge.rb +74 -0
  62. data/lib/oauth_util.rb +112 -0
  63. data/lib/tasks/geocoder.rake +25 -0
  64. data/test/active_record_test.rb +15 -0
  65. data/test/cache_test.rb +19 -0
  66. data/test/calculations_test.rb +195 -0
  67. data/test/configuration_test.rb +78 -0
  68. data/test/custom_block_test.rb +32 -0
  69. data/test/error_handling_test.rb +43 -0
  70. data/test/fixtures/bing_invalid_key +1 -0
  71. data/test/fixtures/bing_madison_square_garden +40 -0
  72. data/test/fixtures/bing_no_results +16 -0
  73. data/test/fixtures/bing_reverse +42 -0
  74. data/test/fixtures/freegeoip_74_200_247_59 +12 -0
  75. data/test/fixtures/freegeoip_no_results +1 -0
  76. data/test/fixtures/geocoder_ca_madison_square_garden +1 -0
  77. data/test/fixtures/geocoder_ca_no_results +1 -0
  78. data/test/fixtures/geocoder_ca_reverse +34 -0
  79. data/test/fixtures/google_garbage +456 -0
  80. data/test/fixtures/google_madison_square_garden +57 -0
  81. data/test/fixtures/google_no_city_data +44 -0
  82. data/test/fixtures/google_no_locality +51 -0
  83. data/test/fixtures/google_no_results +4 -0
  84. data/test/fixtures/mapquest_madison_square_garden +52 -0
  85. data/test/fixtures/mapquest_no_results +7 -0
  86. data/test/fixtures/maxmind_24_24_24_21 +1 -0
  87. data/test/fixtures/maxmind_24_24_24_22 +1 -0
  88. data/test/fixtures/maxmind_24_24_24_23 +1 -0
  89. data/test/fixtures/maxmind_24_24_24_24 +1 -0
  90. data/test/fixtures/maxmind_74_200_247_59 +1 -0
  91. data/test/fixtures/maxmind_invalid_key +1 -0
  92. data/test/fixtures/maxmind_no_results +1 -0
  93. data/test/fixtures/nominatim_madison_square_garden +150 -0
  94. data/test/fixtures/nominatim_no_results +1 -0
  95. data/test/fixtures/ovi_madison_square_garden +72 -0
  96. data/test/fixtures/ovi_no_results +8 -0
  97. data/test/fixtures/yahoo_error +1 -0
  98. data/test/fixtures/yahoo_invalid_key +2 -0
  99. data/test/fixtures/yahoo_madison_square_garden +52 -0
  100. data/test/fixtures/yahoo_no_results +10 -0
  101. data/test/fixtures/yahoo_over_limit +2 -0
  102. data/test/fixtures/yandex_invalid_key +1 -0
  103. data/test/fixtures/yandex_kremlin +48 -0
  104. data/test/fixtures/yandex_no_city_and_town +112 -0
  105. data/test/fixtures/yandex_no_results +16 -0
  106. data/test/geocoder_test.rb +59 -0
  107. data/test/https_test.rb +16 -0
  108. data/test/integration/smoke_test.rb +26 -0
  109. data/test/lookup_test.rb +116 -0
  110. data/test/method_aliases_test.rb +25 -0
  111. data/test/mongoid_test.rb +39 -0
  112. data/test/mongoid_test_helper.rb +43 -0
  113. data/test/near_test.rb +43 -0
  114. data/test/oauth_util_test.rb +30 -0
  115. data/test/proxy_test.rb +23 -0
  116. data/test/query_test.rb +51 -0
  117. data/test/request_test.rb +29 -0
  118. data/test/result_test.rb +42 -0
  119. data/test/services_test.rb +277 -0
  120. data/test/test_helper.rb +279 -0
  121. data/test/test_mode_test.rb +50 -0
  122. metadata +170 -0
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/*_test.rb'
8
+ test.verbose = true
9
+ end
10
+
11
+ Rake::TestTask.new(:integration) do |test|
12
+ test.libs << 'lib' << 'test'
13
+ test.pattern = 'test/integration/*_test.rb'
14
+ test.verbose = true
15
+ end
16
+
17
+ task :default => [:test, :integration]
18
+
19
+ require 'rdoc/task'
20
+ Rake::RDocTask.new do |rdoc|
21
+ rdoc.rdoc_dir = 'rdoc'
22
+ rdoc.title = "Geocoder #{Geocoder::VERSION}"
23
+ rdoc.rdoc_files.include('*.rdoc')
24
+ rdoc.rdoc_files.include('lib/**/*.rb')
25
+ end
data/bin/geocode ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'geocoder/cli'
4
+
5
+ Geocoder::Cli.run ARGV
@@ -0,0 +1,28 @@
1
+ # This class implements a cache with simple delegation to the Redis store, but
2
+ # when it creates a key/value pair, it also sends an EXPIRE command with a TTL.
3
+ # It should be fairly simple to do the same thing with Memcached.
4
+ class AutoexpireCache
5
+ def initialize(store)
6
+ @store = store
7
+ @ttl = 86400
8
+ end
9
+
10
+ def [](url)
11
+ @store.[](url)
12
+ end
13
+
14
+ def []=(url, value)
15
+ @store.[]=(url, value)
16
+ @store.expire(url, @ttl)
17
+ end
18
+
19
+ def keys
20
+ @store.keys
21
+ end
22
+
23
+ def del(url)
24
+ @store.del(url)
25
+ end
26
+ end
27
+
28
+ Geocoder.configure(:cache => AutoexpireCache.new(Redis.new))
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec :path => '..'
4
+
5
+ group :development, :test do
6
+ gem 'rake'
7
+ gem 'mongoid', '2.4.11'
8
+ gem 'bson_ext', :platforms => :ruby
9
+
10
+ gem 'rails'
11
+
12
+ platforms :jruby do
13
+ gem 'jruby-openssl'
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails/generators'
2
+
3
+ module Geocoder
4
+ class ConfigGenerator < Rails::Generators::Base
5
+ source_root File.expand_path("../templates", __FILE__)
6
+
7
+ desc "This generator creates an initializer file at config/initializers, " +
8
+ "with the default configuration options for Geocoder."
9
+ def add_initializer
10
+ template "initializer.rb", "config/initializers/geocoder.rb"
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,21 @@
1
+ Geocoder.configure(
2
+ # geocoding options
3
+ # :timeout => 3, # geocoding service timeout (secs)
4
+ # :lookup => :google, # name of geocoding service (symbol)
5
+ # :language => :en, # ISO-639 language code
6
+ # :use_https => false, # use HTTPS for lookup requests? (if supported)
7
+ # :http_proxy => nil, # HTTP proxy server (user:pass@host:port)
8
+ # :https_proxy => nil, # HTTPS proxy server (user:pass@host:port)
9
+ # :api_key => nil, # API key for geocoding service
10
+ # :cache => nil, # cache object (must respond to #[], #[]=, and #keys)
11
+ # :cache_prefix => "geocoder:", # prefix (string) to use for all cache keys
12
+
13
+ # exceptions that should not be rescued by default
14
+ # (if you want to implement custom error handling);
15
+ # supports SocketError and TimeoutError
16
+ # :always_raise => [],
17
+
18
+ # calculation options
19
+ # :units => :mi, # :km for kilometers or :mi for miles
20
+ # :distances => :linear # :spherical or :linear
21
+ )
data/lib/geocoder.rb ADDED
@@ -0,0 +1,55 @@
1
+ require "geocoder/configuration"
2
+ require "geocoder/query"
3
+ require "geocoder/calculations"
4
+ require "geocoder/exceptions"
5
+ require "geocoder/cache"
6
+ require "geocoder/request"
7
+ require "geocoder/lookup"
8
+ require "geocoder/models/active_record" if defined?(::ActiveRecord)
9
+ require "geocoder/models/mongoid" if defined?(::Mongoid)
10
+ require "geocoder/models/mongo_mapper" if defined?(::MongoMapper)
11
+
12
+ module Geocoder
13
+ extend self
14
+
15
+ ##
16
+ # Search for information about an address or a set of coordinates.
17
+ #
18
+ def search(query, options = {})
19
+ query = Geocoder::Query.new(query, options) unless query.is_a?(Geocoder::Query)
20
+ query.blank? ? [] : query.execute
21
+ end
22
+
23
+ ##
24
+ # Look up the coordinates of the given street or IP address.
25
+ #
26
+ def coordinates(address, options = {})
27
+ if (results = search(address, options)).size > 0
28
+ results.first.coordinates
29
+ end
30
+ end
31
+
32
+ ##
33
+ # Look up the address of the given coordinates ([lat,lon])
34
+ # or IP address (string).
35
+ #
36
+ def address(query, options = {})
37
+ if (results = search(query, options)).size > 0
38
+ results.first.address
39
+ end
40
+ end
41
+
42
+ ##
43
+ # The working Cache object, or +nil+ if none configured.
44
+ #
45
+ def cache
46
+ warn "WARNING: Calling Geocoder.cache is DEPRECATED. The #cache method now belongs to the Geocoder::Lookup object."
47
+ Geocoder::Lookup.get(Geocoder.config.lookup).send(:configuration).cache
48
+ end
49
+ end
50
+
51
+ # load Railtie if Rails exists
52
+ if defined?(Rails)
53
+ require "geocoder/railtie"
54
+ Geocoder::Railtie.insert
55
+ end
@@ -0,0 +1,85 @@
1
+ module Geocoder
2
+ class Cache
3
+
4
+ def initialize(store, prefix)
5
+ @store = store
6
+ @prefix = prefix
7
+ end
8
+
9
+ ##
10
+ # Read from the Cache.
11
+ #
12
+ def [](url)
13
+ interpret case
14
+ when store.respond_to?(:[])
15
+ store[key_for(url)]
16
+ when store.respond_to?(:get)
17
+ store.get key_for(url)
18
+ end
19
+ end
20
+
21
+ ##
22
+ # Write to the Cache.
23
+ #
24
+ def []=(url, value)
25
+ case
26
+ when store.respond_to?(:[]=)
27
+ store[key_for(url)] = value
28
+ when store.respond_to?(:set)
29
+ store.set key_for(url), value
30
+ end
31
+ end
32
+
33
+ ##
34
+ # Delete cache entry for given URL,
35
+ # or pass <tt>:all</tt> to clear all URLs.
36
+ #
37
+ def expire(url)
38
+ if url == :all
39
+ urls.each{ |u| expire(u) }
40
+ else
41
+ expire_single_url(url)
42
+ end
43
+ end
44
+
45
+
46
+ private # ----------------------------------------------------------------
47
+
48
+ attr_reader :prefix, :store
49
+
50
+ ##
51
+ # Cache key for a given URL.
52
+ #
53
+ def key_for(url)
54
+ [prefix, url].join
55
+ end
56
+
57
+ ##
58
+ # Array of keys with the currently configured prefix
59
+ # that have non-nil values.
60
+ #
61
+ def keys
62
+ store.keys.select{ |k| k.match /^#{prefix}/ and interpret(store[k]) }
63
+ end
64
+
65
+ ##
66
+ # Array of cached URLs.
67
+ #
68
+ def urls
69
+ keys.map{ |k| k[/^#{prefix}(.*)/, 1] }
70
+ end
71
+
72
+ ##
73
+ # Clean up value before returning. Namely, convert empty string to nil.
74
+ # (Some key/value stores return empty string instead of nil.)
75
+ #
76
+ def interpret(value)
77
+ value == "" ? nil : value
78
+ end
79
+
80
+ def expire_single_url(url)
81
+ key = key_for(url)
82
+ store.respond_to?(:del) ? store.del(key) : store.delete(key)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,319 @@
1
+ module Geocoder
2
+ module Calculations
3
+ extend self
4
+
5
+ ##
6
+ # Compass point names, listed clockwise starting at North.
7
+ #
8
+ # If you want bearings named using more, fewer, or different points
9
+ # override Geocoder::Calculations.COMPASS_POINTS with your own array.
10
+ #
11
+ COMPASS_POINTS = %w[N NE E SE S SW W NW]
12
+
13
+ ##
14
+ # Radius of the Earth, in kilometers.
15
+ # Value taken from: http://en.wikipedia.org/wiki/Earth_radius
16
+ #
17
+ EARTH_RADIUS = 6371.0
18
+
19
+ ##
20
+ # Conversion factor: multiply by kilometers to get miles.
21
+ #
22
+ KM_IN_MI = 0.621371192
23
+
24
+ # Not a number constant
25
+ NAN = defined?(::Float::NAN) ? ::Float::NAN : 0 / 0.0
26
+
27
+ ##
28
+ # Returns true if all given arguments are valid latitude/longitude values.
29
+ #
30
+ def coordinates_present?(*args)
31
+ args.each do |a|
32
+ # note that Float::NAN != Float::NAN
33
+ # still, this could probably be improved:
34
+ return false if (!a.is_a?(Numeric) or a.to_s == "NaN")
35
+ end
36
+ true
37
+ end
38
+
39
+ ##
40
+ # Distance spanned by one degree of latitude in the given units.
41
+ #
42
+ def latitude_degree_distance(units = nil)
43
+ units ||= Geocoder.config.units
44
+ 2 * Math::PI * earth_radius(units) / 360
45
+ end
46
+
47
+ ##
48
+ # Distance spanned by one degree of longitude at the given latitude.
49
+ # This ranges from around 69 miles at the equator to zero at the poles.
50
+ #
51
+ def longitude_degree_distance(latitude, units = nil)
52
+ units ||= Geocoder.config.units
53
+ latitude_degree_distance(units) * Math.cos(to_radians(latitude))
54
+ end
55
+
56
+ ##
57
+ # Distance between two points on Earth (Haversine formula).
58
+ # Takes two points and an options hash.
59
+ # The points are given in the same way that points are given to all
60
+ # Geocoder methods that accept points as arguments. They can be:
61
+ #
62
+ # * an array of coordinates ([lat,lon])
63
+ # * a geocodable address (string)
64
+ # * a geocoded object (one which implements a +to_coordinates+ method
65
+ # which returns a [lat,lon] array
66
+ #
67
+ # The options hash supports:
68
+ #
69
+ # * <tt>:units</tt> - <tt>:mi</tt> or <tt>:km</tt>
70
+ # Use Geocoder.configure(:units => ...) to configure default units.
71
+ #
72
+ def distance_between(point1, point2, options = {})
73
+
74
+ # set default options
75
+ options[:units] ||= Geocoder.config.units
76
+
77
+ # convert to coordinate arrays
78
+ point1 = extract_coordinates(point1)
79
+ point2 = extract_coordinates(point2)
80
+
81
+ # convert degrees to radians
82
+ point1 = to_radians(point1)
83
+ point2 = to_radians(point2)
84
+
85
+ # compute deltas
86
+ dlat = point2[0] - point1[0]
87
+ dlon = point2[1] - point1[1]
88
+
89
+ a = (Math.sin(dlat / 2))**2 + Math.cos(point1[0]) *
90
+ (Math.sin(dlon / 2))**2 * Math.cos(point2[0])
91
+ c = 2 * Math.atan2( Math.sqrt(a), Math.sqrt(1-a))
92
+ c * earth_radius(options[:units])
93
+ end
94
+
95
+ ##
96
+ # Bearing between two points on Earth.
97
+ # Returns a number of degrees from due north (clockwise).
98
+ #
99
+ # See Geocoder::Calculations.distance_between for
100
+ # ways of specifying the points. Also accepts an options hash:
101
+ #
102
+ # * <tt>:method</tt> - <tt>:linear</tt> or <tt>:spherical</tt>;
103
+ # the spherical method is "correct" in that it returns the shortest path
104
+ # (one along a great circle) but the linear method is less confusing
105
+ # (returns due east or west when given two points with the same latitude).
106
+ # Use Geocoder.configure(:distances => ...) to configure calculation method.
107
+ #
108
+ # Based on: http://www.movable-type.co.uk/scripts/latlong.html
109
+ #
110
+ def bearing_between(point1, point2, options = {})
111
+
112
+ # set default options
113
+ options[:method] ||= Geocoder.config.distances
114
+ options[:method] = :linear unless options[:method] == :spherical
115
+
116
+ # convert to coordinate arrays
117
+ point1 = extract_coordinates(point1)
118
+ point2 = extract_coordinates(point2)
119
+
120
+ # convert degrees to radians
121
+ point1 = to_radians(point1)
122
+ point2 = to_radians(point2)
123
+
124
+ # compute deltas
125
+ dlat = point2[0] - point1[0]
126
+ dlon = point2[1] - point1[1]
127
+
128
+ case options[:method]
129
+ when :linear
130
+ y = dlon
131
+ x = dlat
132
+
133
+ when :spherical
134
+ y = Math.sin(dlon) * Math.cos(point2[0])
135
+ x = Math.cos(point1[0]) * Math.sin(point2[0]) -
136
+ Math.sin(point1[0]) * Math.cos(point2[0]) * Math.cos(dlon)
137
+ end
138
+
139
+ bearing = Math.atan2(x,y)
140
+ # Answer is in radians counterclockwise from due east.
141
+ # Convert to degrees clockwise from due north:
142
+ (90 - to_degrees(bearing) + 360) % 360
143
+ end
144
+
145
+ ##
146
+ # Translate a bearing (float) into a compass direction (string, eg "North").
147
+ #
148
+ def compass_point(bearing, points = COMPASS_POINTS)
149
+ seg_size = 360 / points.size
150
+ points[((bearing + (seg_size / 2)) % 360) / seg_size]
151
+ end
152
+
153
+ ##
154
+ # Compute the geographic center (aka geographic midpoint, center of
155
+ # gravity) for an array of geocoded objects and/or [lat,lon] arrays
156
+ # (can be mixed). Any objects missing coordinates are ignored. Follows
157
+ # the procedure documented at http://www.geomidpoint.com/calculation.html.
158
+ #
159
+ def geographic_center(points)
160
+
161
+ # convert objects to [lat,lon] arrays and convert degrees to radians
162
+ coords = points.map{ |p| to_radians(extract_coordinates(p)) }
163
+
164
+ # convert to Cartesian coordinates
165
+ x = []; y = []; z = []
166
+ coords.each do |p|
167
+ x << Math.cos(p[0]) * Math.cos(p[1])
168
+ y << Math.cos(p[0]) * Math.sin(p[1])
169
+ z << Math.sin(p[0])
170
+ end
171
+
172
+ # compute average coordinate values
173
+ xa, ya, za = [x,y,z].map do |c|
174
+ c.inject(0){ |tot,i| tot += i } / c.size.to_f
175
+ end
176
+
177
+ # convert back to latitude/longitude
178
+ lon = Math.atan2(ya, xa)
179
+ hyp = Math.sqrt(xa**2 + ya**2)
180
+ lat = Math.atan2(za, hyp)
181
+
182
+ # return answer in degrees
183
+ to_degrees [lat, lon]
184
+ end
185
+
186
+ ##
187
+ # Returns coordinates of the southwest and northeast corners of a box
188
+ # with the given point at its center. The radius is the shortest distance
189
+ # from the center point to any side of the box (the length of each side
190
+ # is twice the radius).
191
+ #
192
+ # This is useful for finding corner points of a map viewport, or for
193
+ # roughly limiting the possible solutions in a geo-spatial search
194
+ # (ActiveRecord queries use it thusly).
195
+ #
196
+ # See Geocoder::Calculations.distance_between for
197
+ # ways of specifying the point. Also accepts an options hash:
198
+ #
199
+ # * <tt>:units</tt> - <tt>:mi</tt> or <tt>:km</tt>.
200
+ # Use Geocoder.configure(:units => ...) to configure default units.
201
+ #
202
+ def bounding_box(point, radius, options = {})
203
+ lat,lon = extract_coordinates(point)
204
+ radius = radius.to_f
205
+ units = options[:units] || Geocoder.config.units
206
+ [
207
+ lat - (radius / latitude_degree_distance(units)),
208
+ lon - (radius / longitude_degree_distance(lat, units)),
209
+ lat + (radius / latitude_degree_distance(units)),
210
+ lon + (radius / longitude_degree_distance(lat, units))
211
+ ]
212
+ end
213
+
214
+ ##
215
+ # Convert degrees to radians.
216
+ # If an array (or multiple arguments) is passed,
217
+ # converts each value and returns array.
218
+ #
219
+ def to_radians(*args)
220
+ args = args.first if args.first.is_a?(Array)
221
+ if args.size == 1
222
+ args.first * (Math::PI / 180)
223
+ else
224
+ args.map{ |i| to_radians(i) }
225
+ end
226
+ end
227
+
228
+ ##
229
+ # Convert radians to degrees.
230
+ # If an array (or multiple arguments) is passed,
231
+ # converts each value and returns array.
232
+ #
233
+ def to_degrees(*args)
234
+ args = args.first if args.first.is_a?(Array)
235
+ if args.size == 1
236
+ (args.first * 180.0) / Math::PI
237
+ else
238
+ args.map{ |i| to_degrees(i) }
239
+ end
240
+ end
241
+
242
+ def distance_to_radians(distance, units = nil)
243
+ units ||= Geocoder.config.units
244
+ distance.to_f / earth_radius(units)
245
+ end
246
+
247
+ def radians_to_distance(radians, units = nil)
248
+ units ||= Geocoder.config.units
249
+ radians * earth_radius(units)
250
+ end
251
+
252
+ ##
253
+ # Convert miles to kilometers.
254
+ #
255
+ def to_kilometers(mi)
256
+ mi * mi_in_km
257
+ end
258
+
259
+ ##
260
+ # Convert kilometers to miles.
261
+ #
262
+ def to_miles(km)
263
+ km * km_in_mi
264
+ end
265
+
266
+ ##
267
+ # Radius of the Earth in the given units (:mi or :km).
268
+ # Use Geocoder.configure(:units => ...) to configure default units.
269
+ #
270
+ def earth_radius(units = nil)
271
+ units ||= Geocoder.config.units
272
+ units == :km ? EARTH_RADIUS : to_miles(EARTH_RADIUS)
273
+ end
274
+
275
+ ##
276
+ # Conversion factor: km to mi.
277
+ #
278
+ def km_in_mi
279
+ KM_IN_MI
280
+ end
281
+
282
+ ##
283
+ # Conversion factor: mi to km.
284
+ #
285
+ def mi_in_km
286
+ 1.0 / KM_IN_MI
287
+ end
288
+
289
+ ##
290
+ # Takes an object which is a [lat,lon] array, a geocodable string,
291
+ # or an object that implements +to_coordinates+ and returns a
292
+ # [lat,lon] array. Note that if a string is passed this may be a slow-
293
+ # running method and may return nil.
294
+ #
295
+ def extract_coordinates(point)
296
+ case point
297
+ when Array
298
+ if point.size == 2
299
+ lat, lon = point
300
+ if !lat.nil? && lat.respond_to?(:to_f) and
301
+ !lon.nil? && lon.respond_to?(:to_f)
302
+ then
303
+ return [ lat.to_f, lon.to_f ]
304
+ end
305
+ end
306
+ when String
307
+ point = Geocoder.coordinates(point) and return point
308
+ else
309
+ if point.respond_to?(:to_coordinates)
310
+ if Array === array = point.to_coordinates
311
+ return extract_coordinates(array)
312
+ end
313
+ end
314
+ end
315
+ [ NAN, NAN ]
316
+ end
317
+ end
318
+ end
319
+