ffi-geoip 0.0.1

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.
@@ -0,0 +1,68 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ module Base
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ def release(ptr)
11
+ FFIGeoIP.GeoIP_delete(ptr)
12
+ end
13
+ end
14
+
15
+ def value_to_addr(value)
16
+ case value
17
+ when Numeric
18
+ GeoIP.num_to_addr(value)
19
+
20
+ when /^\d+\.\d+\.\d+\.\d+$/
21
+ value
22
+ end
23
+ end
24
+
25
+ private
26
+ def initialize_geoip(file, load_option = nil, check_cache = nil)
27
+ if load_option.nil?
28
+ load_option = :memory
29
+ end
30
+
31
+ flags = check_load_option(load_option) or
32
+ raise TypeError.new("the second option must be :memory, :filesystem, or :index")
33
+
34
+ if check_cache
35
+ flags |= GeoIPOptions[:check_cache]
36
+ end
37
+
38
+ if !File.exists?(file)
39
+ raise enoent_exception
40
+ else
41
+ @ptr = FFI::AutoPointer.new(
42
+ FFIGeoIP.GeoIP_open(file, flags),
43
+ self.class.method(:release)
44
+ )
45
+
46
+ if @ptr.null?
47
+ raise_enoent
48
+ end
49
+ end
50
+ end
51
+
52
+ def enoent_exception
53
+ Errno::ENOENT.new("Problem opening database")
54
+ end
55
+
56
+ def check_load_option(load_option)
57
+ case load_option
58
+ when :memory
59
+ GeoIP::GeoIPOptions[:memory_cache]
60
+ when :filesystem
61
+ GeoIP::GeoIPOptions[:standard]
62
+ when :index
63
+ GeoIP::GeoIPOptions[:index_cache]
64
+ end
65
+ end
66
+ end
67
+ end
68
+
@@ -0,0 +1,26 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ class City
5
+ include GeoIP::Base
6
+ include GeoIP::Tools
7
+
8
+ def initialize(*args)
9
+ initialize_geoip(*args)
10
+ end
11
+
12
+ def look_up(addr)
13
+ addr = value_to_addr(addr)
14
+ check_type(addr, String)
15
+
16
+ record = Record.new(FFIGeoIP.GeoIP_record_by_addr(@ptr, addr))
17
+
18
+ if !record.null?
19
+ hash = record.to_h
20
+ FFIGeoIP.GeoIPRecord_delete(record)
21
+ hash
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ class Country
5
+ include GeoIP::Base
6
+ include GeoIP::Tools
7
+
8
+ def initialize(*args)
9
+ initialize_geoip(*args)
10
+ end
11
+
12
+ def look_up(addr)
13
+ addr = value_to_addr(addr)
14
+ check_type(addr, String)
15
+
16
+ fix_encoding(
17
+ :country_code => FFIGeoIP.GeoIP_country_code_by_addr(@ptr, addr),
18
+ :country_code3 => FFIGeoIP.GeoIP_country_code3_by_addr(@ptr, addr),
19
+ :country_name => FFIGeoIP.GeoIP_country_name_by_addr(@ptr, addr)
20
+ )
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ class ISP
5
+ include GeoIP::Base
6
+ include GeoIP::Tools
7
+
8
+ def initialize(*args)
9
+ initialize_geoip(*args)
10
+ end
11
+
12
+ def look_up(addr)
13
+ addr = value_to_addr(addr)
14
+ check_type(addr, String)
15
+
16
+ fix_encoding(:isp => FFIGeoIP.GeoIP_name_by_addr(@ptr, addr))
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ class Organization
5
+ include GeoIP::Base
6
+ include GeoIP::Tools
7
+
8
+ def initialize(*args)
9
+ initialize_geoip(*args)
10
+ end
11
+
12
+ def look_up(addr)
13
+ addr = value_to_addr(addr)
14
+ check_type(addr, String)
15
+
16
+ fix_encoding(:name => FFIGeoIP.GeoIP_name_by_addr(@ptr, addr))
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,53 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ class Record < FFI::Struct
5
+ include Tools
6
+
7
+ layout(
8
+ :country_code, :string,
9
+ :country_code3, :string,
10
+ :country_name, :string,
11
+ :region, :string,
12
+ :city, :string,
13
+ :postal_code, :string,
14
+ :latitude, :float,
15
+ :longitude, :float,
16
+ :dma_code, :int,
17
+ :area_code, :int,
18
+ :charset, :int,
19
+ :continent_code, :string,
20
+ :country_conf, :uchar,
21
+ :region_conf, :uchar,
22
+ :city_conf, :uchar,
23
+ :postal_conf, :uchar,
24
+ :accuracy_radius, :int
25
+ )
26
+
27
+ HASH_KEYS = [
28
+ :country_code,
29
+ :country_code3,
30
+ :country_name,
31
+ :region,
32
+ :city,
33
+ :postal_code,
34
+ :latitude,
35
+ :longitude,
36
+ :dma_code,
37
+ :area_code
38
+ ].freeze
39
+
40
+ def to_h
41
+ hash = HASH_KEYS.each_with_object({}) do |key, memo|
42
+ memo[key] = self[key] unless self[key].nil?
43
+ end
44
+
45
+ if self[:region]
46
+ hash[:region_name] = FFIGeoIP.GeoIP_region_name_by_code(self[:country_code], self[:region])
47
+ end
48
+
49
+ fix_encoding(hash)
50
+ end
51
+ end
52
+ end
53
+
@@ -0,0 +1,26 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ module Tools
5
+ private
6
+ def check_enum_value(enum, value)
7
+ enum[value] or
8
+ raise TypeError.new("Couldn't find valid #{enum.tag} value: #{value}")
9
+ end
10
+
11
+ def check_type(value, *types)
12
+ if !types.include?(value.class)
13
+ type_names = types.collect(&:name).join(' or ')
14
+
15
+ raise TypeError.new("wrong argument type #{value.class.name} (expected #{type_names})")
16
+ end
17
+ end
18
+
19
+ def fix_encoding(hash)
20
+ hash.each do |_, value|
21
+ value.encode!('UTF-8', 'ISO-8859-1') if value.is_a?(String)
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,6 @@
1
+ # encoding: UTF-8
2
+
3
+ module GeoIP
4
+ VERSION = "0.0.1"
5
+ end
6
+
@@ -0,0 +1,77 @@
1
+ # encoding: UTF-8
2
+
3
+ $: << File.dirname(__FILE__)
4
+ require 'test_helper'
5
+
6
+ class GeoIPCityTest < Minitest::Test
7
+ PITTSBURGH = {
8
+ :country_code => "US",
9
+ :country_code3 => "USA",
10
+ :country_name => "United States",
11
+ :region => "PA",
12
+ :city => "Pittsburgh",
13
+ :latitude => 40.44060134887695,
14
+ :longitude => -79.99590301513672,
15
+ :dma_code => 508,
16
+ :area_code => 412,
17
+ :region_name => "Pennsylvania"
18
+ }
19
+
20
+ PITTSBURGH_IP = '12.87.118.0'
21
+
22
+ def assert_look_up(db, expected = PITTSBURGH, lookup = PITTSBURGH_IP)
23
+ hash = db.look_up(lookup)
24
+ assert_kind_of(Hash, hash)
25
+ assert_equal(expected, hash)
26
+ end
27
+
28
+ def assert_raises_type_error(db)
29
+ assert_raises(TypeError) do
30
+ db.look_up(nil)
31
+ end
32
+ end
33
+
34
+ def test_construction_default
35
+ db = GeoIP::City.new(CITY_DB)
36
+ assert_raises_type_error(db)
37
+ assert_look_up(db)
38
+ end
39
+
40
+ def test_construction_index
41
+ db = GeoIP::City.new(CITY_DB, :index)
42
+ assert_raises_type_error(db)
43
+ assert_look_up(db)
44
+ end
45
+
46
+ def test_construction_filesystem
47
+ db = GeoIP::City.new(CITY_DB, :filesystem)
48
+ assert_raises_type_error(db)
49
+ assert_look_up(db)
50
+ end
51
+
52
+ def test_construction_memory
53
+ db = GeoIP::City.new(CITY_DB, :memory)
54
+ assert_raises_type_error(db)
55
+ assert_look_up(db)
56
+ end
57
+
58
+ def test_construction_filesystem_check
59
+ db = GeoIP::City.new(CITY_DB, :filesystem, true)
60
+ assert_raises_type_error(db)
61
+ assert_look_up(db)
62
+ end
63
+
64
+ def test_bad_db_file
65
+ assert_raises(Errno::ENOENT) do
66
+ GeoIP::City.new('/supposed-to-fail')
67
+ end
68
+ end
69
+
70
+ def test_character_encoding_converted_to_utf8_first
71
+ db = GeoIP::City.new(CITY_DB, :filesystem, true)
72
+ hash = db.look_up('89.160.20.112')
73
+ assert_equal('UTF-8', hash[:city].encoding.to_s)
74
+ assert_equal('Linköping', hash[:city])
75
+ end
76
+ end
77
+
@@ -0,0 +1,51 @@
1
+ # encoding: UTF-8
2
+
3
+ $: << File.dirname(__FILE__)
4
+ require 'test_helper'
5
+
6
+ class GeoIPCountryTest < Minitest::Test
7
+ UNITED_STATES = {
8
+ :country_code => "US",
9
+ :country_code3 => "USA",
10
+ :country_name => "United States"
11
+ }
12
+
13
+ UNITED_STATES_IP = '12.87.118.0'
14
+
15
+ def assert_look_up(db, expected = UNITED_STATES, lookup = UNITED_STATES_IP)
16
+ hash = db.look_up(lookup)
17
+ assert_kind_of(Hash, hash)
18
+ assert_equal(expected, hash)
19
+ end
20
+
21
+ def test_construction_default
22
+ db = GeoIP::Country.new(COUNTRY_DB)
23
+ assert_raises_type_error(db)
24
+ assert_look_up(db)
25
+ end
26
+
27
+ def test_construction_filesystem
28
+ db = GeoIP::Country.new(COUNTRY_DB, :filesystem)
29
+ assert_raises_type_error(db)
30
+ assert_look_up(db)
31
+ end
32
+
33
+ def test_construction_memory
34
+ db = GeoIP::Country.new(COUNTRY_DB, :memory)
35
+ assert_raises_type_error(db)
36
+ assert_look_up(db)
37
+ end
38
+
39
+ def test_construction_filesystem_check
40
+ db = GeoIP::Country.new(COUNTRY_DB, :filesystem, true)
41
+ assert_raises_type_error(db)
42
+ assert_look_up(db)
43
+ end
44
+
45
+ def test_bad_db_file
46
+ assert_raises(Errno::ENOENT) do
47
+ GeoIP::Country.new('/supposed-to-fail')
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,50 @@
1
+ # encoding: UTF-8
2
+
3
+ $: << File.dirname(__FILE__)
4
+ require 'test_helper'
5
+
6
+ class GeoIPTest < Minitest::Test
7
+ def setup
8
+ @ip = "24.24.24.24"
9
+ @ipnum = 16777216 * 24 + 65536 * 24 + 256 * 24 + 24
10
+
11
+ @large_ip = "245.245.245.245"
12
+ @large_ipnum = 16777216 * 245 + 65536 * 245 + 256 * 245 + 245
13
+ end
14
+
15
+ def test_addr_to_num_converts_an_ip_to_an_ipnum
16
+ assert_equal @ipnum, GeoIP.addr_to_num(@ip)
17
+ end
18
+
19
+ def test_addr_to_num_converts_large_ips_to_an_ipnum_correctly
20
+ assert_equal @large_ipnum, GeoIP.addr_to_num(@large_ip)
21
+ end
22
+
23
+ def test_addr_to_num_expects_an_ip_string
24
+ assert_raises TypeError do
25
+ GeoIP.addr_to_num(nil)
26
+ end
27
+ end
28
+
29
+ def test_addr_to_num_returns_zero_for_an_illformed_ip_string
30
+ assert_equal 0, GeoIP.addr_to_num("foo.bar")
31
+ end
32
+
33
+ def test_num_to_addr_converts_an_ipnum_to_an_ip
34
+ assert_equal @ip, GeoIP.num_to_addr(@ipnum)
35
+ end
36
+
37
+ def test_num_to_addr_converts_large_ipnums_to_an_ip_correctly
38
+ assert_equal @large_ip, GeoIP.num_to_addr(@large_ipnum)
39
+ end
40
+
41
+ def test_num_to_addr_expects_a_numeric_ip
42
+ assert_raises TypeError do
43
+ GeoIP.num_to_addr(nil)
44
+ end
45
+ assert_raises TypeError do
46
+ GeoIP.num_to_addr("foo.bar")
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,54 @@
1
+ # encoding: UTF-8
2
+
3
+ $: << File.dirname(__FILE__)
4
+ require 'test_helper'
5
+
6
+ class GeoIPISPTest < Minitest::Test
7
+ ISP = {
8
+ :isp => "AT&T Services"
9
+ }
10
+
11
+ ISP_IP = '12.87.118.0'
12
+
13
+ def assert_look_up(db, expected = ISP, lookup = ISP_IP)
14
+ hash = db.look_up(lookup)
15
+ assert_kind_of(Hash, hash)
16
+ assert_equal(expected, hash)
17
+ end
18
+
19
+ def test_construction_default
20
+ db = GeoIP::ISP.new(ISP_DB)
21
+ assert_raises_type_error(db)
22
+ assert_look_up(db)
23
+ end
24
+
25
+ # def test_construction_index
26
+ # db = GeoIP::ISP.new(ISP_DB, :index)
27
+ # assert_look_up(db, ISP_IP, :isp, 'Bell Aliant')
28
+ # end
29
+
30
+ def test_construction_filesystem
31
+ db = GeoIP::ISP.new(ISP_DB, :filesystem)
32
+ assert_raises_type_error(db)
33
+ assert_look_up(db)
34
+ end
35
+
36
+ def test_construction_memory
37
+ db = GeoIP::ISP.new(ISP_DB, :memory)
38
+ assert_raises_type_error(db)
39
+ assert_look_up(db)
40
+ end
41
+
42
+ def test_construction_filesystem_check
43
+ db = GeoIP::ISP.new(ISP_DB, :filesystem, true)
44
+ assert_raises_type_error(db)
45
+ assert_look_up(db)
46
+ end
47
+
48
+ def test_bad_db_file
49
+ assert_raises Errno::ENOENT do
50
+ GeoIP::ISP.new('/supposed-to-fail')
51
+ end
52
+ end
53
+ end
54
+