geocoder 1.2.5 → 1.2.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of geocoder might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +83 -8
- data/lib/geocoder/ip_address.rb +11 -2
- data/lib/geocoder/lookup.rb +4 -0
- data/lib/geocoder/lookups/geoip2.rb +40 -0
- data/lib/geocoder/lookups/google_places_details.rb +50 -0
- data/lib/geocoder/lookups/maxmind_local.rb +1 -1
- data/lib/geocoder/lookups/okf.rb +43 -0
- data/lib/geocoder/lookups/postcode_anywhere_uk.rb +51 -0
- data/lib/geocoder/lookups/smarty_streets.rb +1 -1
- data/lib/geocoder/results/geoip2.rb +64 -0
- data/lib/geocoder/results/google_places_details.rb +35 -0
- data/lib/geocoder/results/okf.rb +106 -0
- data/lib/geocoder/results/postcode_anywhere_uk.rb +42 -0
- data/lib/geocoder/results/test.rb +1 -1
- data/lib/geocoder/stores/active_record.rb +22 -11
- data/lib/geocoder/version.rb +1 -1
- data/test/fixtures/google_places_details_invalid_request +4 -0
- data/test/fixtures/google_places_details_madison_square_garden +120 -0
- data/test/fixtures/google_places_details_no_results +4 -0
- data/test/fixtures/google_places_details_no_reviews +60 -0
- data/test/fixtures/google_places_details_no_types +66 -0
- data/test/fixtures/okf_kirstinmaki +67 -0
- data/test/fixtures/okf_no_results +4 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_WR26NJ +1 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_generic_error +1 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_hampshire +1 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_key_limit_exceeded +1 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_no_results +1 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_romsey +1 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_unknown_key +1 -0
- data/test/test_helper.rb +44 -0
- data/test/unit/cache_test.rb +1 -1
- data/test/unit/error_handling_test.rb +3 -3
- data/test/unit/ip_address_test.rb +3 -0
- data/test/unit/lookup_test.rb +1 -1
- data/test/unit/lookups/geoip2_test.rb +27 -0
- data/test/unit/lookups/google_places_details_test.rb +122 -0
- data/test/unit/lookups/okf_test.rb +38 -0
- data/test/unit/lookups/postcode_anywhere_uk_test.rb +70 -0
- data/test/unit/query_test.rb +1 -0
- data/test/unit/test_mode_test.rb +1 -1
- metadata +28 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27a73d81025d3d5faa23e10ae7db3c1d25e9825e
|
4
|
+
data.tar.gz: 740a6672d7cbfd97dc9c1e22a84473007674d4c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ae067878ed711962248b7a63bd8e322f3f0529cef013eb667f96b2c7b51b1f2a59c0ec9437fc79fb6a7338dc569c834abae6c903cf28339562ce6a4ff8db7f6
|
7
|
+
data.tar.gz: 44af9419d97670067cfde24878a7b893d2f0fa6b784102277089f53c9b43d796cf90a755c261851d23b268b902f48a2217147fdff935719d3574cf4b5915ea38
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,13 @@ 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.2.6 (2014 Nov 8)
|
7
|
+
-------------------
|
8
|
+
* Add :geoip2 lookup (thanks github.com/ChristianHoj).
|
9
|
+
* Add :okf lookup (thanks github.com/kakoni).
|
10
|
+
* Add :postcode_anywhere_uk lookup (thanks github.com/rob-murray).
|
11
|
+
* Properly detect IPv6 addresses (thanks github.com/sethherr and github.com/ignatiusreza).
|
12
|
+
|
6
13
|
1.2.5 (2014 Sep 12)
|
7
14
|
-------------------
|
8
15
|
* Fix bugs in :opencagedata lookup (thanks github.com/duboff and kayakyakr).
|
data/README.md
CHANGED
@@ -384,7 +384,7 @@ The following is a comparison of the supported geocoding APIs. The "Limitations"
|
|
384
384
|
|
385
385
|
#### Google (`:google`, `:google_premier`)
|
386
386
|
|
387
|
-
* **API key**: required for Premier
|
387
|
+
* **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`)
|
388
388
|
* **Key signup**: https://developers.google.com/maps/documentation/business/
|
389
389
|
* **Quota**: 2,500 requests/day, 100,000 with Google Maps API Premier
|
390
390
|
* **Region**: world
|
@@ -396,6 +396,20 @@ The following is a comparison of the supported geocoding APIs. The "Limitations"
|
|
396
396
|
* **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..."
|
397
397
|
* **Notes**: To use Google Premier set `Geocoder.configure(:lookup => :google_premier, :api_key => [key, client, channel])`.
|
398
398
|
|
399
|
+
#### Google Places Details (`:google_places_details`)
|
400
|
+
|
401
|
+
The [Google Places Details API](https://developers.google.com/places/documentation/details) is not, strictly speaking, a geocoding service. It accepts a Google `place_id` and returns address information, ratings and reviews. A `place_id` can be obtained from the Google Places Autocomplete API and should be passed to Geocoder as the first search argument: `Geocoder.search("ChIJhRwB-yFawokR5Phil-QQ3zM", :lookup => :google_places_details)`.
|
402
|
+
|
403
|
+
* **API key**: required
|
404
|
+
* **Key signup**: https://code.google.com/apis/console/
|
405
|
+
* **Quota**: 1,000 request/day, 100,000 after credit card authentication
|
406
|
+
* **Region**: world
|
407
|
+
* **SSL support**: yes
|
408
|
+
* **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)
|
409
|
+
* **Documentation**: https://developers.google.com/places/documentation/details
|
410
|
+
* **Terms of Service**: https://developers.google.com/places/policies
|
411
|
+
* **Limitations**: "If your application displays Places API data on a page or view that does not also display a Google Map, you must show a "Powered by Google" logo with that data."
|
412
|
+
|
399
413
|
#### Yahoo BOSS (`:yahoo`)
|
400
414
|
|
401
415
|
* **API key**: requires OAuth consumer key and secret (set `Geocoder.configure(:api_key => [key, secret])`)
|
@@ -410,7 +424,7 @@ The following is a comparison of the supported geocoding APIs. The "Limitations"
|
|
410
424
|
|
411
425
|
#### Bing (`:bing`)
|
412
426
|
|
413
|
-
* **API key**: required
|
427
|
+
* **API key**: required (set `Geocoder.configure(:lookup => :bing, :api_key => key)`)
|
414
428
|
* **Key signup**: http://www.bingmapsportal.com
|
415
429
|
* **Quota**: 50,000 requests/24 hrs
|
416
430
|
* **Region**: world
|
@@ -565,7 +579,7 @@ Data Science Toolkit provides an API whose reponse format is like Google's but w
|
|
565
579
|
|
566
580
|
#### SmartyStreets (`:smarty_streets`)
|
567
581
|
|
568
|
-
* **API key**:
|
582
|
+
* **API key**: requires auth_id and auth_token (set `Geocoder.configure(:api_key => [id, token])`)
|
569
583
|
* **Quota**: 10,000 free, 250/month then purchase at sliding scale.
|
570
584
|
* **Region**: US
|
571
585
|
* **SSL support**: yes
|
@@ -574,6 +588,34 @@ Data Science Toolkit provides an API whose reponse format is like Google's but w
|
|
574
588
|
* **Terms of Service**: http://smartystreets.com/legal/terms-of-service
|
575
589
|
* **Limitations**: No reverse geocoding.
|
576
590
|
|
591
|
+
|
592
|
+
#### OKF Geocoder (`:okf`)
|
593
|
+
|
594
|
+
* **API key**: none
|
595
|
+
* **Quota**: none
|
596
|
+
* **Region**: FI
|
597
|
+
* **SSL support**: no
|
598
|
+
* **Languages**: fi
|
599
|
+
* **Documentation**: http://books.okf.fi/geocoder/_full/
|
600
|
+
* **Terms of Service**: http://www.itella.fi/liitteet/palvelutjatuotteet/yhteystietopalvelut/Postinumeropalvelut-Palvelukuvausjakayttoehdot.pdf
|
601
|
+
* **Limitations**: ?
|
602
|
+
|
603
|
+
|
604
|
+
#### PostcodeAnywhere Uk (`:postcode_anywhere_uk`)
|
605
|
+
|
606
|
+
This uses the PostcodeAnywhere UK Geocode service, this will geocode any string from UK postcode, placename, point of interest or location.
|
607
|
+
|
608
|
+
* **API key**: required
|
609
|
+
* **Quota**: Dependant on service plan?
|
610
|
+
* **Region**: UK
|
611
|
+
* **SSL support**: yes
|
612
|
+
* **Languages**: English
|
613
|
+
* **Documentation**: [http://www.postcodeanywhere.co.uk/Support/WebService/Geocoding/UK/Geocode/2/](http://www.postcodeanywhere.co.uk/Support/WebService/Geocoding/UK/Geocode/2/)
|
614
|
+
* **Terms of Service**: ?
|
615
|
+
* **Limitations**: ?
|
616
|
+
* **Notes**: To use PostcodeAnywhere you must include an API key: `Geocoder.configure(:lookup => :postcode_anywhere_uk, :api_key => 'your_api_key')`.
|
617
|
+
|
618
|
+
|
577
619
|
### IP Address Services
|
578
620
|
|
579
621
|
#### FreeGeoIP (`:freegeoip`)
|
@@ -647,12 +689,11 @@ This lookup provides methods for geocoding IP addresses without making a call to
|
|
647
689
|
|
648
690
|
You can generate ActiveRecord migrations and download and import data via provided rake tasks:
|
649
691
|
|
692
|
+
# generate migration to create tables
|
650
693
|
rails generate geocoder:maxmind:geolite PACKAGE=city
|
651
694
|
|
652
|
-
|
653
|
-
rake geocoder:maxmind:geolite:
|
654
|
-
rake geocoder:maxmind:geolite:insert PACKAGE=city
|
655
|
-
rake geocoder:maxmind:geolite:load PACKAGE=city # runs the above three in sequence
|
695
|
+
# download, unpack, and import data
|
696
|
+
rake geocoder:maxmind:geolite:load PACKAGE=city
|
656
697
|
|
657
698
|
You can replace `city` with `country` in any of the above tasks, generators, and configurations.
|
658
699
|
|
@@ -668,6 +709,36 @@ You can replace `city` with `country` in any of the above tasks, generators, and
|
|
668
709
|
* **Limitations**: Only good for non-commercial use. For commercial usage please check http://developer.baidu.com/map/question.htm#qa0013
|
669
710
|
* **Notes**: To use Baidu set `Geocoder.configure(:lookup => :baidu_ip, :api_key => "your_api_key")`.
|
670
711
|
|
712
|
+
#### GeoLite2 (`:geoip2`)
|
713
|
+
|
714
|
+
This lookup provides methods for geocoding IP addresses without making a call to a remote API (improves speed and availability). It works, but support is new and should not be considered production-ready. Please [report any bugs](https://github.com/alexreisner/geocoder/issues) you encounter.
|
715
|
+
|
716
|
+
* **API key**: none (requires a GeoIP2 or free GeoLite2 City or Country binary database which can be downloaded from [MaxMind](http://dev.maxmind.com/geoip/geoip2/geoip2/))
|
717
|
+
* **Quota**: none
|
718
|
+
* **Region**: world
|
719
|
+
* **SSL support**: N/A
|
720
|
+
* **Languages**: English
|
721
|
+
* **Documentation**: http://www.maxmind.com/en/city
|
722
|
+
* **Terms of Service**: ?
|
723
|
+
* **Limitations**: ?
|
724
|
+
* **Notes**: **You must download a binary database file from MaxMind and set the `:file` configuration option.** The CSV format databases are not yet supported since they are still in alpha stage. Set the path to the database file in your configuration:
|
725
|
+
|
726
|
+
Geocoder.configure(
|
727
|
+
ip_lookup: :geoip2,
|
728
|
+
geoip2: {
|
729
|
+
file: File.join('folder', 'GeoLite2-City.mmdb')
|
730
|
+
}
|
731
|
+
)
|
732
|
+
|
733
|
+
You must add either the *[hive_geoip2](https://rubygems.org/gems/hive_geoip2)* gem (native extension that relies on libmaxminddb) or the *[maxminddb](http://rubygems.org/gems/maxminddb)* gem (pure Ruby implementation) to your Gemfile or have it installed in your system. The pure Ruby gem (maxminddb) will be used by default. To use `hive_geoip2`:
|
734
|
+
|
735
|
+
Geocoder.configure(
|
736
|
+
ip_lookup: :geoip2,
|
737
|
+
geoip2: {
|
738
|
+
lib: 'hive_geoip2',
|
739
|
+
file: File.join('folder', 'GeoLite2-City.mmdb')
|
740
|
+
}
|
741
|
+
)
|
671
742
|
|
672
743
|
Caching
|
673
744
|
-------
|
@@ -947,12 +1018,16 @@ A lot of debugging time can be saved by understanding how Geocoder works with Ac
|
|
947
1018
|
|
948
1019
|
### Unexpected Responses from Geocoding Services
|
949
1020
|
|
950
|
-
Take a look at the server's raw
|
1021
|
+
Take a look at the server's raw response. You can do this by getting the request URL in an app console:
|
951
1022
|
|
952
1023
|
Geocoder::Lookup.get(:google).query_url(Geocoder::Query.new("..."))
|
953
1024
|
|
954
1025
|
Replace `:google` with the lookup you are using and replace `...` with the address you are trying to geocode. Then visit the returned URL in your web browser. Often the API will return an error message that helps you resolve the problem. If, after reading the raw response, you believe there is a problem with Geocoder, please post an issue and include both the URL and raw response body.
|
955
1026
|
|
1027
|
+
You can also fetch the response in the console:
|
1028
|
+
|
1029
|
+
Geocoder::Lookup.get(:google).send(:fetch_raw_data, Geocoder::Query.new("..."))
|
1030
|
+
|
956
1031
|
|
957
1032
|
Reporting Issues
|
958
1033
|
----------------
|
data/lib/geocoder/ip_address.rb
CHANGED
@@ -2,11 +2,20 @@ module Geocoder
|
|
2
2
|
class IpAddress < String
|
3
3
|
|
4
4
|
def loopback?
|
5
|
-
valid? and (self == "0.0.0.0" or self.match(/\A127\./))
|
5
|
+
valid? and (self == "0.0.0.0" or self.match(/\A127\./) or self == "::1")
|
6
6
|
end
|
7
7
|
|
8
8
|
def valid?
|
9
|
-
|
9
|
+
ipregex = %r{
|
10
|
+
\A( # String Starts
|
11
|
+
((::ffff:)?((\d{1,3})\.){3}\d{1,3}) # Check for IPv4
|
12
|
+
| # .... Or
|
13
|
+
(\S+?(:\S+?){6}\S+) # Check for IPv6
|
14
|
+
| # .... Or
|
15
|
+
(::1) # IPv6 loopback
|
16
|
+
)\z
|
17
|
+
}x
|
18
|
+
!!self.match(ipregex)
|
10
19
|
end
|
11
20
|
end
|
12
21
|
end
|
data/lib/geocoder/lookup.rb
CHANGED
@@ -25,6 +25,7 @@ module Geocoder
|
|
25
25
|
:esri,
|
26
26
|
:google,
|
27
27
|
:google_premier,
|
28
|
+
:google_places_details,
|
28
29
|
:yahoo,
|
29
30
|
:bing,
|
30
31
|
:geocoder_ca,
|
@@ -38,6 +39,8 @@ module Geocoder
|
|
38
39
|
:baidu,
|
39
40
|
:geocodio,
|
40
41
|
:smarty_streets,
|
42
|
+
:okf,
|
43
|
+
:postcode_anywhere_uk,
|
41
44
|
:test
|
42
45
|
]
|
43
46
|
end
|
@@ -49,6 +52,7 @@ module Geocoder
|
|
49
52
|
[
|
50
53
|
:baidu_ip,
|
51
54
|
:freegeoip,
|
55
|
+
:geoip2,
|
52
56
|
:maxmind,
|
53
57
|
:maxmind_local,
|
54
58
|
:telize,
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/geoip2'
|
3
|
+
|
4
|
+
module Geocoder
|
5
|
+
module Lookup
|
6
|
+
class Geoip2 < Base
|
7
|
+
def initialize
|
8
|
+
unless configuration[:file].nil?
|
9
|
+
begin
|
10
|
+
@gem_name = configuration[:lib] || 'maxminddb'
|
11
|
+
require @gem_name
|
12
|
+
rescue LoadError
|
13
|
+
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
|
+
end
|
15
|
+
end
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
'GeoIP2'
|
21
|
+
end
|
22
|
+
|
23
|
+
def required_api_key_parts
|
24
|
+
[]
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def results(query)
|
30
|
+
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
|
36
|
+
result.nil? ? [] : [result]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "geocoder/lookups/google"
|
2
|
+
require "geocoder/results/google_places_details"
|
3
|
+
|
4
|
+
module Geocoder
|
5
|
+
module Lookup
|
6
|
+
class GooglePlacesDetails < Google
|
7
|
+
def name
|
8
|
+
"Google Places Details"
|
9
|
+
end
|
10
|
+
|
11
|
+
def required_api_key_parts
|
12
|
+
["key"]
|
13
|
+
end
|
14
|
+
|
15
|
+
def use_ssl?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def query_url(query)
|
20
|
+
"#{protocol}://maps.googleapis.com/maps/api/place/details/json?#{url_query_string(query)}"
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def results(query)
|
26
|
+
return [] unless doc = fetch_data(query)
|
27
|
+
|
28
|
+
case doc["status"]
|
29
|
+
when "OK"
|
30
|
+
return [doc["result"]]
|
31
|
+
when "OVER_QUERY_LIMIT"
|
32
|
+
raise_error(Geocoder::OverQueryLimitError) || warn("Google Places Details API error: over query limit.")
|
33
|
+
when "REQUEST_DENIED"
|
34
|
+
raise_error(Geocoder::RequestDenied) || warn("Google Places Details API error: request denied.")
|
35
|
+
when "INVALID_REQUEST"
|
36
|
+
raise_error(Geocoder::InvalidRequest) || warn("Google Places Details API error: invalid request.")
|
37
|
+
end
|
38
|
+
|
39
|
+
[]
|
40
|
+
end
|
41
|
+
|
42
|
+
def query_url_google_params(query)
|
43
|
+
{
|
44
|
+
placeid: query.text,
|
45
|
+
language: query.language || configuration.language
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -36,7 +36,7 @@ module Geocoder::Lookup
|
|
36
36
|
addr = IPAddr.new(query.text).to_i
|
37
37
|
q = "SELECT l.country, l.region, l.city, l.latitude, l.longitude
|
38
38
|
FROM maxmind_geolite_city_location l WHERE l.loc_id = (SELECT b.loc_id FROM maxmind_geolite_city_blocks b
|
39
|
-
WHERE b.start_ip_num <= #{addr} AND #{addr} <= b.end_ip_num)"
|
39
|
+
WHERE b.start_ip_num <= #{addr} AND #{addr} <= b.end_ip_num LIMIT 1)"
|
40
40
|
format_result(q, [:country_name, :region_name, :city_name, :latitude, :longitude])
|
41
41
|
elsif configuration[:package] == :country
|
42
42
|
addr = IPAddr.new(query.text).to_i
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require "geocoder/results/okf"
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class Okf < Base
|
6
|
+
|
7
|
+
def name
|
8
|
+
"Okf"
|
9
|
+
end
|
10
|
+
|
11
|
+
def query_url(query)
|
12
|
+
"#{protocol}://data.okf.fi/gis/1/geocode/json?" + url_query_string(query)
|
13
|
+
end
|
14
|
+
|
15
|
+
private # ---------------------------------------------------------------
|
16
|
+
|
17
|
+
def valid_response?(response)
|
18
|
+
status = parse_json(response.body)["status"]
|
19
|
+
super(response) and ['OK', 'ZERO_RESULTS'].include?(status)
|
20
|
+
end
|
21
|
+
|
22
|
+
def results(query)
|
23
|
+
return [] unless doc = fetch_data(query)
|
24
|
+
case doc['status']; when "OK" # OK status implies >0 results
|
25
|
+
return doc['results']
|
26
|
+
end
|
27
|
+
return []
|
28
|
+
end
|
29
|
+
|
30
|
+
def query_url_okf_params(query)
|
31
|
+
params = {
|
32
|
+
(query.reverse_geocode? ? :latlng : :address) => query.sanitized_text,
|
33
|
+
:sensor => "false",
|
34
|
+
:language => (query.language || configuration.language)
|
35
|
+
}
|
36
|
+
params
|
37
|
+
end
|
38
|
+
|
39
|
+
def query_url_params(query)
|
40
|
+
query_url_okf_params(query).merge(super)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/postcode_anywhere_uk'
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class PostcodeAnywhereUk < Base
|
6
|
+
# API documentation: http://www.postcodeanywhere.co.uk/Support/WebService/Geocoding/UK/Geocode/2/
|
7
|
+
BASE_URL_GEOCODE_V2_00 = 'services.postcodeanywhere.co.uk/Geocoding/UK/Geocode/v2.00/json.ws'
|
8
|
+
DAILY_LIMIT_EXEEDED_ERROR_CODES = ['8', '17'] # api docs say these two codes are the same error
|
9
|
+
INVALID_API_KEY_ERROR_CODE = '2'
|
10
|
+
|
11
|
+
def name
|
12
|
+
'PostcodeAnywhereUk'
|
13
|
+
end
|
14
|
+
|
15
|
+
def required_api_key_parts
|
16
|
+
%w(key)
|
17
|
+
end
|
18
|
+
|
19
|
+
def query_url(query)
|
20
|
+
format('%s://%s?%s', protocol, BASE_URL_GEOCODE_V2_00, url_query_string(query))
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def results(query)
|
26
|
+
response = fetch_data(query)
|
27
|
+
return [] if response.nil? || !response.is_a?(Array) || response.empty?
|
28
|
+
|
29
|
+
raise_exception_for_response(response[0]) if response[0]['Error']
|
30
|
+
response
|
31
|
+
end
|
32
|
+
|
33
|
+
def raise_exception_for_response(response)
|
34
|
+
case response['Error']
|
35
|
+
when *DAILY_LIMIT_EXEEDED_ERROR_CODES
|
36
|
+
raise_error(Geocoder::OverQueryLimitError, response['Cause']) || warn(response['Cause'])
|
37
|
+
when INVALID_API_KEY_ERROR_CODE
|
38
|
+
raise_error(Geocoder::InvalidApiKey, response['Cause']) || warn(response['Cause'])
|
39
|
+
else # anything else just raise general error with the api cause
|
40
|
+
raise_error(Geocoder::Error, response['Cause']) || warn(response['Cause'])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def query_url_params(query)
|
45
|
+
{
|
46
|
+
:location => query.sanitized_text,
|
47
|
+
:key => configuration.api_key
|
48
|
+
}.merge(super)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'geocoder/results/base'
|
2
|
+
|
3
|
+
module Geocoder
|
4
|
+
module Result
|
5
|
+
class Geoip2 < Base
|
6
|
+
def address(format = :full)
|
7
|
+
s = state.to_s == '' ? '' : ", #{state_code}"
|
8
|
+
"#{city}#{s} #{postal_code}, #{country}".sub(/^[ ,]*/, '')
|
9
|
+
end
|
10
|
+
|
11
|
+
def coordinates
|
12
|
+
[latitude, longitude]
|
13
|
+
end
|
14
|
+
|
15
|
+
def latitude
|
16
|
+
return 0.0 unless @data['location']
|
17
|
+
@data['location']['latitude'].to_f
|
18
|
+
end
|
19
|
+
|
20
|
+
def longitude
|
21
|
+
return 0.0 unless @data['location']
|
22
|
+
@data['location']['longitude'].to_f
|
23
|
+
end
|
24
|
+
|
25
|
+
def city
|
26
|
+
return '' unless @data['city']
|
27
|
+
@data['city']['names']['en']
|
28
|
+
end
|
29
|
+
|
30
|
+
def state
|
31
|
+
return '' unless @data['subdivisions']
|
32
|
+
@data['subdivisions'][0]['names']['en']
|
33
|
+
end
|
34
|
+
|
35
|
+
def state_code
|
36
|
+
return '' unless @data['subdivisions']
|
37
|
+
@data['subdivisions'][0]['iso_code']
|
38
|
+
end
|
39
|
+
|
40
|
+
def country
|
41
|
+
@data['country']['names']['en']
|
42
|
+
end
|
43
|
+
|
44
|
+
def country_code
|
45
|
+
@data['country']['iso_code']
|
46
|
+
end
|
47
|
+
|
48
|
+
def postal_code
|
49
|
+
return '' unless @data['postal']
|
50
|
+
@data['postal']['code']
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.response_attributes
|
54
|
+
%w[ip]
|
55
|
+
end
|
56
|
+
|
57
|
+
response_attributes.each do |a|
|
58
|
+
define_method a do
|
59
|
+
@data[a]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|