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
Branches
Tags
No related merge requests found
......@@ -10,21 +10,45 @@ module Geocoder::Lookup
end
def query_url(query)
"#{protocol}://geoip3.maxmind.com/f?" + url_query_string(query)
"#{protocol}://geoip.maxmind.com/#{service_code}?" + url_query_string(query)
end
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)
# don't look up a loopback address, just return the stored result
return [reserved_result] if query.loopback_ip_address?
doc = fetch_data(query)
if doc and doc.is_a?(Array)
if doc.size == 10
if doc.last.nil?
return [doc]
elsif doc.size > 10 and doc[10] == "INVALID_LICENSE_KEY"
raise_error(Geocoder::InvalidApiKey) ||
warn("Invalid MaxMind API key.")
elsif doc.last == "INVALID_LICENSE_KEY"
raise_error(Geocoder::InvalidApiKey) || warn("Invalid MaxMind API key.")
end
end
return []
......@@ -35,7 +59,7 @@ module Geocoder::Lookup
end
def reserved_result
",,,,0,0,0,0,,"
",,,,0,0,0,0,,,"
end
def query_url_params(query)
......
......@@ -3,53 +3,134 @@ require 'geocoder/results/base'
module Geocoder::Result
class Maxmind < Base
def address(format = :full)
s = state_code.to_s == "" ? "" : ", #{state_code}"
"#{city}#{s} #{postal_code}, #{country_code}".sub(/^[ ,]*/, "")
end
##
# Hash mapping service names to names of returned fields.
#
def self.field_names
{
:country => [
:country_code,
:error
],
def country_code
@data[0]
:city => [
: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
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
def city
@data[2]
def field_names
self.class.field_names[service_name]
end
def postal_code
@data[3]
def data_hash
@data_hash ||= Hash[*field_names.zip(@data).flatten]
end
def coordinates
[@data[4].to_f, @data[5].to_f]
[data_hash[:latitude].to_f, data_hash[:longitude].to_f]
end
def metrocode
@data[6]
def address(format = :full)
s = state_code.to_s == "" ? "" : ", #{state_code}"
"#{city}#{s} #{postal_code}, #{country_code}".sub(/^[ ,]*/, "")
end
def area_code
@data[7]
def city
data_hash[:city_name]
end
def isp
@data[8]
def state # not given by MaxMind
data_hash[:region_name] || data_hash[:region_code]
end
def organization
@data[9]
def state_code
data_hash[:region_code]
end
def country #not given by MaxMind
country_code
data_hash[:country_name] || data_hash[:country_code]
end
def state #not given by MaxMind
state_code
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
def respond_to?(method)
if field_names.include?(method)
true
else
super
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"
\ No newline at end of file
US,TX,Plano,75093,33.034698,-96.813400,623,972,"Layered Technologies , US","Layered Technologies , US",
......@@ -154,15 +154,45 @@ class ServicesTest < Test::Unit::TestCase
# --- MaxMind ---
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
assert result.is_a?(Geocoder::Result::Maxmind)
end
def test_maxmind_result_components
Geocoder::Configuration.ip_lookup = :maxmind
result = Geocoder.search("74.200.247.59").first
assert_equal "Plano, TX 75093, US", result.address
def test_maxmind_result_knows_country_service_name
Geocoder.configure(:ip_lookup => :maxmind)
assert_equal :country, Geocoder.search("24.24.24.21").first.service_name
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
......
......@@ -102,7 +102,8 @@ module Geocoder
if query.reverse_geocode?
filename = "#{fixture_prefix}_reverse"
else
filename = "#{fixture_prefix}_#{query.text.gsub(" ", "_")}"
label = query.text.gsub(/[ \.]/, "_")
filename = "#{fixture_prefix}_#{label}"
end
if fixture_exists?(filename)
read_fixture "#{filename}"
......@@ -238,6 +239,10 @@ end
class Test::Unit::TestCase
def setup
Geocoder.configure(:maxmind => {:service => :omni})
end
def teardown
Geocoder.send(:remove_const, :Configuration)
load "geocoder/configuration.rb"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment