From 6b03f839b5fe7966edde12510d86b108166c508d Mon Sep 17 00:00:00 2001
From: Fernando Morgenstern <contato@fernandomarcelo.com>
Date: Wed, 1 May 2013 00:24:53 -0300
Subject: [PATCH] Adding support for MaxMind's local database.

---
 Gemfile                               |  1 +
 README.md                             | 12 ++++++++
 lib/geocoder/lookup.rb                |  2 +-
 lib/geocoder/lookups/maxmind_local.rb | 30 ++++++++++++++++++
 lib/geocoder/results/maxmind_local.rb | 44 +++++++++++++++++++++++++++
 test/maxmind_local.rb                 | 12 ++++++++
 6 files changed, 100 insertions(+), 1 deletion(-)
 create mode 100644 lib/geocoder/lookups/maxmind_local.rb
 create mode 100644 lib/geocoder/results/maxmind_local.rb
 create mode 100644 test/maxmind_local.rb

diff --git a/Gemfile b/Gemfile
index c18d867d..a62bbe09 100644
--- a/Gemfile
+++ b/Gemfile
@@ -4,6 +4,7 @@ group :development, :test do
   gem 'rake'
   gem 'mongoid', '2.6.0'
   gem 'bson_ext', :platforms => :ruby
+  gem 'geoip'
 
   gem 'rails'
 
diff --git a/README.md b/README.md
index d2ec199f..3c4745c4 100644
--- a/README.md
+++ b/README.md
@@ -420,6 +420,18 @@ Yahoo BOSS is **not a free service**. As of November 17, 2012 Yahoo no longer of
 * **Limitations**: ?
 * **Notes**: You must specify which MaxMind service you are using in your configuration. For example: `Geocoder.configure(:maxmind => {:service => :omni})`.
 
+#### MaxMind Local (`:maxmind_local`)
+
+* **API key**: none. But requires the city database which can be downloaded here http://dev.maxmind.com/geoip/geolite
+* **Quota**: none
+* **Region**: world
+* **SSL support**: N/A
+* **Languages**: English
+* **Documentation**: http://www.maxmind.com/en/city
+* **Terms of Service**: ?
+* **Limitations**: ?
+* **Notes**: You must specify the path of the MaxMind database in your configuration. For example: `Geocoder.configure(:maxmind_local => {:database => File.join('folder', 'GeoLiteCity.dat')})`.
+
 #### ESRI (`:esri`)
 
 * **API key**: none
diff --git a/lib/geocoder/lookup.rb b/lib/geocoder/lookup.rb
index 054d55cc..78ac0dc3 100644
--- a/lib/geocoder/lookup.rb
+++ b/lib/geocoder/lookup.rb
@@ -39,7 +39,7 @@ module Geocoder
     # All IP address lookup services, default first.
     #
     def ip_services
-      [:freegeoip, :maxmind]
+      [:freegeoip, :maxmind, :maxmind_local]
     end
 
     ##
diff --git a/lib/geocoder/lookups/maxmind_local.rb b/lib/geocoder/lookups/maxmind_local.rb
new file mode 100644
index 00000000..ae1578f7
--- /dev/null
+++ b/lib/geocoder/lookups/maxmind_local.rb
@@ -0,0 +1,30 @@
+require 'geocoder/lookups/base'
+require 'geocoder/results/maxmind_local'
+require 'geoip'
+
+module Geocoder::Lookup
+  class MaxmindLocal < Base
+
+    def name
+      "MaxMind Local"
+    end
+
+    def required_api_key_parts
+      []
+    end
+
+    private
+
+    def results(query)
+      if configuration[:database].nil?
+        raise(
+          Geocoder::ConfigurationError,
+          "When using MaxMind Database you MUST specify the path: " +
+          "Geocoder.configure(:maxmind_local => {:database => ...}), "
+        )
+      end
+
+      [GeoIP.new(configuration[:database]).city(query.to_s)]
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/geocoder/results/maxmind_local.rb b/lib/geocoder/results/maxmind_local.rb
new file mode 100644
index 00000000..7b8b9d09
--- /dev/null
+++ b/lib/geocoder/results/maxmind_local.rb
@@ -0,0 +1,44 @@
+require 'geocoder/results/base'
+
+module Geocoder::Result
+  class MaxmindLocal < Base
+    def address(format = :full)
+      s = state_code.to_s == "" ? "" : ", #{state_code}"
+      "#{city}#{s} #{postal_code}, #{country}".sub(/^[ ,]*/, "")
+    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_code3
+    end
+
+    def postal_code
+      @data.postal_code
+    end
+
+    def self.response_attributes
+      %w[ip]
+    end
+
+    response_attributes.each do |a|
+      define_method a do
+        @data[a]
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/test/maxmind_local.rb b/test/maxmind_local.rb
new file mode 100644
index 00000000..acc91291
--- /dev/null
+++ b/test/maxmind_local.rb
@@ -0,0 +1,12 @@
+# encoding: utf-8
+require 'test_helper'
+
+class MaxmindLocalTest < Test::Unit::TestCase
+  def test_it_requires_database_path
+    g = Geocoder::Lookup::MaxmindLocal.new
+
+    assert_raise Geocoder::ConfigurationError do
+      g.search(Geocoder::Query.new('8.8.8.8')).first
+    end
+  end
+end
\ No newline at end of file
-- 
GitLab