Skip to content
Snippets Groups Projects
Commit 7e2a8ba0 authored by Alex Reisner's avatar Alex Reisner
Browse files

Implement support for all MaxMind services.

Now it is necessary to specify which service is being used:
  Geocoder.configure(:maxmind => {:service => ...})
where '...' is one of: < :country | :city | :city_isp_org | :omni >
parent 0e3fd4e7
No related branches found
No related tags found
No related merge requests found
...@@ -10,21 +10,45 @@ module Geocoder::Lookup ...@@ -10,21 +10,45 @@ module Geocoder::Lookup
end end
def query_url(query) def query_url(query)
"#{protocol}://geoip3.maxmind.com/f?" + url_query_string(query) "#{protocol}://geoip.maxmind.com/#{service_code}?" + url_query_string(query)
end end
private # --------------------------------------------------------------- private # ---------------------------------------------------------------
def service_code
if s = configuration[:service] and services.keys.include?(s)
services[s]
else
raise(
Geocoder::ConfigurationError,
"When using MaxMind you MUST specify a service name: " +
"Geocoder.configure(:maxmind => {:service => ...}), " +
"where '...' is one of: #{services.keys.inspect}"
)
end
end
##
# Service names mapped to code used in URL.
#
def services
{
:country => "a",
:city => "b",
:city_isp_org => "f",
:omni => "e"
}
end
def results(query) def results(query)
# don't look up a loopback address, just return the stored result # don't look up a loopback address, just return the stored result
return [reserved_result] if query.loopback_ip_address? return [reserved_result] if query.loopback_ip_address?
doc = fetch_data(query) doc = fetch_data(query)
if doc and doc.is_a?(Array) if doc and doc.is_a?(Array)
if doc.size == 10 if doc.last.nil?
return [doc] return [doc]
elsif doc.size > 10 and doc[10] == "INVALID_LICENSE_KEY" elsif doc.last == "INVALID_LICENSE_KEY"
raise_error(Geocoder::InvalidApiKey) || raise_error(Geocoder::InvalidApiKey) || warn("Invalid MaxMind API key.")
warn("Invalid MaxMind API key.")
end end
end end
return [] return []
...@@ -35,7 +59,7 @@ module Geocoder::Lookup ...@@ -35,7 +59,7 @@ module Geocoder::Lookup
end end
def reserved_result def reserved_result
",,,,0,0,0,0,," ",,,,0,0,0,0,,,"
end end
def query_url_params(query) def query_url_params(query)
......
...@@ -3,53 +3,134 @@ require 'geocoder/results/base' ...@@ -3,53 +3,134 @@ require 'geocoder/results/base'
module Geocoder::Result module Geocoder::Result
class Maxmind < Base class Maxmind < Base
def address(format = :full) ##
s = state_code.to_s == "" ? "" : ", #{state_code}" # Hash mapping service names to names of returned fields.
"#{city}#{s} #{postal_code}, #{country_code}".sub(/^[ ,]*/, "") #
end def self.field_names
{
:country => [
:country_code,
:error
],
def country_code :city => [
@data[0] :country_code,
:region_code,
:city_name,
:latitude,
:longitude,
:error
],
:city_isp_org => [
:country_code,
:region_code,
:city_name,
:postal_code,
:latitude,
:longitude,
:metro_code,
:area_code,
:isp_name,
:organization_name,
:error
],
:omni => [
:country_code,
:country_name,
:region_code,
:region_name,
:city_name,
:latitude,
:longitude,
:metro_code,
:area_code,
:time_zone,
:continent_code,
:postal_code,
:isp_name,
:organization_name,
:domain,
:as_number,
:netspeed,
:user_type,
:accuracy_radius,
:country_confidence_factor,
:city_confidence_factor,
:region_confidence_factor,
:postal_confidence_factor,
:error
]
}
end end
def state_code ##
@data[1] # Name of the MaxMind service being used.
# Inferred from format of @data.
#
def service_name
self.class.field_names.to_a.each do |n,f|
return n if f.size == @data.size
end
nil
end end
def city def field_names
@data[2] self.class.field_names[service_name]
end end
def postal_code def data_hash
@data[3] @data_hash ||= Hash[*field_names.zip(@data).flatten]
end end
def coordinates def coordinates
[@data[4].to_f, @data[5].to_f] [data_hash[:latitude].to_f, data_hash[:longitude].to_f]
end end
def metrocode def address(format = :full)
@data[6] s = state_code.to_s == "" ? "" : ", #{state_code}"
"#{city}#{s} #{postal_code}, #{country_code}".sub(/^[ ,]*/, "")
end end
def area_code def city
@data[7] data_hash[:city_name]
end end
def isp def state # not given by MaxMind
@data[8] data_hash[:region_name] || data_hash[:region_code]
end end
def organization def state_code
@data[9] data_hash[:region_code]
end end
def country #not given by MaxMind def country #not given by MaxMind
country_code data_hash[:country_name] || data_hash[:country_code]
end
def country_code
data_hash[:country_code]
end
def postal_code
data_hash[:postal_code]
end
def method_missing(method, *args, &block)
if field_names.include?(method)
data_hash[method]
else
super
end
end end
def state #not given by MaxMind def respond_to?(method)
state_code if field_names.include?(method)
true
else
super
end
end end
end end
end end
US,
US,NY,Jamaica,40.6915,-73.8057,
US,NY,Jamaica,,40.6915,-73.8057,501,718,"Road Runner","Road Runner",
US,"United States",NY,"New York",Jamaica,40.6915,-73.8057,501,718,America/New_York,NA,,"Road Runner","Road Runner",rr.com,"AS11351 Road Runner HoldCo LLC",Cable/DSL,residential,779,99,37,76,,
US,TX,Plano,75093,33.034698,-96.813400,623,972,"Layered Technologies , US","Layered Technologies , US" US,TX,Plano,75093,33.034698,-96.813400,623,972,"Layered Technologies , US","Layered Technologies , US",
\ No newline at end of file
...@@ -154,15 +154,45 @@ class ServicesTest < Test::Unit::TestCase ...@@ -154,15 +154,45 @@ class ServicesTest < Test::Unit::TestCase
# --- MaxMind --- # --- MaxMind ---
def test_maxmind_result_on_ip_address_search def test_maxmind_result_on_ip_address_search
Geocoder::Configuration.ip_lookup = :maxmind Geocoder.configure(:ip_lookup => :maxmind, :maxmind => {:service => :city_isp_org})
result = Geocoder.search("74.200.247.59").first result = Geocoder.search("74.200.247.59").first
assert result.is_a?(Geocoder::Result::Maxmind) assert result.is_a?(Geocoder::Result::Maxmind)
end end
def test_maxmind_result_components def test_maxmind_result_knows_country_service_name
Geocoder::Configuration.ip_lookup = :maxmind Geocoder.configure(:ip_lookup => :maxmind)
result = Geocoder.search("74.200.247.59").first assert_equal :country, Geocoder.search("24.24.24.21").first.service_name
assert_equal "Plano, TX 75093, US", result.address end
def test_maxmind_result_knows_city_service_name
Geocoder.configure(:ip_lookup => :maxmind)
assert_equal :city, Geocoder.search("24.24.24.22").first.service_name
end
def test_maxmind_result_knows_city_isp_org_service_name
Geocoder.configure(:ip_lookup => :maxmind)
assert_equal :city_isp_org, Geocoder.search("24.24.24.23").first.service_name
end
def test_maxmind_result_knows_omni_service_name
Geocoder.configure(:ip_lookup => :maxmind)
assert_equal :omni, Geocoder.search("24.24.24.24").first.service_name
end
def test_maxmind_special_result_components
Geocoder.configure(:ip_lookup => :maxmind)
result = Geocoder.search("24.24.24.24").first
assert_equal "Road Runner", result.isp_name
assert_equal "Cable/DSL", result.netspeed
assert_equal "rr.com", result.domain
end
def test_maxmind_raises_exception_when_service_not_configured
Geocoder.configure(:ip_lookup => :maxmind)
Geocoder.configure(:maxmind => {:service => nil})
assert_raises Geocoder::ConfigurationError do
Geocoder::Query.new("24.24.24.24").url
end
end end
......
...@@ -102,7 +102,8 @@ module Geocoder ...@@ -102,7 +102,8 @@ module Geocoder
if query.reverse_geocode? if query.reverse_geocode?
filename = "#{fixture_prefix}_reverse" filename = "#{fixture_prefix}_reverse"
else else
filename = "#{fixture_prefix}_#{query.text.gsub(" ", "_")}" label = query.text.gsub(/[ \.]/, "_")
filename = "#{fixture_prefix}_#{label}"
end end
if fixture_exists?(filename) if fixture_exists?(filename)
read_fixture "#{filename}" read_fixture "#{filename}"
...@@ -238,6 +239,10 @@ end ...@@ -238,6 +239,10 @@ end
class Test::Unit::TestCase class Test::Unit::TestCase
def setup
Geocoder.configure(:maxmind => {:service => :omni})
end
def teardown def teardown
Geocoder.send(:remove_const, :Configuration) Geocoder.send(:remove_const, :Configuration)
load "geocoder/configuration.rb" load "geocoder/configuration.rb"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment