geocoder 1.2.9 → 1.3.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -0
  3. data/README.md +81 -25
  4. data/lib/generators/geocoder/config/templates/initializer.rb +15 -15
  5. data/lib/geocoder/calculations.rb +6 -3
  6. data/lib/geocoder/configuration.rb +3 -2
  7. data/lib/geocoder/exceptions.rb +5 -0
  8. data/lib/geocoder/kernel_logger.rb +25 -0
  9. data/lib/geocoder/logger.rb +13 -21
  10. data/lib/geocoder/lookup.rb +6 -4
  11. data/lib/geocoder/lookups/baidu.rb +1 -1
  12. data/lib/geocoder/lookups/baidu_ip.rb +1 -1
  13. data/lib/geocoder/lookups/base.rb +13 -13
  14. data/lib/geocoder/lookups/geocoder_us.rb +6 -2
  15. data/lib/geocoder/lookups/geoip2.rb +10 -5
  16. data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
  17. data/lib/geocoder/lookups/google.rb +9 -0
  18. data/lib/geocoder/lookups/mapbox.rb +53 -0
  19. data/lib/geocoder/lookups/maxmind_local.rb +1 -1
  20. data/lib/geocoder/lookups/telize.rb +10 -3
  21. data/lib/geocoder/lookups/yandex.rb +4 -0
  22. data/lib/geocoder/request.rb +1 -1
  23. data/lib/geocoder/results/esri.rb +22 -6
  24. data/lib/geocoder/results/geoip2.rb +12 -8
  25. data/lib/geocoder/results/geoportail_lu.rb +69 -0
  26. data/lib/geocoder/results/google.rb +8 -0
  27. data/lib/geocoder/results/mapbox.rb +55 -0
  28. data/lib/geocoder/results/mapquest.rb +4 -0
  29. data/lib/geocoder/results/pointpin.rb +0 -4
  30. data/lib/geocoder/stores/active_record.rb +16 -0
  31. data/lib/geocoder/stores/base.rb +0 -11
  32. data/lib/geocoder/stores/mongo_base.rb +0 -31
  33. data/lib/geocoder/version.rb +1 -1
  34. data/lib/geocoder.rb +1 -0
  35. data/lib/maxmind_database.rb +1 -1
  36. data/lib/tasks/geocoder.rake +12 -3
  37. metadata +8 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 69826a3c50884c70a7a937f80f1280f234687e2f
4
- data.tar.gz: 4bcdee80b4db4db6c7efbd2886d9fab96b4976bf
3
+ metadata.gz: e7a2b3e33175d20be86a8eaf6c74d6178bc71991
4
+ data.tar.gz: d0dc03b689fbc43f16ae9395c7f743a3dd7876bd
5
5
  SHA512:
6
- metadata.gz: c9d0cbaa046ebc593590340937a29b687e98107ea87606b4fc10ab3bd000376471f4b940f3848bd68a75e1e8f273843e29278ca4449e8ce5219a46ed9daf468e
7
- data.tar.gz: ed245fd8affec37d6f60f54bedf3fb35a704cf6f4f134537bdcac5356bd245c64df0f707b690990585deae794d24bf30c16aaa0f754ee52b8a09c2b79236a509
6
+ metadata.gz: cb9f5c459af278bd20438a714475dece555b72222c34eab8c8fb61f6ddfc695848d330e9b84f366c8d67e5f253bda7d5e61020ab46382f8fbb40c8b7a9a58e82
7
+ data.tar.gz: ca02902240f5287a570ee05b0bc3b0300708200108b09543763e761ad1f0a2371355ef651471cdf96ce5cdabf104a39aedb04ef684e4f02aa3023911c27d7c4a
data/CHANGELOG.md CHANGED
@@ -3,6 +3,41 @@ Changelog
3
3
 
4
4
  Major changes to Geocoder for each release. Please see the Git log for complete list of changes.
5
5
 
6
+ 1.3.0 (2016 Jan 31)
7
+ -------------------
8
+ * Lazy load lookups to reduce memory footprint (thanks github.com/TrangPham).
9
+ * Add :geoportail_lu lookup (Luxembourg only) (thanks github.com/mdebo).
10
+ * Maxmind local query performance improvement (thanks github.com/vojtad).
11
+ * Remove deprecated Mongo near query methods (please use Mongo-native methods instead).
12
+
13
+ 1.2.14 (2015 Dec 27)
14
+ --------------------
15
+ * Fix bug in :geoip2 lookup (thanks github.com/mromulus).
16
+
17
+ 1.2.13 (2015 Dec 15)
18
+ --------------------
19
+ * Update :telize IP lookup to reflect new URL (thanks github.com/jfredrickson).
20
+ * Add reverse geocode rake task (thanks github.com/FanaHOVA).
21
+ * Fix reversed coordinates array with Mapbox (thanks github.com/marcusat).
22
+ * Fix missing city name in some cases with ESRI (thanks github.com/roybotnik).
23
+ * Prevent re-opening of DB file on every read with :geoip2 (thanks github.com/oogali).
24
+
25
+ 1.2.12 (2015 Oct 29)
26
+ --------------------
27
+ * Fix Ruby 1.9.3 incompatibility (remove non-existent timeout classes) (thanks github.com/roychri).
28
+
29
+ 1.2.11 (2015 Sep 10)
30
+ --------------------
31
+ * Fix load issue on Ruby 1.9.3.
32
+
33
+ 1.2.10 (2015 Sep 7)
34
+ -------------------
35
+ * Force Yandex to use HTTPS (thanks github.com/donbobka).
36
+ * Force :google to use HTTPS if API key set.
37
+ * Fix out-of-the-box verbosity issues (GH #881).
38
+ * Improve timeout mechanism and add exception Geocoder::LookupTimeout (thanks github.com/ankane).
39
+ * Deprecate .near and #nearbys for MongoDB-backed models.
40
+
6
41
  1.2.9 (2015 Jun 12)
7
42
  -------------------
8
43
  * Don't cache unsuccessful responses from Bing (thanks github.com/peteb).
data/README.md CHANGED
@@ -9,7 +9,7 @@ _Please note that this README is for the current `HEAD` and may document feature
9
9
  Compatibility
10
10
  -------------
11
11
 
12
- * Supports multiple Ruby versions: Ruby 1.9.3, 2.0.x, 2.1.x, JRuby, and Rubinius.
12
+ * Supports multiple Ruby versions: Ruby 1.9.3, 2.x, JRuby, and Rubinius.
13
13
  * Supports multiple databases: MySQL, PostgreSQL, SQLite, and MongoDB (1.7.0 and higher).
14
14
  * Supports Rails 3 and 4. If you need to use it with Rails 2 please see the `rails2` branch (no longer maintained, limited feature set).
15
15
  * Works very well outside of Rails, you just need to install either the `json` (for MRI) or `json_pure` (for JRuby) gem.
@@ -47,7 +47,7 @@ Your model must have two attributes (database columns) for storing latitude and
47
47
  rails generate migration AddLatitudeAndLongitudeToModel latitude:float longitude:float
48
48
  rake db:migrate
49
49
 
50
- For reverse geocoding your model must provide a method that returns an address. This can be a single attribute, but it can also be a method that returns a string assembled from different attributes (eg: `city`, `state`, and `country`).
50
+ For geocoding your model must provide a method that returns an address. This can be a single attribute, but it can also be a method that returns a string assembled from different attributes (eg: `city`, `state`, and `country`).
51
51
 
52
52
  Next, your model must tell Geocoder which method returns your object's geocodable address:
53
53
 
@@ -106,6 +106,10 @@ If you have just added geocoding to an existing application with a lot of object
106
106
 
107
107
  rake geocode:all CLASS=YourModel
108
108
 
109
+ If you need reverse geocoding instead, call the task with REVERSE=true:
110
+
111
+ rake geocode:all CLASS=YourModel REVERSE=true
112
+
109
113
  Geocoder will print warnings if you exceed the rate limit for your geocoding service. Some services — Google notably — enforce a per-second limit in addition to a per-day limit. To avoid exceeding the per-second limit, you can add a `SLEEP` option to pause between requests for a given amount of time. You can also load objects in batches to save memory, for example:
110
114
 
111
115
  rake geocode:all CLASS=YourModel SLEEP=0.25 BATCH=100
@@ -140,6 +144,12 @@ See _Advanced Geocoding_ below for more information about `Geocoder::Result` obj
140
144
  Location-Aware Database Queries
141
145
  -------------------------------
142
146
 
147
+ ### For Mongo-backed models:
148
+
149
+ Please use MongoDB's [geospatial query language](https://docs.mongodb.org/manual/reference/command/geoNear/). Mongoid also provides [a DSL](http://mongoid.github.io/en/mongoid/docs/querying.html#geo_near) for doing near queries.
150
+
151
+ ### For ActiveRecord models:
152
+
143
153
  To find objects by location, use the following scopes:
144
154
 
145
155
  Venue.near('Omaha, NE, US', 20) # venues within 20 miles of Omaha
@@ -149,6 +159,10 @@ To find objects by location, use the following scopes:
149
159
  Venue.geocoded # venues with coordinates
150
160
  Venue.not_geocoded # venues without coordinates
151
161
 
162
+ by default, objects are ordered by distance. To remove the ORDER BY clause use the following:
163
+
164
+ Venue.near('Omaha', 20, :order => false)
165
+
152
166
  With geocoded objects you can do things like this:
153
167
 
154
168
  if obj.geocoded?
@@ -294,7 +308,7 @@ Every `Geocoder::Result` object, `result`, provides the following data:
294
308
 
295
309
  * `result.latitude` - float
296
310
  * `result.longitude` - float
297
- * `result.coordinates` - array of the above two
311
+ * `result.coordinates` - array of the above two in the form of `[lat,lon]`
298
312
  * `result.address` - string
299
313
  * `result.city` - string
300
314
  * `result.state` - string
@@ -351,6 +365,10 @@ Please see the [source code for each lookup](https://github.com/alexreisner/geoc
351
365
  # with Nominatim:
352
366
  Geocoder.search("Paris", :params => {:countrycodes => "gb,de,fr,es,us"})
353
367
 
368
+ Or, to search within a particular region with Google:
369
+
370
+ Geocoder.search("...", :params => {:region => "..."})
371
+
354
372
  You can also configure multiple geocoding services at once, like this:
355
373
 
356
374
  Geocoder.configure(
@@ -381,19 +399,26 @@ The above combines global and service-specific options and could be useful if yo
381
399
 
382
400
  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.
383
401
 
384
- #### Google (`:google`, `:google_premier`)
402
+ #### Google (`:google`)
385
403
 
386
- * **API key**: required for Premier, optional for the free service (if using the free service with API key, https is required. Add `:use_https => true` to `Geocoder.configure`)
387
- * **Key signup**: https://developers.google.com/maps/documentation/business/
388
- * **Quota**: 2,500 requests/day, 100,000 with Google Maps API Premier
404
+ * **API key**: optional, but quota is higher if key is used (use of key requires HTTPS so be sure to set: `:use_https => true` in `Geocoder.configure`)
405
+ * **Key signup**: https://console.developers.google.com//flows/enableapi?apiid=geocoding_backend&keyType=SERVER_SIDE
406
+ * **Quota**: 2,500 requests/24 hrs, 5 requests/second
389
407
  * **Region**: world
390
- * **SSL support**: yes
391
- * **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)
408
+ * **SSL support**: yes (required if key is used)
409
+ * **Languages**: see https://developers.google.com/maps/faq#languagesupport
392
410
  * **Extra options**: `:bounds` - pass SW and NE coordinates as an array of two arrays to bias results towards a viewport
393
- * **Documentation**: http://code.google.com/apis/maps/documentation/geocoding/#JSON
411
+ * **Documentation**: https://developers.google.com/maps/documentation/geocoding/intro
394
412
  * **Terms of Service**: http://code.google.com/apis/maps/terms.html#section_10_12
395
413
  * **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..."
396
- * **Notes**: To use Google Premier set `Geocoder.configure(:lookup => :google_premier, :api_key => [key, client, channel])`.
414
+
415
+ #### Google Maps API for Work (`:google_premier`)
416
+
417
+ Similar to `:google`, with the following differences:
418
+
419
+ * **API key**: required, plus client and channel (set `Geocoder.configure(:lookup => :google_premier, :api_key => [key, client, channel])`)
420
+ * **Key signup**: https://developers.google.com/maps/documentation/business/
421
+ * **Quota**: 100,000 requests/24 hrs, 10 requests/second
397
422
 
398
423
  #### Google Places Details (`:google_places_details`)
399
424
 
@@ -442,7 +467,7 @@ The [Google Places Details API](https://developers.google.com/places/documentati
442
467
  * **Languages**: ?
443
468
  * **Documentation**: http://wiki.openstreetmap.org/wiki/Nominatim
444
469
  * **Terms of Service**: http://wiki.openstreetmap.org/wiki/Nominatim_usage_policy
445
- * **Limitations**: Please limit request rate to 1 per second and include your contact information in User-Agent headers (eg: `Geocoder.configure(:http_headers => { "User-Agent" => "your contact info" })`). Data licensed under CC-BY-SA (you must provide attribution).
470
+ * **Limitations**: Please limit request rate to 1 per second and include your contact information in User-Agent headers (eg: `Geocoder.configure(:http_headers => { "User-Agent" => "your contact info" })`). [Data licensed under Open Database License (ODbL) (you must provide attribution).](http://www.openstreetmap.org/copyright)
446
471
 
447
472
  #### OpenCageData (`:opencagedata`)
448
473
 
@@ -453,14 +478,14 @@ The [Google Places Details API](https://developers.google.com/places/documentati
453
478
  * **SSL support**: yes
454
479
  * **Languages**: worldwide
455
480
  * **Documentation**: http://geocoder.opencagedata.com/api.html
456
- * **Limitations**: Data licensed under CC-BY-SA or (you must provide attribution).
481
+ * **Limitations**: [Data licensed under Open Database License (ODbL) (you must provide attribution).](http://www.openstreetmap.org/copyright)
457
482
 
458
483
  #### Yandex (`:yandex`)
459
484
 
460
- * **API key**: none
485
+ * **API key**: optional, but without it lookup is territorially limited
461
486
  * **Quota**: 25000 requests / day
462
- * **Region**: world
463
- * **SSL support**: no
487
+ * **Region**: world with API key. Otherwise restricted to Russia, Ukraine, Belarus, Kazakhstan, Georgia, Abkhazia, South Ossetia, Armenia, Azerbaijan, Moldova, Turkmenistan, Tajikistan, Uzbekistan, Kyrgyzstan and Turkey
488
+ * **SSL support**: HTTPS only
464
489
  * **Languages**: Russian, Belarusian, Ukrainian, English, Turkish (only for maps of Turkey)
465
490
  * **Documentation**: http://api.yandex.com.tr/maps/doc/intro/concepts/intro.xml
466
491
  * **Terms of Service**: http://api.yandex.com.tr/maps/doc/intro/concepts/intro.xml#rules
@@ -489,10 +514,24 @@ The [Google Places Details API](https://developers.google.com/places/documentati
489
514
  * **Terms of Service**: http://geocoder.us/terms.shtml
490
515
  * **Limitations**: ?
491
516
 
517
+ #### Mapbox (`:mapbox`)
518
+
519
+ * **API key**: required
520
+ * **Dataset**: Uses `mapbox.places` dataset by default. Specific the `mapbox.places-permanent` dataset by setting: `Geocoder.configure(:mapbox => {:dataset => "mapbox.places-permanent"})`
521
+ * **Key signup**: https://www.mapbox.com/pricing/
522
+ * **Quota**: depends on plan
523
+ * **Region**: complete coverage of US and Canada, partial coverage elsewhere (see for details: https://www.mapbox.com/developers/api/geocoding/#coverage)
524
+ * **SSL support**: yes
525
+ * **Languages**: English
526
+ * **Documentation**: https://www.mapbox.com/developers/api/geocoding/
527
+ * **Terms of Service**: https://www.mapbox.com/tos/
528
+ * **Limitations**: For `mapbox.places` dataset, must be displayed on a Mapbox map; Cache results for up to 30 days. For `mapbox.places-permanent` dataset, depends on plan.
529
+ * **Notes**: Currently in public beta.
530
+
492
531
  #### Mapquest (`:mapquest`)
493
532
 
494
533
  * **API key**: required
495
- * **Key signup**: http://developer.mapquest.com/web/products/open
534
+ * **Key signup**: https://developer.mapquest.com/plans
496
535
  * **Quota**: ?
497
536
  * **HTTP Headers**: when using the licensed API you can specify a referer like so:
498
537
  `Geocoder.configure(:http_headers => { "Referer" => "http://foo.com" })`
@@ -567,13 +606,13 @@ Data Science Toolkit provides an API whose reponse format is like Google's but w
567
606
  #### Geocodio (`:geocodio`)
568
607
 
569
608
  * **API key**: required
570
- * **Quota**: 2,500 free requests/day then purchase $.001 for each
609
+ * **Quota**: 2,500 free requests/day then purchase $.001 for each, also has volume pricing and plans
571
610
  * **Region**: US
572
- * **SSL support**: no
611
+ * **SSL support**: yes
573
612
  * **Languages**: en
574
613
  * **Documentation**: http://geocod.io/docs
575
614
  * **Terms of Service**: http://geocod.io/terms-of-use
576
- * **Limitations**: ?
615
+ * **Limitations**: No restrictions on use
577
616
 
578
617
  #### SmartyStreets (`:smarty_streets`)
579
618
 
@@ -598,6 +637,16 @@ Data Science Toolkit provides an API whose reponse format is like Google's but w
598
637
  * **Terms of Service**: http://www.itella.fi/liitteet/palvelutjatuotteet/yhteystietopalvelut/Postinumeropalvelut-Palvelukuvausjakayttoehdot.pdf
599
638
  * **Limitations**: ?
600
639
 
640
+ #### Geoportail.lu (`:geoportail_lu`)
641
+
642
+ * **API key**: none
643
+ * **Quota**: none
644
+ * **Region**: LU
645
+ * **SSL support**: yes
646
+ * **Languages**: en
647
+ * **Documentation**: http://wiki.geoportail.lu/doku.php?id=en:api
648
+ * **Terms of Service**: http://wiki.geoportail.lu/doku.php?id=en:mcg_1
649
+ * **Limitations**: ?
601
650
 
602
651
  #### PostcodeAnywhere Uk (`:postcode_anywhere_uk`)
603
652
 
@@ -642,14 +691,15 @@ This uses the PostcodeAnywhere UK Geocode service, this will geocode any string
642
691
 
643
692
  #### Telize (`:telize`)
644
693
 
645
- * **API key**: none
646
- * **Quota**: none
694
+ * **API key**: required
695
+ * **Quota**: 1,000/day for $7/mo through 100,000/day for $100/mo
647
696
  * **Region**: world
648
- * **SSL support**: no
697
+ * **SSL support**: yes
649
698
  * **Languages**: English
650
- * **Documentation**: http://www.telize.com/
699
+ * **Documentation**: https://market.mashape.com/fcambus/telize
651
700
  * **Terms of Service**: ?
652
701
  * **Limitations**: ?
702
+ * **Notes**: To use Telize set `Geocoder.configure(:ip_lookup => :telize, :api_key => "your_api_key")`.
653
703
 
654
704
  #### MaxMind Legacy Web Services (`:maxmind`)
655
705
 
@@ -884,6 +934,9 @@ Now, any time Geocoder looks up "New York, NY" its results array will contain on
884
934
  ]
885
935
  )
886
936
 
937
+ Note:
938
+ Keys must be strings not symbols when calling `add_stub` or `set_default_stub`. For example `'latitude' =>` not `:latitude =>`.
939
+
887
940
 
888
941
  Command Line Interface
889
942
  ----------------------
@@ -1059,7 +1112,9 @@ If anyone has a more elegant solution to this problem I am very interested in se
1059
1112
  Contributing
1060
1113
  ------------
1061
1114
 
1062
- Contributions are welcome via pull requests on Github. Please respect the following guidelines:
1115
+ Contributions are welcome via Github pull requests. If you are new to the project and looking for a way to get involved, try picking up an issue with a "beginner-task" label. Hints about what needs to be done are usually provided.
1116
+
1117
+ For all contributions, please respect the following guidelines:
1063
1118
 
1064
1119
  * Each pull request should implement ONE feature or bugfix. If you want to add or fix more than one thing, submit more than one pull request.
1065
1120
  * Do not commit changes to files that are irrelevant to your feature or bugfix (eg: `.gitignore`).
@@ -1068,6 +1123,7 @@ Contributions are welcome via pull requests on Github. Please respect the follow
1068
1123
  * Remember: Geocoder needs to run outside of Rails. Don't assume things like ActiveSupport are available.
1069
1124
  * Be willing to accept criticism and work on improving your code; Geocoder is used by thousands of developers and care must be taken not to introduce bugs.
1070
1125
  * Be aware that the pull request review process is not immediate, and is generally proportional to the size of the pull request.
1126
+ * If your pull request is merged, please do not ask for an immediate release of the gem. There are many factors contributing to when releases occur (remember that they affect thousands of apps with Geocoder in their Gemfiles). If necessary, please install from the Github source until the next official release.
1071
1127
 
1072
1128
 
1073
1129
  Copyright (c) 2009-15 Alex Reisner, released under the MIT license
@@ -1,21 +1,21 @@
1
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
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
12
 
13
- # exceptions that should not be rescued by default
13
+ # Exceptions that should not be rescued by default
14
14
  # (if you want to implement custom error handling);
15
15
  # supports SocketError and TimeoutError
16
- # :always_raise => [],
16
+ # always_raise: [],
17
17
 
18
- # calculation options
19
- # :units => :mi, # :km for kilometers or :mi for miles
20
- # :distances => :linear # :spherical or :linear
18
+ # Calculation options
19
+ # units: :mi, # :km for kilometers or :mi for miles
20
+ # distances: :linear # :spherical or :linear
21
21
  )
@@ -237,11 +237,14 @@ module Geocoder
237
237
  #
238
238
  # * <tt>:units</tt> - <tt>:mi</tt> or <tt>:km</tt>
239
239
  # Use Geocoder.configure(:units => ...) to configure default units.
240
+ # * <tt>:seed</tt> - The seed for the random number generator
240
241
  def random_point_near(center, radius, options = {})
241
242
 
242
243
  # set default options
243
244
  options[:units] ||= Geocoder.config.units
244
245
 
246
+ random = Random.new(options[:seed] || Random.new_seed)
247
+
245
248
  # convert to coordinate arrays
246
249
  center = extract_coordinates(center)
247
250
 
@@ -249,18 +252,18 @@ module Geocoder
249
252
  max_degree_delta = 360.0 * (radius / earth_circumference)
250
253
 
251
254
  # random bearing in radians
252
- theta = 2 * Math::PI * rand
255
+ theta = 2 * Math::PI * random.rand
253
256
 
254
257
  # random radius, use the square root to ensure a uniform
255
258
  # distribution of points over the circle
256
- r = Math.sqrt(rand) * max_degree_delta
259
+ r = Math.sqrt(random.rand) * max_degree_delta
257
260
 
258
261
  delta_lat, delta_long = [r * Math.cos(theta), r * Math.sin(theta)]
259
262
  [center[0] + delta_lat, center[1] + delta_long]
260
263
  end
261
264
 
262
265
  ##
263
- # Given a start point, distance, and heading (in degrees), provides
266
+ # Given a start point, heading (in degrees), and distance, provides
264
267
  # an endpoint.
265
268
  # The starting point is given in the same way that points are given to all
266
269
  # Geocoder methods that accept points as arguments. It can be:
@@ -57,7 +57,8 @@ module Geocoder
57
57
  :units,
58
58
  :distances,
59
59
  :basic_auth,
60
- :logger
60
+ :logger,
61
+ :kernel_logger_level
61
62
  ]
62
63
 
63
64
  attr_accessor :data
@@ -100,6 +101,7 @@ module Geocoder
100
101
  @data[:cache_prefix] = "geocoder:" # prefix (string) to use for all cache keys
101
102
  @data[:basic_auth] = {} # user and password for basic auth ({:user => "user", :password => "password"})
102
103
  @data[:logger] = :kernel # :kernel or Logger instance
104
+ @data[:kernel_logger_level] = ::Logger::WARN # log level, if kernel logger is used
103
105
 
104
106
  # exceptions that should not be rescued by default
105
107
  # (if you want to implement custom error handling);
@@ -123,6 +125,5 @@ module Geocoder
123
125
  end
124
126
  EOS
125
127
  end.join("\n\n"))
126
-
127
128
  end
128
129
  end
@@ -1,3 +1,5 @@
1
+ require 'timeout' # required for Ruby 1.9.3
2
+
1
3
  module Geocoder
2
4
 
3
5
  class Error < StandardError
@@ -29,4 +31,7 @@ module Geocoder
29
31
  class ServiceUnavailable < Error
30
32
  end
31
33
 
34
+ class LookupTimeout < ::Timeout::Error
35
+ end
36
+
32
37
  end
@@ -0,0 +1,25 @@
1
+ module Geocoder
2
+ class KernelLogger
3
+ include Singleton
4
+
5
+ def add(level, message)
6
+ return unless log_message_at_level?(level)
7
+ case level
8
+ when ::Logger::DEBUG, ::Logger::INFO
9
+ puts message
10
+ when ::Logger::WARN
11
+ warn message
12
+ when ::Logger::ERROR
13
+ raise message
14
+ when ::Logger::FATAL
15
+ fail message
16
+ end
17
+ end
18
+
19
+ private # ----------------------------------------------------------------
20
+
21
+ def log_message_at_level?(level)
22
+ level >= Geocoder.config.kernel_logger_level
23
+ end
24
+ end
25
+ end
@@ -18,14 +18,11 @@ module Geocoder
18
18
  }
19
19
 
20
20
  def log(level, message)
21
- return nil unless valid_level?(level)
22
-
23
- logger = Geocoder.config[:logger]
24
-
25
- if logger == :kernel
26
- kernel_log(level, message)
27
- elsif logger.kind_of? ::Logger
28
- logger.add(SEVERITY[level], message)
21
+ unless valid_level?(level)
22
+ raise StandardError, "Geocoder tried to log a message with an invalid log level."
23
+ end
24
+ if current_logger.respond_to? :add
25
+ current_logger.add(SEVERITY[level], message)
29
26
  else
30
27
  raise Geocoder::ConfigurationError, "Please specify valid logger for Geocoder. " +
31
28
  "Logger specified must be :kernel or must respond to `add(level, message)`."
@@ -33,23 +30,18 @@ module Geocoder
33
30
  nil
34
31
  end
35
32
 
36
- private
37
-
38
- def kernel_log(level, message)
39
- case level
40
- when :debug, :info
41
- puts message
42
- when :warn
43
- warn message
44
- when :error
45
- raise message
46
- when :fatal
47
- fail message
33
+ private # ----------------------------------------------------------------
34
+
35
+ def current_logger
36
+ logger = Geocoder.config[:logger]
37
+ if logger == :kernel
38
+ logger = Geocoder::KernelLogger.instance
48
39
  end
40
+ logger
49
41
  end
50
42
 
51
43
  def valid_level?(level)
52
- [:debug, :info, :warn, :error, :fatal].include? level
44
+ SEVERITY.keys.include?(level)
53
45
  end
54
46
  end
55
47
  end
@@ -1,3 +1,5 @@
1
+ require "geocoder/lookups/test"
2
+
1
3
  module Geocoder
2
4
  module Lookup
3
5
  extend self
@@ -32,6 +34,7 @@ module Geocoder
32
34
  :geocoder_us,
33
35
  :yandex,
34
36
  :nominatim,
37
+ :mapbox,
35
38
  :mapquest,
36
39
  :opencagedata,
37
40
  :ovi,
@@ -41,6 +44,7 @@ module Geocoder
41
44
  :smarty_streets,
42
45
  :okf,
43
46
  :postcode_anywhere_uk,
47
+ :geoportail_lu,
44
48
  :test
45
49
  ]
46
50
  end
@@ -82,6 +86,8 @@ module Geocoder
82
86
  #
83
87
  def spawn(name)
84
88
  if all_services.include?(name)
89
+ name = name.to_s
90
+ require "geocoder/lookups/#{name}"
85
91
  Geocoder::Lookup.const_get(classify_name(name)).new
86
92
  else
87
93
  valids = all_services.map(&:inspect).join(", ")
@@ -98,7 +104,3 @@ module Geocoder
98
104
  end
99
105
  end
100
106
  end
101
-
102
- Geocoder::Lookup.all_services.each do |name|
103
- require "geocoder/lookups/#{name}"
104
- end
@@ -13,7 +13,7 @@ module Geocoder::Lookup
13
13
  end
14
14
 
15
15
  def query_url(query)
16
- "http://api.map.baidu.com/geocoder/v2/?" + url_query_string(query)
16
+ "#{protocol}://api.map.baidu.com/geocoder/v2/?" + url_query_string(query)
17
17
  end
18
18
 
19
19
  # HTTP only
@@ -13,7 +13,7 @@ module Geocoder::Lookup
13
13
  end
14
14
 
15
15
  def query_url(query)
16
- "http://api.map.baidu.com/location/ip?" + url_query_string(query)
16
+ "#{protocol}://api.map.baidu.com/location/ip?" + url_query_string(query)
17
17
  end
18
18
 
19
19
  # HTTP only
@@ -190,7 +190,7 @@ module Geocoder
190
190
  else
191
191
  JSON.parse(data)
192
192
  end
193
- rescue => err
193
+ rescue
194
194
  raise_error(ResponseParseError.new(data)) or Geocoder.log(:warn, "Geocoding API's response was not valid JSON: #{data}")
195
195
  end
196
196
 
@@ -271,20 +271,20 @@ module Geocoder
271
271
  # return the response object.
272
272
  #
273
273
  def make_api_request(query)
274
- timeout(configuration.timeout) do
275
- uri = URI.parse(query_url(query))
276
- Geocoder.log(:debug, "Geocoder: HTTP request being made for #{uri.to_s}")
277
- http_client.start(uri.host, uri.port, use_ssl: use_ssl?) do |client|
278
- req = Net::HTTP::Get.new(uri.request_uri, configuration.http_headers)
279
- if configuration.basic_auth[:user] and configuration.basic_auth[:password]
280
- req.basic_auth(
281
- configuration.basic_auth[:user],
282
- configuration.basic_auth[:password]
283
- )
284
- end
285
- client.request(req)
274
+ uri = URI.parse(query_url(query))
275
+ Geocoder.log(:debug, "Geocoder: HTTP request being made for #{uri.to_s}")
276
+ http_client.start(uri.host, uri.port, use_ssl: use_ssl?, open_timeout: configuration.timeout, read_timeout: configuration.timeout) do |client|
277
+ req = Net::HTTP::Get.new(uri.request_uri, configuration.http_headers)
278
+ if configuration.basic_auth[:user] and configuration.basic_auth[:password]
279
+ req.basic_auth(
280
+ configuration.basic_auth[:user],
281
+ configuration.basic_auth[:password]
282
+ )
286
283
  end
284
+ client.request(req)
287
285
  end
286
+ rescue Timeout::Error
287
+ raise Geocoder::LookupTimeout
288
288
  end
289
289
 
290
290
  def use_ssl?
@@ -8,11 +8,15 @@ module Geocoder::Lookup
8
8
  "Geocoder.us"
9
9
  end
10
10
 
11
+ def supported_protocols
12
+ [:http]
13
+ end
14
+
11
15
  def query_url(query)
12
16
  if configuration.api_key
13
- "http://#{configuration.api_key}@geocoder.us/member/service/csv/geocode?" + url_query_string(query)
17
+ "#{protocol}://#{configuration.api_key}@geocoder.us/member/service/csv/geocode?" + url_query_string(query)
14
18
  else
15
- "http://geocoder.us/service/csv/geocode?" + url_query_string(query)
19
+ "#{protocol}://geocoder.us/service/csv/geocode?" + url_query_string(query)
16
20
  end
17
21
  end
18
22
 
@@ -4,6 +4,8 @@ require 'geocoder/results/geoip2'
4
4
  module Geocoder
5
5
  module Lookup
6
6
  class Geoip2 < Base
7
+ attr_reader :gem_name
8
+
7
9
  def initialize
8
10
  unless configuration[:file].nil?
9
11
  begin
@@ -12,6 +14,8 @@ module Geocoder
12
14
  rescue LoadError
13
15
  raise "Could not load Maxmind DB dependency. To use the GeoIP2 lookup you must add the #{@gem_name} gem to your Gemfile or have it installed in your system."
14
16
  end
17
+
18
+ @mmdb = db_class.new(configuration[:file].to_s)
15
19
  end
16
20
  super
17
21
  end
@@ -26,13 +30,14 @@ module Geocoder
26
30
 
27
31
  private
28
32
 
33
+ def db_class
34
+ gem_name == 'hive_geoip2' ? Hive::GeoIP2 : MaxMindDB
35
+ end
36
+
29
37
  def results(query)
30
38
  return [] unless configuration[:file]
31
- if @gem_name == 'hive_geoip2'
32
- result = Hive::GeoIP2.lookup(query.to_s, configuration[:file].to_s)
33
- else
34
- result = MaxMindDB.new(configuration[:file].to_s).lookup(query.to_s)
35
- end
39
+
40
+ result = @mmdb.lookup(query.to_s)
36
41
  result.nil? ? [] : [result]
37
42
  end
38
43
  end