diff --git a/README.md b/README.md index e3d99c46532c5eb9108e4787d7a05a97dbde36ae..e749b272b9a945e28ada3a37cf1127522e80e992 100644 --- a/README.md +++ b/README.md @@ -584,6 +584,18 @@ Data Science Toolkit provides an API whose reponse format is like Google's but w * **Limitations**: ? * **Notes**: If you are [running your own local instance of the FreeGeoIP service](https://github.com/fiorix/freegeoip) you can configure the host like this: `Geocoder.configure(freegeoip: {host: "..."})`. +#### Pointpin (`:pointpin`) + +* **API key**: required +* **Quota**: 50,000/mo for €9 through 1m/mo for €49 +* **Region**: world +* **SSL support**: yes +* **Languages**: English +* **Documentation**: https://pointp.in/docs/get-started +* **Terms of Service**: https://pointp.in/terms +* **Limitations**: ? +* **Notes**: To use Pointpin set `Geocoder.configure(:ip_lookup => :pointpin, :api_key => "your_pointpin_api_key")`. + #### Telize (`:telize`) * **API key**: none diff --git a/lib/geocoder/lookup.rb b/lib/geocoder/lookup.rb index dbfa651959a1ee1a0c2a7098a746469df85df11d..9d380e3f3b76a2c9c7d887ecfda76172288fd413 100644 --- a/lib/geocoder/lookup.rb +++ b/lib/geocoder/lookup.rb @@ -51,7 +51,8 @@ module Geocoder :freegeoip, :maxmind, :maxmind_local, - :telize + :telize, + :pointpin ] end diff --git a/lib/geocoder/lookups/pointpin.rb b/lib/geocoder/lookups/pointpin.rb new file mode 100644 index 0000000000000000000000000000000000000000..6bb8bf8388082d9b6360f7bc994888cb5cfe251a --- /dev/null +++ b/lib/geocoder/lookups/pointpin.rb @@ -0,0 +1,68 @@ +require 'geocoder/lookups/base' +require 'geocoder/results/pointpin' + +module Geocoder::Lookup + class Pointpin < Base + + def name + "Pointpin" + end + + def required_api_key_parts + ["key"] + end + + def query_url(query) + "#{ protocol }://geo.pointp.in/#{ api_key }/json/#{ query.sanitized_text }" + end + + private + + def results(query) + # don't look up a loopback address, just return the stored result + return [] if query.loopback_ip_address? + doc = fetch_data(query) + if doc and doc.is_a?(Hash) + if !data_contains_error?(doc) + return [doc] + elsif doc['error'] + case doc['error'] + when "Invalid IP address" + raise_error(Geocoder::InvalidRequest) || warn("Invalid Pointpin request.") + when "Invalid API key" + raise_error(Geocoder::InvalidApiKey) || warn("Invalid Pointpin API key.") + when "Address not found" + warn("Address not found.") + end + else + raise_error(Geocoder::Error) || warn("Pointpin server error") + end + end + + return [] + end + + def data_contains_error?(parsed_data) + parsed_data.keys.include?('error') + end + + def reserved_result(ip) + { + "ip" => ip, + "city" => "", + "region_code" => "", + "region_name" => "", + "metrocode" => "", + "zipcode" => "", + "latitude" => "0", + "longitude" => "0", + "country_name" => "Reserved", + "country_code" => "RD" + } + end + + def api_key + configuration.api_key + end + end +end diff --git a/lib/geocoder/results/pointpin.rb b/lib/geocoder/results/pointpin.rb new file mode 100644 index 0000000000000000000000000000000000000000..f6a99d0fe9b5b58a26259250d3551c3d6d9334ea --- /dev/null +++ b/lib/geocoder/results/pointpin.rb @@ -0,0 +1,44 @@ +require 'geocoder/results/base' + +module Geocoder::Result + class Pointpin < Base + + def address + [ city_name, state, postal_code, country ].select{ |i| i.to_s != "" }.join(", ") + end + + def city + @data['city_name'] + end + + def state + @data['region_name'] + end + + def state_code + @data['region_code'] + end + + def country + @data['country_name'] + end + + def country_code + @data['country_code'] + end + + def postal_code + @data['postcode'] + end + + def self.response_attributes + %w[continent_code ip country_code country_name region_name city_name postcode latitude longitude time_zone languages] + end + + response_attributes.each do |a| + define_method a do + @data[a] + end + end + end +end diff --git a/test/fixtures/pointpin_10_10_10_10 b/test/fixtures/pointpin_10_10_10_10 new file mode 100644 index 0000000000000000000000000000000000000000..2ddd88488ffe920434ca800d546d2748bc965945 --- /dev/null +++ b/test/fixtures/pointpin_10_10_10_10 @@ -0,0 +1 @@ +{"error":"Address not found"} \ No newline at end of file diff --git a/test/fixtures/pointpin_555_555_555_555 b/test/fixtures/pointpin_555_555_555_555 new file mode 100644 index 0000000000000000000000000000000000000000..859aa415bc987e1517f49c68bbd1dd100da02c57 --- /dev/null +++ b/test/fixtures/pointpin_555_555_555_555 @@ -0,0 +1 @@ +{"error":"Invalid IP address"} \ No newline at end of file diff --git a/test/fixtures/pointpin_80_111_555_555 b/test/fixtures/pointpin_80_111_555_555 new file mode 100644 index 0000000000000000000000000000000000000000..2ec552dce6e0dd0f5f60778b7870d03c820331e8 --- /dev/null +++ b/test/fixtures/pointpin_80_111_555_555 @@ -0,0 +1 @@ +{"ip":"80.111.555.555","continent_code":"EU","country_code":"IE","country_name":"Ireland","region_name":"Dublin City","region_code":"D8","city_name":"Dublin","postcode":"8","latitude":53.3331,"longitude":-6.2489,"time_zone":"Europe/Dublin"} \ No newline at end of file diff --git a/test/fixtures/pointpin_no_results b/test/fixtures/pointpin_no_results new file mode 100644 index 0000000000000000000000000000000000000000..2ddd88488ffe920434ca800d546d2748bc965945 --- /dev/null +++ b/test/fixtures/pointpin_no_results @@ -0,0 +1 @@ +{"error":"Address not found"} \ No newline at end of file diff --git a/test/test_helper.rb b/test/test_helper.rb index b618b65e3d12eabc7af38ab66534a885a8f68a2e..0faf3f113d02c505d7ffcce1063881250697025b 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -150,6 +150,13 @@ module Geocoder end end + class Pointpin + private + def default_fixture_filename + "pointpin_80_111_555_555" + end + end + class Maxmind private def default_fixture_filename diff --git a/test/unit/lookup_test.rb b/test/unit/lookup_test.rb index d0507afa952ed51cd891cf0c82383aaf227add10..7515b599526f70eda35f2c1c7bc4994bd6bdfc04 100644 --- a/test/unit/lookup_test.rb +++ b/test/unit/lookup_test.rb @@ -23,7 +23,7 @@ class LookupTest < GeocoderTestCase def test_query_url_contains_values_in_params_hash Geocoder::Lookup.all_services_except_test.each do |l| - next if [:freegeoip, :maxmind_local, :telize].include? l # does not use query string + next if [:freegeoip, :maxmind_local, :telize, :pointpin].include? l # does not use query string set_api_key!(l) url = Geocoder::Lookup.get(l).query_url(Geocoder::Query.new( "test", :params => {:one_in_the_hand => "two in the bush"} @@ -119,6 +119,12 @@ class LookupTest < GeocoderTestCase assert_match "ak=MY_KEY", g.query_url(Geocoder::Query.new("Madison Square Garden, New York, NY 10001, United States")) end + def test_pointpin_api_key + Geocoder.configure(:api_key => "MY_KEY") + g = Geocoder::Lookup::Pointpin.new + assert_match "/MY_KEY/", g.query_url(Geocoder::Query.new("232.65.123.94")) + end + def test_google_api_key Geocoder.configure(:api_key => "MY_KEY") g = Geocoder::Lookup::Google.new diff --git a/test/unit/lookups/pointpin_test.rb b/test/unit/lookups/pointpin_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..201ed7016b1267b8327e39a27979f336af489adb --- /dev/null +++ b/test/unit/lookups/pointpin_test.rb @@ -0,0 +1,30 @@ +# encoding: utf-8 +$: << File.join(File.dirname(__FILE__), "..", "..") +require 'test_helper' + +class PointpinTest < GeocoderTestCase + + def setup + Geocoder.configure(ip_lookup: :pointpin, api_key: "abc123") + end + + def test_result_on_ip_address_search + result = Geocoder.search("80.111.555.555").first + assert result.is_a?(Geocoder::Result::Pointpin) + end + + def test_result_components + result = Geocoder.search("80.111.555.555").first + assert_equal "Dublin, Dublin City, 8, Ireland", result.address + end + + def test_no_results + results = Geocoder.search("10.10.10.10") + assert_equal 0, results.length + end + + def test_invalid_address + results = Geocoder.search("555.555.555.555") + assert_equal 0, results.length + end +end