mm_geoip 0.0.4 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/bin/mm_geoip ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mm_geoip'
4
+
5
+ begin
6
+ if ip = ARGV[0]
7
+ MMGeoip.db_path = ARGV[1] if ARGV[1]
8
+
9
+ puts "Using database: #{MMGeoip.db_path}"
10
+
11
+ geoip = MMGeoip.new :ip => ip
12
+
13
+ (MMGeoip::FIELDS + [:region_name]).each do |field|
14
+ puts "#{field}: #{geoip.send field}"
15
+ end
16
+
17
+ else
18
+ puts "You should try passing an IP as argument: mm_geoip 134.34.3.2"
19
+ end
20
+ rescue MMGeoip::NoDatabaseFile => e
21
+ puts %Q{
22
+ MMGeoip could't find your geodb database file.
23
+ #{e.class}: #{e.message}
24
+
25
+ When runing this tool you have three possibilities to define the database location.
26
+
27
+ * Either you can put one into the gem so mm_geoip finds it automatically:
28
+ ln -s /your/database.dat `pwd`
29
+
30
+ * Or you set an environment variable:
31
+ MMGeoipDatabase=/your/database.dat mm_geoip 134.34.3.2
32
+
33
+ * Or you pass the location as a second argument:
34
+ mm_geoip 134.34.3.2 /your/database.dat
35
+
36
+ Download:
37
+ curl http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz | gunzip > GeoLiteCity.dat
38
+
39
+ }
40
+
41
+ end
@@ -1,3 +1,3 @@
1
1
  class MMGeoip
2
- VERSION = '0.0.4'
2
+ VERSION = '0.1.0'
3
3
  end
data/lib/mm_geoip.rb CHANGED
@@ -4,6 +4,7 @@ $LOAD_PATH << File.dirname(File.expand_path __FILE__)
4
4
 
5
5
  class MMGeoip; end
6
6
 
7
+ require 'mm_geoip/version'
7
8
  require 'mm_geoip/region'
8
9
 
9
10
  class MMGeoip
@@ -13,14 +14,19 @@ class MMGeoip
13
14
  attr_reader :lookup
14
15
 
15
16
  class NoIpGiven < StandardError; end
17
+ class NoDatabaseFile < StandardError; end
16
18
 
17
19
  def initialize(env)
18
- @env = env # may be a Rack @env or any hash containing initial data
19
- @env[:ip] ||= @env["HTTP_X_REAL_IP"] || @env["HTTP_X_FORWARDED_FOR"] || @env["REMOTE_ADDR"]
20
+ # May be a Rack @env or any hash containing initial data. Or just an IP.
21
+ @env = env.is_a?(Hash) ? env.dup : {:ip => env}
22
+ @ip = @env[:ip] || @env["HTTP_X_REAL_IP"] || @env["HTTP_X_FORWARDED_FOR"] || @env["REMOTE_ADDR"]
20
23
 
21
- raise NoIpGiven.new unless @env[:ip]
22
-
23
- @geodb = GeoIP.new self.class.db_path
24
+ raise NoIpGiven.new("No IP in env hash") unless @ip
25
+ raise NoDatabaseFile.new("No database file: #{self.class.db_path}") unless File.exists? self.class.db_path
26
+ end
27
+
28
+ def geodb
29
+ @geodb ||= GeoIP.new self.class.db_path
24
30
  end
25
31
 
26
32
  FIELDS.each do |field|
@@ -56,7 +62,7 @@ class MMGeoip
56
62
  def lookup
57
63
  return @lookup if @lookup
58
64
 
59
- looked_up_fields = @geodb.city @env[:ip]
65
+ looked_up_fields = geodb.city @ip
60
66
 
61
67
  return @lookup = {} unless looked_up_fields
62
68
 
@@ -69,7 +75,7 @@ class MMGeoip
69
75
  File.join(File.dirname(File.expand_path(__FILE__)), '../data')
70
76
  end
71
77
  def self.db_path
72
- @db_path || File.join(data_path, 'GeoLiteCity.dat')
78
+ @db_path || ENV['MMGeoipDatabase'] || File.join(data_path, 'GeoLiteCity.dat')
73
79
  end
74
80
  def self.db_path=(path)
75
81
  @db_path = path
@@ -1,3 +1,5 @@
1
+ require 'mm_geoip.rb'
2
+
1
3
  module Rack
2
4
  class MMGeoip
3
5
  def initialize(app)
@@ -5,8 +7,8 @@ module Rack
5
7
  end
6
8
 
7
9
  def call(env)
8
- env['GEOIP'] = ::MMGeoip.new env
9
- @app.call(env)
10
+ @app.call env.dup.merge('GEOIP' => ::MMGeoip.new(env))
10
11
  end
11
12
  end
12
13
  end
14
+
@@ -0,0 +1,15 @@
1
+ require 'rack/mm_geoip.rb'
2
+
3
+ module Sinatra
4
+ module MMGeoip
5
+
6
+ # Just a convinience method to access the mm_geoip proxy
7
+ # object in Sinatra routes and views.
8
+ def geoip
9
+ request.env['GEOIP']
10
+ end
11
+
12
+ end
13
+
14
+ helpers MMGeoip
15
+ end
@@ -0,0 +1,20 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper')
2
+
3
+ describe MMGeoip::Regions do
4
+ describe "#parse" do
5
+ it "works" do
6
+ MMGeoip::Regions.parse[:CA]['NS'].should == 'Nova Scotia' # CA,NS,"Nova Scotia"
7
+ MMGeoip::Regions.parse[:US]['AL'].should == 'Alabama' # US,AL,"Alabama"
8
+ MMGeoip::Regions.parse[:DE]['01'].should == 'Baden-Wurttemberg' # DE,02,"Bayern"
9
+ MMGeoip::Regions.parse[:DE]['02'].should == 'Bayern' # DE,01,"Baden-Wurttemberg"
10
+ end
11
+ end
12
+ describe "#[]" do
13
+ it "works" do
14
+ MMGeoip::Regions[:CA]['NS'].should == 'Nova Scotia' # CA,NS,"Nova Scotia"
15
+ MMGeoip::Regions[:US]['AL'].should == 'Alabama' # US,AL,"Alabama"
16
+ MMGeoip::Regions[:DE]['01'].should == 'Baden-Wurttemberg' # DE,02,"Bayern"
17
+ MMGeoip::Regions[:DE]['02'].should == 'Bayern' # DE,01,"Baden-Wurttemberg"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,105 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper')
2
+
3
+ describe MMGeoip do
4
+ describe "the whole stack" do
5
+ before(:each) do
6
+ @env = {:ip => '134.34.3.2'}
7
+ end
8
+ it "should be fast" do
9
+ # Succeeds with a margin of about 10% on my MBP core2duo 2.4GHz.
10
+ # On slower computers this will fail.
11
+ Benchmark.measure{
12
+ 1000.times{mm_geoip = MMGeoip.new @env ; mm_geoip.city} # with lookup
13
+ }.total.should < 0.6
14
+ end
15
+ it "be lazy, i.e. 3 times faster without lookup" do
16
+ with_lookup = Benchmark.measure{
17
+ 1000.times{mm_geoip = MMGeoip.new @env ; mm_geoip.city} # with lookup
18
+ }.total
19
+
20
+ no_lookup = Benchmark.measure{
21
+ 1000.times{mm_geoip = MMGeoip.new @env} # no lookup
22
+ }.total
23
+
24
+ (no_lookup*3).should < with_lookup
25
+ end
26
+ end
27
+
28
+ describe "#initialize" do
29
+ it "works with the IP as :ip field" do
30
+ MMGeoip.new '134.34.3.2'
31
+ end
32
+ it "works with just the IP" do
33
+ MMGeoip.new :ip => '134.34.3.2'
34
+ end
35
+ it "works with the IP as 'REMOTE_ADDR' field" do
36
+ MMGeoip.new 'REMOTE_ADDR' => '134.34.3.2'
37
+ end
38
+ it "works with the IP as 'HTTP_X_REAL_IP' field" do
39
+ MMGeoip.new 'HTTP_X_REAL_IP' => '134.34.3.2'
40
+ end
41
+ it "works with the IP as 'HTTP_X_FORWARDED_FOR' field" do
42
+ MMGeoip.new 'HTTP_X_FORWARDED_FOR' => '134.34.3.2'
43
+ end
44
+ it "raises, if not :ip or 'REMOTE_ADDR' is given" do
45
+ lambda{ MMGeoip.new :whatelse => 'something' }.should raise_error(MMGeoip::NoIpGiven)
46
+ end
47
+ it "puts the parameter into the env instance variable" do
48
+ env = {:ip => '134.34.3.2'}
49
+ mm_geoip = MMGeoip.new env
50
+ mm_geoip.instance_variable_get('@env').should == env
51
+ end
52
+ it "does not alter the env hash" do
53
+ env = {'REMOTE_ADDR' => '134.34.3.2'}
54
+ env_before = env.dup
55
+ mm_geoip = MMGeoip.new env
56
+ env.should == env_before
57
+ end
58
+ end
59
+
60
+ describe "#geoip" do
61
+ it "sets up a geoidb object" do
62
+ mm_geoip = MMGeoip.new(:ip => '134.34.3.2')
63
+ mm_geoip.geodb.should == mm_geoip.instance_variable_get('@geodb')
64
+ mm_geoip.geodb.should be_a(GeoIP)
65
+ end
66
+ end
67
+
68
+ describe "the getters" do
69
+ it "works" do
70
+ mm_geoip = MMGeoip.new :ip => '134.34.3.2'
71
+ mm_geoip.ip.should == '134.34.3.2'
72
+
73
+ mm_geoip.hostname.should == '134.34.3.2'
74
+ mm_geoip.ip.should == '134.34.3.2'
75
+ mm_geoip.country_code.should == 'DE'
76
+ mm_geoip.country_code3.should == 'DEU'
77
+ mm_geoip.country_name.should == 'Germany'
78
+ mm_geoip.country_continent.should == 'EU'
79
+ mm_geoip.region.should == '01'
80
+ mm_geoip.city.should == 'Konstanz'
81
+ mm_geoip.postal_code.should == ''
82
+ mm_geoip.lat.should == 47.66669999999999
83
+ mm_geoip.lng.should == 9.183300000000003
84
+ mm_geoip.dma_code.should == nil
85
+ mm_geoip.area_code.should == nil
86
+ mm_geoip.timezone.should == 'Europe/Berlin'
87
+ mm_geoip.region_name.should == 'Baden-Wurttemberg'
88
+ end
89
+ it "works with localhost, too" do
90
+ mm_geoip = MMGeoip.new :ip => '127.0.0.1'
91
+ mm_geoip.ip.should == '127.0.0.1'
92
+
93
+ mm_geoip.hostname.should be_nil
94
+ mm_geoip.region_name.should be_nil
95
+ end
96
+ end
97
+
98
+ describe "#get_from_env" do
99
+ it "tries the env fields" do
100
+ MMGeoip.new(:ip => '134.34.3.2', :hostname => 'hostname').hostname.should == 'hostname'
101
+ MMGeoip.new(:ip => '134.34.3.2', 'GEOIP_HOSTNAME' => 'geoip hostname').hostname.should == 'geoip hostname'
102
+ MMGeoip.new(:ip => '134.34.3.2', 'X_GEOIP_HOSTNAME' => 'x geoip hostname').hostname.should == 'x geoip hostname'
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,11 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), '../spec_helper')
2
+
3
+ describe Rack::MMGeoip do
4
+ describe '#call' do
5
+ it "adds a MMGeoip object to the env hash" do
6
+ app = proc{|env| env}
7
+ rack_geoip = Rack::MMGeoip.new app
8
+ rack_geoip.call({:ip => '134.34.3.2'})['GEOIP'].should be_a(MMGeoip)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,39 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), '../spec_helper')
2
+
3
+ require 'rack/test'
4
+
5
+ class SinatraMMGeoipApp < Sinatra::Base
6
+ use Rack::MMGeoip
7
+ helpers Sinatra::MMGeoip
8
+
9
+ get '/' do
10
+ geoip.city
11
+ end
12
+
13
+ end
14
+
15
+ describe Sinatra::MMGeoip do
16
+ include Rack::Test::Methods
17
+
18
+ def app
19
+ SinatraMMGeoipApp
20
+ end
21
+
22
+ describe "a test app which just puts the city into the body" do
23
+ describe "with a remote address in the env hash" do
24
+ it "returns the city as response" do
25
+ get '/', {}, {'REMOTE_ADDR' => '134.34.3.2'}
26
+ puts last_response.body
27
+ last_response.should be_ok
28
+ last_response.body.should == 'Konstanz'
29
+ end
30
+ end
31
+ describe "without a remote address in the env hash" do
32
+ it "returns an emty response" do
33
+ get '/'
34
+ last_response.should be_ok
35
+ last_response.body.should == ''
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH << File.join(File.dirname(File.expand_path __FILE__), '../lib')
2
+
3
+ require 'benchmark'
4
+
5
+ require 'mm_geoip'
6
+ require 'rack/mm_geoip'
7
+ require 'sinatra/base'
8
+ require 'sinatra/mm_geoip'
9
+
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: mm_geoip
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.4
5
+ version: 0.1.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Niko Dittmann
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-06-06 00:00:00 Z
13
+ date: 2011-06-13 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: geoip
@@ -23,10 +23,65 @@ dependencies:
23
23
  version: "0"
24
24
  type: :runtime
25
25
  version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :development
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: bundler
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :development
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: sinatra
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ type: :development
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: rack-test
61
+ prerelease: false
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ type: :development
69
+ version_requirements: *id005
70
+ - !ruby/object:Gem::Dependency
71
+ name: rspec
72
+ prerelease: false
73
+ requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ type: :development
80
+ version_requirements: *id006
26
81
  description: A proxy object around the geoip gem for lazy lookup. Includes a Rack middleware.
27
82
  email: mail+git@niko-dittmann.com
28
- executables: []
29
-
83
+ executables:
84
+ - mm_geoip
30
85
  extensions: []
31
86
 
32
87
  extra_rdoc_files: []
@@ -35,13 +90,19 @@ files:
35
90
  - lib/mm_geoip/region.rb
36
91
  - lib/mm_geoip/version.rb
37
92
  - lib/mm_geoip.rb
38
- - lib/rack_mm_geoip.rb
93
+ - lib/rack/mm_geoip.rb
94
+ - lib/sinatra/mm_geoip.rb
39
95
  - data/fips_and_3166_2.txt
40
- - data/GeoLiteCity.dat
96
+ - bin/mm_geoip
97
+ - spec/mm_geoip_region_spec.rb
98
+ - spec/mm_geoip_spec.rb
99
+ - spec/rack/mm_geoip_spec.rb
100
+ - spec/sinatra/mm_geoip_spec.rb
101
+ - spec/spec_helper.rb
41
102
  homepage: http://github.com/niko/mm_geoip
42
103
  licenses: []
43
104
 
44
- post_install_message:
105
+ post_install_message: "Try your new mm_geoip installation: type mm_geoip 134.34.3.2 [RETURN] in the command line."
45
106
  rdoc_options: []
46
107
 
47
108
  require_paths:
@@ -65,5 +126,9 @@ rubygems_version: 1.7.2
65
126
  signing_key:
66
127
  specification_version: 3
67
128
  summary: A proxy object around the geoip gem for lazy lookup. Includes a Rack middleware.
68
- test_files: []
69
-
129
+ test_files:
130
+ - spec/mm_geoip_region_spec.rb
131
+ - spec/mm_geoip_spec.rb
132
+ - spec/rack/mm_geoip_spec.rb
133
+ - spec/sinatra/mm_geoip_spec.rb
134
+ - spec/spec_helper.rb
data/data/GeoLiteCity.dat DELETED
Binary file