geo_ip_curb 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010-2011 Ryan Conway, Jeroen Jacobs
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,80 @@
1
+ require 'json'
2
+ require 'curb'
3
+
4
+ class GeoIpCurb
5
+ SERVICE_URL = "http://api.ipinfodb.com/v2"
6
+ CITY_API = "ip_query.php"
7
+ COUNTRY_API = "ip_query_country.php"
8
+ IPV4_REGEXP = /\A(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)(?:\.(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)){3}\z/
9
+ TIMEOUT = 1
10
+ ERROR_PREFIX = "GeoIpCurb service error"
11
+
12
+ @@api_key = nil
13
+
14
+ def self.api_key
15
+ @@api_key
16
+ end
17
+
18
+ def self.api_key=(api_key)
19
+ @@api_key = api_key
20
+ end
21
+
22
+ # Retreive the remote location of a given ip address.
23
+ #
24
+ # It takes two optional arguments:
25
+ # * +preceision+: can either be +:city+ (default) or +:country+
26
+ # * +timezone+: can either be +false+ (default) or +true+
27
+ #
28
+ # ==== Example:
29
+ # GeoIpCurb.geolocation('209.85.227.104', {:precision => :city, :timezone => true})
30
+ def self.geolocation(ip, options={})
31
+ @precision = options[:precision] || :city
32
+ @timezone = options[:timezone] || false
33
+ @timeout = options[:timeout] || TIMEOUT
34
+
35
+ raise "API key must be set first: GeoIpCurb.api_key = 'YOURKEY'" if self.api_key.nil?
36
+ raise "Invalid IP address" unless ip.to_s =~ IPV4_REGEXP
37
+ raise "Invalid precision" unless [:country, :city].include?(@precision)
38
+ raise "Invalid timezone" unless [true, false].include?(@timezone)
39
+
40
+ uri = "#{SERVICE_URL}/#{@country ? COUNTRY_API : CITY_API}?key=#{self.api_key}&ip=#{ip}&output=json&timezone=#{@timezone}"
41
+
42
+ convert_keys send_request(uri)
43
+ end
44
+
45
+ private
46
+
47
+ def self.send_request(uri)
48
+ http = Curl::Easy.new(uri)
49
+ http.timeout = @timeout
50
+ http.perform
51
+ JSON.parse(http.body_str)
52
+ rescue => e
53
+ error = {}
54
+ error[:error_msg] = "#{ERROR_PREFIX}: \"#{e}\"."
55
+ error
56
+ end
57
+
58
+ def self.convert_keys(hash)
59
+ location = {}
60
+ location[:ip] = hash["Ip"]
61
+ location[:status] = hash["Status"]
62
+ location[:country_code] = hash["CountryCode"]
63
+ location[:country_name] = hash["CountryName"]
64
+ if @precision == :city
65
+ location[:region_code] = hash["RegionCode"]
66
+ location[:region_name] = hash["RegionName"]
67
+ location[:city] = hash["City"]
68
+ location[:zip_postal_code] = hash["ZipPostalCode"]
69
+ location[:latitude] = hash["Latitude"]
70
+ location[:longitude] = hash["Longitude"]
71
+ if @timezone
72
+ location[:timezone_name] = hash["TimezoneName"]
73
+ location[:utc_offset] = hash["Gmtoffset"].to_i
74
+ location[:dst?] = hash["Isdst"] ? true : false
75
+ end
76
+ end
77
+ location[:error] = hash[:error_msg] if hash[:error_msg]
78
+ location
79
+ end
80
+ end
@@ -0,0 +1 @@
1
+ key: YOUR_KEY_HERE
@@ -0,0 +1,120 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ IP_GOOGLE_US = '209.85.227.104'
3
+ IP_PRIVATE = '10.0.0.1'
4
+ IP_LOCAL = '127.0.0.1'
5
+
6
+ describe "GeoIp" do
7
+
8
+ before :each do
9
+ api_config = YAML.load_file(File.dirname(__FILE__) + '/api.yml')
10
+ GeoIp.api_key = api_config['key']
11
+ end
12
+
13
+ context "api_key" do
14
+ it "should return the API key when set" do
15
+ GeoIp.api_key = "my_api_key"
16
+ GeoIp.api_key.should == "my_api_key"
17
+ end
18
+
19
+ it "should throw an error when API key is not set" do
20
+ GeoIp.api_key = nil
21
+ lambda {GeoIp.geolocation(IP_GOOGLE_US)}.should raise_error
22
+ end
23
+ end
24
+
25
+ context "service failure" do
26
+ it "should return an error hash if the GeoIP service is down" do
27
+ GeoIp.expects(:send_request).returns({:error_msg => "#{GeoIp::ERROR_PREFIX}: Im on fire!"}).once
28
+ geolocation = GeoIp.geolocation(IP_GOOGLE_US)
29
+ geolocation[:error].should =~ Regexp.new("^#{GeoIp::ERROR_PREFIX}")
30
+ Mocha::Mockery.instance.stubba.unstub_all
31
+ end
32
+ end
33
+
34
+ context "city" do
35
+ it "should return the correct city for a public ip address" do
36
+ geolocation = GeoIp.geolocation(IP_GOOGLE_US)
37
+ geolocation[:country_code].should == 'US'
38
+ geolocation[:country_name].should == 'United States'
39
+ geolocation[:city].should == 'Mountain View'
40
+ end
41
+
42
+ it "should return the correct city for a private ip address" do
43
+ geolocation = GeoIp.geolocation(IP_PRIVATE)
44
+ geolocation[:country_code].should == 'RD'
45
+ geolocation[:country_name].should == 'Reserved'
46
+ geolocation[:city].should be_empty
47
+ end
48
+
49
+ it "should return the correct city for localhost ip address" do
50
+ geolocation = GeoIp.geolocation(IP_LOCAL)
51
+ geolocation[:country_code].should == 'RD'
52
+ geolocation[:country_name].should == 'Reserved'
53
+ geolocation[:city].should be_empty
54
+ end
55
+
56
+ it "should return the correct city for a public ip address when explicitly requiring it" do
57
+ geolocation = GeoIp.geolocation(IP_GOOGLE_US, {:precision => :city})
58
+ geolocation[:country_code].should == 'US'
59
+ geolocation[:country_name].should == 'United States'
60
+ geolocation[:city].should == 'Mountain View'
61
+ end
62
+ end
63
+
64
+ context "country" do
65
+ it "should return the correct country for a public ip address" do
66
+ geolocation = GeoIp.geolocation(IP_GOOGLE_US, {:precision => :country})
67
+ geolocation[:country_code].should == 'US'
68
+ geolocation[:country_name].should == 'United States'
69
+ end
70
+
71
+ it "should return the correct country for a private ip address" do
72
+ geolocation = GeoIp.geolocation(IP_PRIVATE, {:precision => :country})
73
+ geolocation[:country_code].should == 'RD'
74
+ geolocation[:country_name].should == 'Reserved'
75
+ end
76
+
77
+ it "should return the correct country for localhost ip address" do
78
+ geolocation = GeoIp.geolocation(IP_LOCAL, {:precision => :country})
79
+ geolocation[:country_code].should == 'RD'
80
+ geolocation[:country_name].should == 'Reserved'
81
+ end
82
+
83
+ it "should not return the city for a public ip address" do
84
+ geolocation = GeoIp.geolocation(IP_GOOGLE_US, {:precision => :country})
85
+ geolocation[:country_code].should == 'US'
86
+ geolocation[:country_name].should == 'United States'
87
+ geolocation[:city].should be_nil
88
+ end
89
+ end
90
+
91
+ context "timezone" do
92
+ it "should return the correct timezone information for a public ip address" do
93
+ geolocation = GeoIp.geolocation(IP_GOOGLE_US, {:timezone => true})
94
+ geolocation[:timezone_name].should == 'America/Los_Angeles'
95
+ geolocation[:utc_offset].should == -28800
96
+ geolocation[:dst?].should_not be_nil # true if dst?, false if not dst?
97
+ end
98
+
99
+ it "should not return the timezone information when explicitly not requesting it" do
100
+ geolocation = GeoIp.geolocation(IP_GOOGLE_US, {:timezone => false})
101
+ geolocation[:timezone_name].should be_nil
102
+ geolocation[:utc_offset].should be_nil
103
+ geolocation[:dst?].should be_nil
104
+ end
105
+
106
+ it "should not return the timezone information when not requesting it" do
107
+ geolocation = GeoIp.geolocation(IP_GOOGLE_US)
108
+ geolocation[:timezone_name].should be_nil
109
+ geolocation[:utc_offset].should be_nil
110
+ geolocation[:dst?].should be_nil
111
+ end
112
+
113
+ it "should not return the timezone information when country precision is selected" do
114
+ geolocation = GeoIp.geolocation(IP_GOOGLE_US, {:precision => :country, :timezone => true})
115
+ geolocation[:timezone_name].should be_nil
116
+ geolocation[:utc_offset].should be_nil
117
+ geolocation[:dst?].should be_nil
118
+ end
119
+ end
120
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup
4
+ Bundler.require :development
5
+
6
+ require 'geo_ip'
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: geo_ip_curb
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 2
10
+ version: 0.3.2
11
+ platform: ruby
12
+ authors:
13
+ - Ryan Conway
14
+ - Jeroen Jacobs
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-05-24 00:00:00 Z
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: json
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 11
30
+ segments:
31
+ - 1
32
+ - 4
33
+ - 6
34
+ version: 1.4.6
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: curb
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 29
46
+ segments:
47
+ - 0
48
+ - 7
49
+ - 15
50
+ version: 0.7.15
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: rspec
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ hash: 9
62
+ segments:
63
+ - 2
64
+ - 5
65
+ version: "2.5"
66
+ type: :development
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: mocha
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ hash: 35
77
+ segments:
78
+ - 0
79
+ - 9
80
+ - 12
81
+ version: 0.9.12
82
+ type: :development
83
+ version_requirements: *id004
84
+ description: A call to the ipinfodb.com will be done to retreive the geolocation based on the IP address. No need to include a database file in the application.
85
+ email:
86
+ executables: []
87
+
88
+ extensions: []
89
+
90
+ extra_rdoc_files: []
91
+
92
+ files:
93
+ - LICENSE
94
+ - lib/geo_ip_curb.rb
95
+ - spec/api.yml.example
96
+ - spec/geo_ip_spec.rb
97
+ - spec/spec.opts
98
+ - spec/spec_helper.rb
99
+ homepage:
100
+ licenses: []
101
+
102
+ post_install_message:
103
+ rdoc_options: []
104
+
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: 3
113
+ segments:
114
+ - 0
115
+ version: "0"
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ hash: 3
122
+ segments:
123
+ - 0
124
+ version: "0"
125
+ requirements: []
126
+
127
+ rubyforge_project:
128
+ rubygems_version: 1.8.2
129
+ signing_key:
130
+ specification_version: 3
131
+ summary: Retreive the geolocation of an IP address based on the ipinfodb.com webservice. It is the same as Jeroen Jacobs' gem, but uses the Curb gem, rather than Net::HTTP in order to avoid issues with DNS resolution ignoring timeout settings.
132
+ test_files:
133
+ - spec/api.yml.example
134
+ - spec/geo_ip_spec.rb
135
+ - spec/spec.opts
136
+ - spec/spec_helper.rb