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 +41 -0
- data/lib/mm_geoip/version.rb +1 -1
- data/lib/mm_geoip.rb +13 -7
- data/lib/{rack_mm_geoip.rb → rack/mm_geoip.rb} +4 -2
- data/lib/sinatra/mm_geoip.rb +15 -0
- data/spec/mm_geoip_region_spec.rb +20 -0
- data/spec/mm_geoip_spec.rb +105 -0
- data/spec/rack/mm_geoip_spec.rb +11 -0
- data/spec/sinatra/mm_geoip_spec.rb +39 -0
- data/spec/spec_helper.rb +9 -0
- metadata +74 -9
- data/data/GeoLiteCity.dat +0 -0
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
|
data/lib/mm_geoip/version.rb
CHANGED
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
|
-
|
19
|
-
@env
|
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 @
|
22
|
-
|
23
|
-
|
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 =
|
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
|
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,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
|
data/spec/spec_helper.rb
ADDED
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
|
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-
|
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/
|
93
|
+
- lib/rack/mm_geoip.rb
|
94
|
+
- lib/sinatra/mm_geoip.rb
|
39
95
|
- data/fips_and_3166_2.txt
|
40
|
-
-
|
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
|