geocoder 0.9.12 → 1.0.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/CHANGELOG.rdoc CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  Per-release changes to Geocoder.
4
4
 
5
+ == 1.0.0 (2011 May 9)
6
+
7
+ * Add command line interface.
8
+ * Add support for local proxy (thanks github.com/Olivier).
9
+ * Add support for Yandex.ru geocoding service.
10
+ * Add support for Bing geocoding service (thanks github.com/astevens).
11
+ * Fix single table inheritance bug (reported by github.com/enrico).
12
+ * Fix bug when Google result supplies no city (thanks github.com/jkeen).
13
+
14
+ == 0.9.13 (2011 Apr 11)
15
+
16
+ * Fix "can't find special index: 2d" error when using Mongoid with Ruby 1.8.
17
+
5
18
  == 0.9.12 (2011 Apr 6)
6
19
 
7
20
  * Add support for Mongoid.
@@ -19,9 +32,9 @@ Per-release changes to Geocoder.
19
32
  * Add support for Geocoder.ca geocoding service.
20
33
  * Add +bearing+ attribute to objects returned by geo-aware queries (thanks github.com/matellis).
21
34
  * Add config setting: language.
22
- * Add config settings: use_https, google_api_key (thanks github.com/svesely).
23
- * DEPRECATION: Geocoder.search now returns an array instead of a single result.
24
- * DEPRECATION: obj.nearbys second argument is now an options hash (instead of units). Please change <tt>obj.nearbys(20, :km)</tt> to: <tt>obj.nearbys(20, :units => :km)</tt>.
35
+ * Add config settings: +use_https+, +google_api_key+ (thanks github.com/svesely).
36
+ * DEPRECATION: <tt>Geocoder.search</tt> now returns an array instead of a single result.
37
+ * DEPRECATION: <tt>obj.nearbys</tt> second argument is now an options hash (instead of units). Please change <tt>obj.nearbys(20, :km)</tt> to: <tt>obj.nearbys(20, :units => :km)</tt>.
25
38
 
26
39
  == 0.9.10 (2011 Mar 9)
27
40
 
@@ -38,15 +51,15 @@ Per-release changes to Geocoder.
38
51
  * Gem now works outside of Rails.
39
52
  * DEPRECATION: +fetch_coordinates+ no longer takes an argument.
40
53
  * DEPRECATION: +fetch_address+ no longer takes an argument.
41
- * DEPRECATION: Geocoder.search now returns a single result instead of an array.
54
+ * DEPRECATION: <tt>Geocoder.search</tt> now returns a single result instead of an array.
42
55
  * DEPRECATION: <tt>fetch_coordinates!</tt> has been superceded by +geocode+ (then save your object manually).
43
56
  * DEPRECATION: <tt>fetch_address!</tt> has been superceded by +reverse_geocode+ (then save your object manually).
44
57
  * Fix: don't die when trying to get coordinates with a nil address (github.com/zmack).
45
58
 
46
59
  == 0.9.8 (2011 Feb 8)
47
60
 
48
- * Include geocode:all Rake task in gem (was missing!).
49
- * Add Geocoder.search for access to Google's full response.
61
+ * Include <tt>geocode:all</tt> Rake task in gem (was missing!).
62
+ * Add <tt>Geocoder.search</tt> for access to Google's full response.
50
63
  * Add ability to configure Google connection timeout.
51
64
  * Emit warnings on Google connection problems and errors.
52
65
  * Refactor: insert Geocoder into ActiveRecord via Railtie.
@@ -129,7 +142,7 @@ Per-release changes to Geocoder.
129
142
 
130
143
  == 0.8.1 (2009 Oct 8)
131
144
 
132
- * Extract XML-fetching code from Geocoder.search and place in Geocoder._fetch_xml (for ease of mocking).
145
+ * Extract XML-fetching code from <tt>Geocoder.search</tt> and place in Geocoder._fetch_xml (for ease of mocking).
133
146
  * Add tests for coordinate-fetching instance methods.
134
147
 
135
148
  == 0.8.0 (2009 Oct 1)
data/README.rdoc CHANGED
@@ -122,7 +122,7 @@ Some utility methods are also available:
122
122
  => 3619.77359999382
123
123
 
124
124
  # find the geographic center (aka center of gravity) of objects or points
125
- Geocoder::Calculations.geographic_center(city1, city2, [40.22,-73.99], city4)
125
+ Geocoder::Calculations.geographic_center([city1, city2, [40.22,-73.99], city4])
126
126
  => [35.14968, -90.048929]
127
127
 
128
128
  Please see the code for more methods and detailed information about arguments (eg, working with kilometers).
@@ -208,68 +208,121 @@ Every <tt>Geocoder::Result</tt> object, +result+, provides the following data:
208
208
  * <tt>result.coordinates</tt> - array of the above two
209
209
  * <tt>result.address</tt> - string
210
210
  * <tt>result.city</tt> - string
211
+ * <tt>result.state</tt> - string
212
+ * <tt>result.state_code</tt> - string
211
213
  * <tt>result.postal_code</tt> - string
212
214
  * <tt>result.country_name</tt> - string
213
215
  * <tt>result.country_code</tt> - string
214
216
 
215
- and if you're familiar with the results returned by the geocoding service you're using, you can access even more (see code comments for details: <tt>lib/geocoder/results/*</tt>).
217
+ If you're familiar with the results returned by the geocoding service you're using you can access even more data, but you'll need to be familiar with the particular <tt>Geocoder::Result</tt> object you're using and the structure of your geocoding service's responses. (See below for links to geocoding service documentation.)
216
218
 
217
219
 
218
220
  == Geocoding Services
219
221
 
220
- By default Geocoder uses Google's geocoding API to fetch coordinates and addresses. However if you wish to use Yahoo's geocoding API you can simply add this to an initializer:
222
+ By default Geocoder uses Google's geocoding API to fetch coordinates and street addresses (FreeGeoIP is used for IP address info). However there are several other APIs supported, as well as a variety of settings. Please see the listing and comparison below for details on specific geocoding services (not all settings are supported by all services). The configuration options are:
221
223
 
222
224
  # config/initializers/geocoder.rb
223
- Geocoder::Configuration.lookup = :yahoo
224
-
225
- Street address geocoding services currently supported (valid settings for the above):
226
-
227
- * Google: <tt>:google</tt>
228
- * Yahoo: <tt>:yahoo</tt>
229
- * Geocoder.ca: <tt>:geocoder_ca</tt> (US and Canada only)
230
-
231
- Note that the result objects returned by different geocoding services all implement the methods listed above. Beyond that, however, you must be familiar with your particular subclass of <tt>Geocoder::Result</tt> and the geocoding service's result structure:
232
225
 
233
- * Google: http://code.google.com/apis/maps/documentation/geocoding/#JSON
234
- * Yahoo: http://developer.yahoo.com/geo/placefinder/guide/responses.html
235
- * Geocoder.ca: (???)
236
- * FreeGeoIP: http://github.com/fiorix/freegeoip/blob/master/README.rst
237
-
238
- === API Keys
239
-
240
- To use your Google API key or Yahoo app ID:
226
+ # geocoding service (see below for supported options):
227
+ Geocoder::Configuration.lookup = :yahoo
241
228
 
229
+ # to use an API key:
242
230
  Geocoder::Configuration.api_key = "..."
243
231
 
244
- To obtain an API key (not required):
245
-
246
- * Yahoo: https://developer.apps.yahoo.com/wsregapp
247
- * Google: http://code.google.com/apis/maps/signup.html
248
-
249
- === Timeout
250
-
251
- You can set the timeout used for connections to the geocoding service. The default is 3 seconds but if you want to set it to 5, for example, put the following in an initializer:
252
-
232
+ # geocoding service request timeout, in seconds (default 3):
253
233
  Geocoder::Configuration.timeout = 5
254
234
 
255
- === Language
256
-
257
- You can set the language used for reverse geocoding results to German, for example, by setting the following:
235
+ # use HTTPS for geocoding service connections:
236
+ Geocoder::Configuration.use_https = true
258
237
 
238
+ # language to use (for search queries and reverse geocoding):
259
239
  Geocoder::Configuration.language = :de
260
240
 
261
- For a list of supported languages see the documentation for the geocoding service you're using.
262
-
263
- === HTTPS
241
+ # use a proxy to access the service:
242
+ Geocoder::Configuration.http_proxy = "127.4.4.1"
243
+ Geocoder::Configuration.https_proxy = "127.4.4.2" # only if HTTPS is needed
264
244
 
265
- If you want to use HTTPS for geocoding service connections:
266
-
267
- Geocoder::Configuration.use_https = true
268
-
269
- Note that currently the only service that supports HTTPS is Google.
245
+ # caching (see below for details)
246
+ Geocoder::Configuration.cache = Redis.new
247
+ Geocoder::Configuration.cache_prefix = "..."
270
248
 
271
249
 
272
- == Caching Results
250
+ === Listing and Comparison
251
+
252
+ The following is a comparison of the supported geocoding APIs. The "Limitations" listed for each are a very brief and incomplete summary of some special limitations beyond basic data source attribution. Please read the official Terms of Service for a service before using it.
253
+
254
+ ==== Google (<tt>:google</tt>)
255
+
256
+ API key:: optional (required for Premier)
257
+ Key signup:: http://code.google.com/apis/maps/signup.html
258
+ Quota:: 2,500 requests/day, 100,000 with Google Maps API Premier
259
+ Region:: world
260
+ SSL support:: yes
261
+ Languages:: ar, eu, bg, bn, ca, cs, da, de, el, en, en-AU, en-GB, es, eu, fa, fi, fil, fr, gl, gu, hi, hr, hu, id, it, iw, ja, kn, ko, lt, lv, ml, mr, nl, no, pl, pt, pt-BR, pt-PT, ro, ru, sk, sl, sr, sv, tl, ta, te, th, tr, uk, vi, zh-CN, zh-TW (see http://spreadsheets.google.com/pub?key=p9pdwsai2hDMsLkXsoM05KQ&gid=1)
262
+ Documentation:: http://code.google.com/apis/maps/documentation/geocoding/#JSON
263
+ Terms of Service:: http://code.google.com/apis/maps/terms.html#section_10_12
264
+ Limitations:: "You must not use or display the Content without a corresponding Google map, unless you are explicitly permitted to do so in the Maps APIs Documentation, or through written permission from Google." "You must not pre-fetch, cache, or store any Content, except that you may store: (i) limited amounts of Content for the purpose of improving the performance of your Maps API Implementation..."
265
+
266
+ ==== Yahoo (<tt>:yahoo</tt>)
267
+
268
+ API key:: optional in development (required for production apps)
269
+ Key signup:: https://developer.apps.yahoo.com/wsregapp
270
+ Quota:: 50,000 requests/day, more available by special arrangement
271
+ Region:: world
272
+ SSL support:: no
273
+ Languages:: ?
274
+ Documentation:: http://developer.yahoo.com/geo/placefinder/guide/responses.html
275
+ Terms of Service:: http://info.yahoo.com/legal/us/yahoo/maps/mapsapi/mapsapi-2141.html
276
+ Limitations:: "YOU SHALL NOT... (viii) store or allow end users to store map imagery, map data or geocoded location information from the Yahoo! Maps APIs for any future use; (ix) use the stand-alone geocoder for any use other than displaying Yahoo! Maps or displaying points on Yahoo! Maps;"
277
+
278
+ ==== Bing (<tt>:bing</tt>)
279
+
280
+ API key:: required
281
+ Key signup:: http://www.bingmapsportal.com
282
+ Quota:: 50,000 requests/24 hrs
283
+ Region:: world
284
+ SSL support:: no
285
+ Languages:: ?
286
+ Documentation:: http://msdn.microsoft.com/en-us/library/ff701715.aspx
287
+ Terms of Service:: http://www.microsoft.com/maps/product/terms.html
288
+ Limitations:: No country codes or state names. Must be used on "public-facing, non-password protected web sites," "in conjunction with Bing Maps or an application that integrates Bing Maps."
289
+
290
+ ==== Yandex (<tt>:yandex</tt>)
291
+
292
+ API key:: required
293
+ Key signup:: http://api.yandex.ru/maps/intro/concepts/intro.xml#apikey
294
+ Quota:: ?
295
+ Region:: Russia
296
+ SSL support:: no
297
+ Languages:: Russian, Belarusian, and Ukrainian
298
+ Documentation:: http://api.yandex.ru/maps/geocoder/doc/desc/concepts/response_structure.xml
299
+ Terms of Service:: http://api.yandex.com/direct/eula.xml?ncrnd=8453
300
+ Limitations:: ?
301
+
302
+ ==== Geocoder.ca (<tt>:geocoder_ca</tt>)
303
+
304
+ API key:: none
305
+ Quota:: ?
306
+ Region:: US and Canada
307
+ SSL support:: no
308
+ Languages:: English
309
+ Documentation:: ?
310
+ Terms of Service:: http://geocoder.ca/?terms=1
311
+ Limitations:: "Under no circumstances can our data be re-distributed or re-sold by anyone to other parties without our written permission."
312
+
313
+ ==== FreeGeoIP
314
+
315
+ API key:: none
316
+ Quota:: ?
317
+ Region:: world
318
+ SSL support:: no
319
+ Languages:: English
320
+ Documentation:: http://github.com/fiorix/freegeoip/blob/master/README.rst
321
+ Terms of Service:: ?
322
+ Limitations:: ?
323
+
324
+
325
+ == Caching
273
326
 
274
327
  It's a good idea, when relying on any external service, to cache retrieved data. When implemented correctly it improves your app's response time and stability. It's easy to cache geocoding results with Geocoder, just configure a cache store:
275
328
 
@@ -296,6 +349,8 @@ If you need to expire cached content:
296
349
 
297
350
  Do *not* include the prefix when passing a URL to be expired. Expiring <tt>:all</tt> will only expire keys with the configured prefix (won't kill every entry in your key/value store).
298
351
 
352
+ <i>Before you implement caching in your app please be sure that doing so does not violate the Terms of Service for your geocoding service.</i>
353
+
299
354
 
300
355
  == Forward and Reverse Geocoding in the Same Model
301
356
 
@@ -338,6 +393,23 @@ You can use Geocoder outside of Rails by calling the <tt>Geocoder.search</tt> me
338
393
  This returns an array of <tt>Geocoder::Result</tt> objects with all information provided by the geocoding service. Please see above and in the code for details.
339
394
 
340
395
 
396
+ == Command Line Interface
397
+
398
+ When you install the Geocoder gem it adds a +geocode+ command to your shell. You can search for a street address, IP address, postal code, coordinates, etc just like you can with the Geocoder.search method for example:
399
+
400
+ $ geocode 29.951,-90.081
401
+ Latitude: 29.952211
402
+ Longitude: -90.080563
403
+ Full address: 1500 Sugar Bowl Dr, New Orleans, LA 70112, USA
404
+ City: New Orleans
405
+ State/province: Louisiana
406
+ Postal code: 70112
407
+ Country: United States
408
+ Google map: http://maps.google.com/maps?q=29.952211,-90.080563
409
+
410
+ There are also a number of options for setting the geocoding API, key, and language, viewing the raw JSON reponse, and more. Please run <tt>geocode -h</tt> for details.
411
+
412
+
341
413
  == Notes on Mongoid
342
414
 
343
415
  === The Near Method
@@ -346,7 +418,7 @@ Mongoid document classes have a built-in +near+ scope, but since it only works t
346
418
 
347
419
  === Latitude/Longitude Order
348
420
 
349
- Coordinates are generally printed and spoken as latitude, then logitude ([lat,lon]). Geocoder respects this convention and always expects method arguments to be given in [lat,lon] order. However, MongoDB requires that coordinates be stored in [lon,lat] order as per the GeoJSON spec (http://geojson.org/geojson-spec.html#positions), so internally they are stored "backwards." However, this does not affect order of arguments to methods when using Mongoid. I mention this only in case you notice it and freak out. Don't worry. Everything is going to be OK.
421
+ Coordinates are generally printed and spoken as latitude, then logitude ([lat,lon]). Geocoder respects this convention and always expects method arguments to be given in [lat,lon] order. However, MongoDB requires that coordinates be stored in [lon,lat] order as per the GeoJSON spec (http://geojson.org/geojson-spec.html#positions), so internally they are stored "backwards." However, this does not affect order of arguments to methods when using Mongoid.
350
422
 
351
423
 
352
424
  == Distance Queries in SQLite
@@ -376,19 +448,12 @@ http://github.com/alexreisner/geocoder_test
376
448
 
377
449
  == Known Issue
378
450
 
379
- You cannot use the +near+ scope with another scope that provides an +includes+ option because the +SELECT+ clause generated by +near+ will overwrite it (or vice versa). Instead, try using +joins+ and pass a <tt>:select</tt> option to the +near+ scope to get the columns you want. For example, in Rails 2 syntax:
451
+ You cannot use the +near+ scope with another scope that provides an +includes+ option because the +SELECT+ clause generated by +near+ will overwrite it (or vice versa). Instead, try using +joins+ and pass a <tt>:select</tt> option to the +near+ scope to get the columns you want. For example:
380
452
 
381
- # instead of :includes => :venues:
382
- City.near("Omaha, NE", 20, :select => "venues.*").all(:joins => :venues)
453
+ # instead of City.near(...).includes(:venues)
454
+ City.near("Omaha, NE", 20, :select => "cities.*, venues.*").joins(:venues)
383
455
 
384
456
  If anyone has a more elegant solution to this problem I am very interested in seeing it.
385
457
 
386
458
 
387
- == Roadmap
388
-
389
- * add support for more ORMs (Mongoid, DataMapper)
390
- * add support for more geocoding services
391
- * maintain the same simple interface
392
-
393
-
394
459
  Copyright (c) 2009-11 Alex Reisner, released under the MIT license
data/bin/geocode ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'geocoder/cli'
4
+
5
+ Geocoder::Cli.run ARGV
@@ -51,13 +51,7 @@ module Geocoder
51
51
  #
52
52
  # * <tt>:units</tt> - <tt>:mi</tt> (default) or <tt>:km</tt>
53
53
  #
54
- def distance_between(point1, point2, options = {}, *args)
55
- if args.size > 0
56
- warn "DEPRECATION WARNING: Instead of passing lat1/lon1/lat2/lon2 as separate arguments to the distance_between method, please pass two two-element arrays: [#{point1},#{point2}], [#{options}, #{args.first}]. The old argument format will not be supported in Geocoder v.1.0."
57
- point1 = [point1, point2]
58
- point2 = [options, args.shift]
59
- options = args.shift || {}
60
- end
54
+ def distance_between(point1, point2, options = {})
61
55
 
62
56
  # set default options
63
57
  options[:units] ||= :mi
@@ -95,14 +89,9 @@ module Geocoder
95
89
  #
96
90
  # Based on: http://www.movable-type.co.uk/scripts/latlong.html
97
91
  #
98
- def bearing_between(point1, point2, options = {}, *args)
99
- if args.size > 0
100
- warn "DEPRECATION WARNING: Instead of passing lat1/lon1/lat2/lon2 as separate arguments to the bearing_between method, please pass two two-element arrays: [#{point1},#{point2}], [#{options}, #{args.first}]. The old argument format will not be supported in Geocoder v.1.0."
101
- point1 = [point1, point2]
102
- point2 = [options, args.shift]
103
- options = args.shift || {}
104
- end
92
+ def bearing_between(point1, point2, options = {})
105
93
 
94
+ # set default options
106
95
  options[:method] = :linear unless options[:method] == :spherical
107
96
 
108
97
  # convert to coordinate arrays
@@ -190,13 +179,7 @@ module Geocoder
190
179
  #
191
180
  # * <tt>:units</tt> - <tt>:mi</tt> (default) or <tt>:km</tt>
192
181
  #
193
- def bounding_box(point, radius, options = {}, *args)
194
- if point.is_a?(Numeric)
195
- warn "DEPRECATION WARNING: Instead of passing latitude/longitude as separate arguments to the bounding_box method, please pass an array [#{point},#{radius}], a geocoded object, or a geocodable address (string). The old argument format will not be supported in Geocoder v.1.0."
196
- point = [point, radius]
197
- radius = options
198
- options = args.first || {}
199
- end
182
+ def bounding_box(point, radius, options = {})
200
183
  lat,lon = extract_coordinates(point)
201
184
  radius = radius.to_f
202
185
  units = options[:units] || :mi
@@ -0,0 +1,111 @@
1
+ require 'geocoder'
2
+ require 'optparse'
3
+
4
+ module Geocoder
5
+ class Cli
6
+
7
+ def self.run(args, out = STDOUT)
8
+ show_url = false
9
+ show_json = false
10
+
11
+ OptionParser.new{ |opts|
12
+ opts.banner = "Usage:\n geocode [options] <location>"
13
+ opts.separator "\nOptions: "
14
+
15
+ opts.on("-k <key>", "--key <key>",
16
+ "Key for geocoding API (optional for most)") do |key|
17
+ Geocoder::Configuration.api_key = key
18
+ end
19
+
20
+ opts.on("-l <language>", "--language <language>",
21
+ "Language of output (see API docs for valid choices)") do |language|
22
+ Geocoder::Configuration.language = language
23
+ end
24
+
25
+ opts.on("-p <proxy>", "--proxy <proxy>",
26
+ "HTTP proxy server to use (user:pass@host:port)") do |proxy|
27
+ Geocoder::Configuration.http_proxy = proxy
28
+ end
29
+
30
+ opts.on("-s <service>", Geocoder.street_lookups, "--service <service>",
31
+ "Geocoding service: #{Geocoder.street_lookups * ', '}") do |service|
32
+ Geocoder::Configuration.lookup = service.to_sym
33
+ end
34
+
35
+ opts.on("-t <seconds>", "--timeout <seconds>",
36
+ "Maximum number of seconds to wait for API response") do |timeout|
37
+ Geocoder::Configuration.timeout = timeout.to_i
38
+ end
39
+
40
+ opts.on("-j", "--json", "Print API's raw JSON response") do
41
+ show_json = true
42
+ end
43
+
44
+ opts.on("-u", "--url", "Print URL for API query instead of result") do
45
+ show_url = true
46
+ end
47
+
48
+ opts.on_tail("-v", "--version", "Print version number") do
49
+ require "geocoder/version"
50
+ out << "Geocoder #{Geocoder::VERSION}\n"
51
+ exit
52
+ end
53
+
54
+ opts.on_tail("-h", "--help", "Print this help") do
55
+ out << "Look up geographic information about a location.\n\n"
56
+ out << opts
57
+ out << "\nCreated and maintained by Alex Reisner, available under the MIT License.\n"
58
+ out << "Report bugs and contribute at http://github.com/alexreisner/geocoder\n"
59
+ exit
60
+ end
61
+ }.parse!(args)
62
+
63
+ query = args.join(" ")
64
+
65
+ if query == ""
66
+ out << "Please specify a location (run `geocode -h` for more info).\n"
67
+ exit 1
68
+ end
69
+
70
+ if show_url and show_json
71
+ out << "You can only specify one of -j and -u.\n"
72
+ exit 2
73
+ end
74
+
75
+ if show_url
76
+ lookup = Geocoder.send(:lookup, query)
77
+ reverse = lookup.send(:coordinates?, query)
78
+ out << lookup.send(:query_url, query, reverse) + "\n"
79
+ exit 0
80
+ end
81
+
82
+ if show_json
83
+ lookup = Geocoder.send(:lookup, query)
84
+ reverse = lookup.send(:coordinates?, query)
85
+ out << lookup.send(:fetch_raw_data, query, reverse) + "\n"
86
+ exit 0
87
+ end
88
+
89
+ if (result = Geocoder.search(query).first)
90
+ lookup = Geocoder.send(:get_lookup, :google)
91
+ lines = [
92
+ ["Latitude", result.latitude],
93
+ ["Longitude", result.longitude],
94
+ ["Full address", result.address],
95
+ ["City", result.city],
96
+ ["State/province", result.state],
97
+ ["Postal code", result.postal_code],
98
+ ["Country", result.country],
99
+ ["Google map", lookup.map_link_url(result.coordinates)],
100
+ ]
101
+ lines.each do |line|
102
+ out << (line[0] + ": ").ljust(18) + line[1].to_s + "\n"
103
+ end
104
+ exit 0
105
+ else
106
+ out << "Location '#{query}' not found.\n"
107
+ exit 1
108
+ end
109
+ end
110
+ end
111
+ end
@@ -15,6 +15,12 @@ module Geocoder
15
15
  # use HTTPS for lookup requests? (if supported)
16
16
  [:use_https, false],
17
17
 
18
+ # HTTP proxy server (user:pass@host:port)
19
+ [:http_proxy, nil],
20
+
21
+ # HTTPS proxy server (user:pass@host:port)
22
+ [:https_proxy, nil],
23
+
18
24
  # API key for geocoding service
19
25
  [:api_key, nil],
20
26
 
@@ -32,13 +38,6 @@ module Geocoder
32
38
  eval("def self.#{o}=(obj); @@#{o} = obj; end")
33
39
  end
34
40
 
35
- # legacy support
36
- def self.yahoo_app_id=(value)
37
- warn "DEPRECATION WARNING: Geocoder's 'yahoo_app_id' setting has been replaced by 'api_key'. " +
38
- "This method will be removed in Geocoder v1.0."
39
- @@api_key = value
40
- end
41
-
42
41
  ##
43
42
  # Set all values to default.
44
43
  #
@@ -1,4 +1,6 @@
1
1
  require 'net/http'
2
+ require 'uri'
3
+
2
4
  unless defined?(ActiveSupport::JSON)
3
5
  begin
4
6
  require 'rubygems' # for Ruby 1.8
@@ -20,12 +22,7 @@ module Geocoder
20
22
  # "205.128.54.202") for geocoding, or coordinates (latitude, longitude)
21
23
  # for reverse geocoding. Returns an array of <tt>Geocoder::Result</tt>s.
22
24
  #
23
- def search(query, *args)
24
- # convert coordinates as separate arguments to an array
25
- if query.is_a?(Numeric) and args.first.is_a?(Numeric)
26
- warn "DEPRECATION WARNING: Instead of passing latitude/longitude as separate arguments to the search method, please pass an array: [#{query},#{args.first}]. The old argument format will not be supported in Geocoder v.1.0."
27
- query = [query, args.first]
28
- end
25
+ def search(query)
29
26
 
30
27
  # if coordinates given as string, turn into array
31
28
  query = query.split(/\s*,\s*/) if coordinates?(query)
@@ -39,9 +36,39 @@ module Geocoder
39
36
  results(query, reverse).map{ |r| result_class.new(r) }
40
37
  end
41
38
 
39
+ ##
40
+ # Return the URL for a map of the given coordinates.
41
+ #
42
+ # Not necessarily implemented by all subclasses as only some lookups
43
+ # also provide maps.
44
+ #
45
+ def map_link_url(coordinates)
46
+ nil
47
+ end
48
+
42
49
 
43
50
  private # -------------------------------------------------------------
44
51
 
52
+ ##
53
+ # Object used to make HTTP requests.
54
+ #
55
+ def http_client
56
+ protocol = "http#{'s' if Geocoder::Configuration.use_https}"
57
+ proxy_name = "#{protocol}_proxy"
58
+ if proxy = Geocoder::Configuration.send(proxy_name)
59
+ proxy_url = protocol + '://' + proxy
60
+ begin
61
+ uri = URI.parse(proxy_url)
62
+ rescue URI::InvalidURIError
63
+ raise ConfigurationError,
64
+ "Error parsing #{protocol.upcase} proxy URL: '#{proxy_url}'"
65
+ end
66
+ Net::HTTP::Proxy(uri.host, uri.port, uri.user, uri.password)
67
+ else
68
+ Net::HTTP
69
+ end
70
+ end
71
+
45
72
  ##
46
73
  # Geocoder::Result object or nil on timeout or other error.
47
74
  #
@@ -74,7 +101,7 @@ module Geocoder
74
101
  rescue TimeoutError
75
102
  warn "Geocoding API not responding fast enough " +
76
103
  "(see Geocoder::Configuration.timeout to set limit)."
77
- end
104
+ end
78
105
  end
79
106
 
80
107
  ##
@@ -107,7 +134,7 @@ module Geocoder
107
134
  timeout(Geocoder::Configuration.timeout) do
108
135
  url = query_url(query, reverse)
109
136
  unless cache and response = cache[url]
110
- response = Net::HTTP.get_response(URI.parse(url)).body
137
+ response = http_client.get_response(URI.parse(url)).body
111
138
  if cache
112
139
  cache[url] = response
113
140
  end
@@ -134,7 +161,7 @@ module Geocoder
134
161
  # Does the given string look like latitude/longitude coordinates?
135
162
  #
136
163
  def coordinates?(value)
137
- !!value.to_s.match(/^[0-9\.\-]+, *[0-9\.\-]+$/)
164
+ value.is_a?(String) and !!value.to_s.match(/^-?[0-9\.]+, *-?[0-9\.]+$/)
138
165
  end
139
166
 
140
167
  ##
@@ -0,0 +1,33 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/bing"
3
+
4
+ module Geocoder::Lookup
5
+ class Bing < Base
6
+
7
+ def map_link_url(coordinates)
8
+ "http://www.bing.com/maps/default.aspx?cp=#{coordinates.join('~')}"
9
+ end
10
+
11
+ private # ---------------------------------------------------------------
12
+
13
+ def results(query, reverse = false)
14
+ return [] unless doc = fetch_data(query, reverse)
15
+
16
+ if doc['statusDescription'] == "OK"
17
+ return doc['resourceSets'].first['estimatedTotal'] > 0 ? doc['resourceSets'].first['resources'] : []
18
+ else
19
+ warn "Bing Geocoding API error: #{doc['statusCode']} (#{doc['statusDescription']})."
20
+ return []
21
+ end
22
+ end
23
+
24
+ def query_url(query, reverse = false)
25
+ params = {:key => Geocoder::Configuration.api_key}
26
+ params[:query] = query unless reverse
27
+
28
+ base_url = "http://dev.virtualearth.net/REST/v1/Locations"
29
+ url_tail = reverse ? "/#{query}?" : "?"
30
+ base_url + url_tail + hash_to_query(params)
31
+ end
32
+ end
33
+ end
@@ -4,6 +4,10 @@ require "geocoder/results/google"
4
4
  module Geocoder::Lookup
5
5
  class Google < Base
6
6
 
7
+ def map_link_url(coordinates)
8
+ "http://maps.google.com/maps?q=#{coordinates.join(',')}"
9
+ end
10
+
7
11
  private # ---------------------------------------------------------------
8
12
 
9
13
  def results(query, reverse = false)
@@ -4,6 +4,10 @@ require "geocoder/results/yahoo"
4
4
  module Geocoder::Lookup
5
5
  class Yahoo < Base
6
6
 
7
+ def map_link_url(coordinates)
8
+ "http://maps.yahoo.com/#lat=#{coordinates[0]}&lon=#{coordinates[1]}"
9
+ end
10
+
7
11
  private # ---------------------------------------------------------------
8
12
 
9
13
  def results(query, reverse = false)
@@ -18,7 +22,7 @@ module Geocoder::Lookup
18
22
 
19
23
  def query_url(query, reverse = false)
20
24
  params = {
21
- :location => query,
25
+ :location => query,
22
26
  :flags => "JXTSR",
23
27
  :gflags => "AC#{'R' if reverse}",
24
28
  :locale => "#{Geocoder::Configuration.language}_US",
@@ -28,4 +32,3 @@ module Geocoder::Lookup
28
32
  end
29
33
  end
30
34
  end
31
-