geo_code_repo.rb: add reverse geocode

Phillip Davis created

Change summary

lib/geo_code_repo.rb       | 24 ++++++++++++++++++++----
test/test_geo_code_repo.rb | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+), 4 deletions(-)

Detailed changes

lib/geo_code_repo.rb 🔗

@@ -10,12 +10,30 @@ class GeoCodeRepo
 		@memcache = memcache
 	end
 
+	# @param q [String]
+	# @return [EMPromise<GeoCode>]
 	def find(q)
-		cache(q) {
+		req(q, locate: q)
+	end
+
+	# @param lat [Float]
+	# @param lon [Float]
+	# @return [EMPromise<GeoCode>]
+	def reverse(lat, lon)
+		req("reverse_#{lat}_#{lon}", latt: lat, longt: lon)
+	end
+
+protected
+
+	# @param cache_key [String]
+	# @param query [Hash]
+	# @return [EMPromise<GeoCode>]
+	def req(cache_key, **query)
+		cache(cache_key) {
 			EM::HttpRequest.new(
 				"https://geocoder.ca/",
 				tls: { verify_peer: true }
-			).aget(query: { json: 1, locate: q }).then { |res|
+			).aget(query: { json: 1, **query }).then { |res|
 				json = JSON.parse(res.response)
 				raise "Geocode Failure" unless json["latt"] && json["longt"]
 
@@ -24,8 +42,6 @@ class GeoCodeRepo
 		}.then(&GeoCode.method(:for))
 	end
 
-protected
-
 	def cache(k, &blk)
 		k = "geocode_#{k.gsub(/ /, '%20')}"
 		promise = EMPromise.new

test/test_geo_code_repo.rb 🔗

@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require "test_helper"
+require "geo_code_repo"
+
+class GeoCodeRepoTest < Minitest::Test
+	def test_reverse
+		stub_request(
+			:get,
+			"https://geocoder.ca/?json=1&latt=40.739362&longt=-73.991043"
+		).to_return(status: 200, body: {
+			"city" => "New York",
+			"prov" => "NY",
+			"latt" => "40.739362",
+			"longt" => "-73.991043",
+			"usa" => { "uscity" => "New York", "state" => "NY", "zip" => "10011" }
+		}.to_json)
+
+		geo = GeoCodeRepo.new(memcache: FakeMemcache.new)
+			.reverse(40.739362, -73.991043).sync
+
+		assert_equal "New York", geo.city
+		assert_equal "NY", geo.state
+	end
+	em :test_reverse
+
+	def test_reverse_raises_on_missing_coords
+		stub_request(
+			:get,
+			"https://geocoder.ca/?json=1&latt=0.0&longt=0.0"
+		).to_return(status: 200, body: { "error" => "no result" }.to_json)
+
+		assert_raises(RuntimeError) do
+			GeoCodeRepo.new(memcache: FakeMemcache.new)
+				.reverse(0.0, 0.0).sync
+		end
+	end
+	em :test_reverse_raises_on_missing_coords
+end