diff --git a/README.md b/README.md index 605c5bb6ea3391ac1afb2eaa9d1e49d8e9a3f1a4..a71dd671ee3c43122361116ce2dace66faf19fe3 100644 --- a/README.md +++ b/README.md @@ -663,6 +663,17 @@ This uses the PostcodeAnywhere UK Geocode service, this will geocode any string * **Limitations**: ? * **Notes**: To use PostcodeAnywhere you must include an API key: `Geocoder.configure(:lookup => :postcode_anywhere_uk, :api_key => 'your_api_key')`. +#### LatLon.io (`:latlon`) + +* **API key**: required +* **Quota**: Depends on the user's plan (free and paid plans available) +* **Region**: US +* **SSL support**: yes +* **Languages**: en +* **Documentation**: https://latlon.io/documentation +* **Terms of Service**: ? +* **Limitations**: No restrictions on use + ### IP Address Services diff --git a/lib/geocoder/lookup.rb b/lib/geocoder/lookup.rb index c48960851bb4aa71656ea1102857c510cfc30ded..92d5a50b2069319c9dda6c6576aa0aa413359041 100644 --- a/lib/geocoder/lookup.rb +++ b/lib/geocoder/lookup.rb @@ -45,7 +45,8 @@ module Geocoder :okf, :postcode_anywhere_uk, :geoportail_lu, - :test + :test, + :latlon ] end diff --git a/lib/geocoder/lookups/latlon.rb b/lib/geocoder/lookups/latlon.rb new file mode 100644 index 0000000000000000000000000000000000000000..0e1faee454bf9d28ddc10c42b090173c2e2a55f6 --- /dev/null +++ b/lib/geocoder/lookups/latlon.rb @@ -0,0 +1,59 @@ +require 'geocoder/lookups/base' +require 'geocoder/results/latlon' + +module Geocoder::Lookup + class Latlon < Base + + def name + "LatLon.io" + end + + def required_api_key_parts + ["api_key"] + end + + def query_url(query) + "#{protocol}://latlon.io/api/v1/#{if query.reverse_geocode? then 'reverse_' end}geocode?#{url_query_string(query)}" + end + + private # --------------------------------------------------------------- + + def results(query) + return [] unless doc = fetch_data(query) + if doc['error'].nil? + [doc] + # The API returned a 404 response, which indicates no results found + elsif doc['error']['type'] == 'api_error' + [] + elsif + doc['error']['type'] == 'authentication_error' + raise_error(Geocoder::InvalidApiKey) || + Geocoder.log(:warn, "LatLon.io service error: invalid API key.") + else + [] + end + end + + def supported_protocols + [:https] + end + + private # --------------------------------------------------------------- + + def query_url_params(query) + if query.reverse_geocode? + { + :token => configuration.api_key, + :lat => query.coordinates[0], + :lon => query.coordinates[1] + }.merge(super) + else + { + :token => configuration.api_key, + :address => query.sanitized_text + }.merge(super) + end + end + + end +end diff --git a/lib/geocoder/results/latlon.rb b/lib/geocoder/results/latlon.rb new file mode 100644 index 0000000000000000000000000000000000000000..0f106bf23eea052ec527e80b5b030a7a29b754e6 --- /dev/null +++ b/lib/geocoder/results/latlon.rb @@ -0,0 +1,71 @@ +require 'geocoder/results/base' + +module Geocoder::Result + class Latlon < Base + + def city + address_components["city"] + end + + def coordinates + [@data['lat'].to_f, @data['lon'].to_f] + end + + def country + "United States" # LatLon.io only supports the US + end + + def country_code + "US" # LatLon.io only supports the US + end + + def formatted_address(format = :full) + address_components["address"] + end + alias_method :address, :formatted_address + + def number + address_components["number"] + end + + def prefix + address_components["prefix"] + end + + def state + address_components["state"] + end + alias_method :state_code, :state + + def street + [street_name, street_type].compact.join(' ') + end + + def street_name + address_components["street_name"] + end + + def street_type + address_components["street_type"] + end + + def suffix + address_components["suffix"] + end + + def unit + address_components["unit"] + end + + def zip + address_components["zip"] + end + alias_method :postal_code, :zip + + private + + def address_components + @data["address"] || {} + end + end +end diff --git a/test/fixtures/latlon_6000_universal_blvd b/test/fixtures/latlon_6000_universal_blvd new file mode 100644 index 0000000000000000000000000000000000000000..97baa14f59c22f7f8b771c7cd13100ce4fcb0882 --- /dev/null +++ b/test/fixtures/latlon_6000_universal_blvd @@ -0,0 +1,16 @@ +{ + "lat": 28.4750507575094, + "lon": -81.4630386931719, + "address": { + "address": "6000 Universal Blvd, Orlando, FL 32819", + "prefix": null, + "number": "6000", + "street_name": "Universal", + "street_type": "Blvd", + "suffix": null, + "unit": null, + "city": "Orlando", + "state": "FL", + "zip": "32819" + } +} \ No newline at end of file diff --git a/test/fixtures/latlon_invalid_key b/test/fixtures/latlon_invalid_key new file mode 100644 index 0000000000000000000000000000000000000000..d00ea46f1e40e000274381899ccdfe4e63f6456b --- /dev/null +++ b/test/fixtures/latlon_invalid_key @@ -0,0 +1,6 @@ +{ + "error": { + "type": "authentication_error", + "message": "Failed to authenticate your request." + } +} \ No newline at end of file diff --git a/test/fixtures/latlon_no_results b/test/fixtures/latlon_no_results new file mode 100644 index 0000000000000000000000000000000000000000..f0d05791d27232a8e17c6640217e61e45d8f3908 --- /dev/null +++ b/test/fixtures/latlon_no_results @@ -0,0 +1,6 @@ +{ + "error": { + "type": "api_error", + "message": "The requested resource could not be found." + } +} diff --git a/test/test_helper.rb b/test/test_helper.rb index d6519f24076016359273307d89922c173cb98f00..973bd083f9a5e3ab15a3326e398266fc9b7bbb10 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -312,6 +312,14 @@ module Geocoder "#{fixture_prefix}_boulevard_royal" end end + + require 'geocoder/lookups/latlon' + class Latlon + private + def default_fixture_filename + "latlon_6000_universal_blvd" + end + end end end diff --git a/test/unit/lookups/latlon_test.rb b/test/unit/lookups/latlon_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..2dcb47a9bbe289d66f38b44d0992428726d88bd1 --- /dev/null +++ b/test/unit/lookups/latlon_test.rb @@ -0,0 +1,42 @@ +# encoding: utf-8 +require 'test_helper' + +class LatlonTest < GeocoderTestCase + + def setup + Geocoder.configure(lookup: :latlon) + set_api_key!(:latlon) + end + + def test_result_components + result = Geocoder.search("6000 Universal Blvd, Orlando, FL 32819").first + assert_equal "6000", result.number + assert_equal "Universal", result.street_name + assert_equal "Blvd", result.street_type + assert_equal "Universal Blvd", result.street + assert_equal "Orlando", result.city + assert_equal "FL", result.state + assert_equal "32819", result.zip + assert_equal "6000 Universal Blvd, Orlando, FL 32819", result.formatted_address + assert_equal(28.4750507575094, result.latitude) + assert_equal(-81.4630386931719, result.longitude) + end + + def test_no_results + results = Geocoder.search("no results") + assert_equal 0, results.length + end + + def test_latlon_reverse_url + query = Geocoder::Query.new([45.423733, -75.676333]) + assert_match /reverse_geocode/, query.url + end + + def test_raises_api_key_exception + Geocoder.configure Geocoder.configure(:always_raise => [Geocoder::InvalidApiKey]) + assert_raises Geocoder::InvalidApiKey do + Geocoder.search("invalid key") + end + end + +end