ip_library 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ip_library.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 tumayun
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # IPLibrary
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'ip_library'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install ip_library
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,5 @@
1
+ 1
2
+ 16777472,16778239,福建,,
3
+ ========================
4
+ 14
5
+ 234881024,234883071,广东,,
@@ -0,0 +1,64 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/ip_library/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["tumayun"]
6
+ gem.email = ["tumayun.2010@gmail.com"]
7
+ gem.description = <<-DESCRIPT
8
+ IPLibrary
9
+ =========
10
+
11
+ 顾名思义,这是一个ip库
12
+
13
+ Example
14
+ =======
15
+
16
+ 本gem中已经带有ip库,默认是gem目录下doc/ip_libraries.txt
17
+ 默认ip库的格式以IPLibrary::Configuration.separator分组
18
+ 各组第一行为ip头(192.168.1.1的ip头为192),其他行各列以英文逗号隔开
19
+ 各列分别是:起始ip, 结束ip, 省份, 城市, 县区, 行政划分最小字段的拼音(如果有县区则为县区的拼音)
20
+
21
+ 当然,您也可以有自己的ip库
22
+ 设置ip库的path: IPLibrary::Configuration.file_path = '/home/doc/ip_libraries.txt'
23
+ 而且,您也可以设置ip库中的列的含义,start_ip、end_ip两列必须有,且必须依次为1、2列
24
+ 设置其他列:IPLibrary::Configuration.optional_columns = [:province, :city, :district, :pinyin]
25
+ 除了1、2列,其他列一次为province、city、district、pinyin
26
+ 然后会动态生成方法:
27
+ IPLibrary::Base#ip2province
28
+ IPLibrary::Base#ip2city
29
+ IPLibrary::Base#ip2district
30
+ IPLibrary::Base#ip2pinyin
31
+
32
+ =============================================
33
+
34
+ IPLibrary::Base 的方法有:
35
+
36
+ IPLibrary::Base.ip2province('123.132.254.134')
37
+ IPLibrary::Base.ip2province(2072313478)
38
+ #=> "山东"
39
+
40
+ IPLibrary::Base.ip2city('123.132.254.134')
41
+ IPLibrary::Base.ip2city(2072313478)
42
+ #=> "临沂"
43
+
44
+ IPLibrary::Base.ip2district('123.132.254.134')
45
+ IPLibrary::Base.ip2district(2072313478)
46
+ # => ""
47
+
48
+ IPLibrary::Base.ip2pinyin('123.132.254.134')
49
+ IPLibrary::Base.ip2pinyin(2072313478)
50
+ #=> "linyi"
51
+ DESCRIPT
52
+ gem.summary = %q{IPLibrary是一个ip库的gem,它能通过类似ip2city等方法得到ip所在城市}
53
+ gem.homepage = 'https://github.com/tumayun/ip_library'
54
+
55
+ #gem.files = `git ls-files`.split($\)
56
+ gem.files = %w(Gemfile ip_library.gemspec LICENSE Rakefile README.md)
57
+ gem.files += Dir.glob("lib/**/*")
58
+ gem.files += Dir.glob("doc/**/*")
59
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
60
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
61
+ gem.name = "ip_library"
62
+ gem.require_paths = ["lib"]
63
+ gem.version = IPLibrary::VERSION
64
+ end
@@ -0,0 +1,3 @@
1
+ module IPLibrary
2
+ Dir["#{File.dirname(__FILE__)}/ip_library/*.rb"].each { |ext| require ext }
3
+ end
@@ -0,0 +1,90 @@
1
+ #encoding: utf-8
2
+ module IPLibrary
3
+
4
+ class Configuration
5
+ cattr_accessor :file_path, :optional_columns, :separator, :except_regexp, :instance_writer => false
6
+ cattr_reader :non_optional_columns, :columns
7
+
8
+ @@file_path = File.join(File.dirname(__FILE__), '..', '..', 'doc', 'ip_libraries.txt') #"#{File.dirname(__FILE__)}/../../doc/ip_libraries.txt"
9
+ @@optional_columns = [:province, :city, :district]
10
+ @@non_optional_columns = [:start_ip, :end_ip]
11
+ @@columns = @@non_optional_columns + @@optional_columns
12
+ @@except_regexp = /[a-zA-Z0-9]?(全国|中国|全省各市|\(.*\))?/
13
+ @@separator = "========================\n"
14
+
15
+ def self.optional_columns=(other)
16
+ Base.undef_class_methods(@@optional_columns)
17
+ @@optional_columns = other
18
+ @@columns = @@non_optional_columns + @@optional_columns
19
+ Base.defined_class_methods
20
+ @@optional_columns
21
+ end
22
+ end
23
+
24
+ class Base
25
+
26
+ class << self
27
+ def ip_cities(force_reload = false)
28
+ return @@ip_cities if !force_reload && defined?(@@ip_cities) && @@ip_cities.present?
29
+
30
+ @@ip_cities = {}
31
+ File.open(Configuration.file_path, 'r') do |file|
32
+ datas = file.to_a.split(Configuration.separator)
33
+ datas.each do |data|
34
+ header = data.delete_at(0).chomp
35
+ data.each do |row|
36
+ ip_city = row.chomp.split(',')
37
+ @@ip_cities[header] ||= []
38
+ @@ip_cities[header] << ip_city
39
+ end
40
+ end
41
+ end
42
+ @@ip_cities
43
+ end
44
+
45
+ def find_by_ip(ip)
46
+ header, ip = get_header_and_ip(ip)
47
+ ip_cities = Base.ip_cities[header]
48
+ return nil if ip_cities.blank?
49
+
50
+ ip_cities = ip_cities.select { |ip_city| ip_city[0].to_i <= ip && ip_city[1].to_i >= ip }
51
+ ip_cities.sort_by { |ip_city| ip_city[1].to_i - ip_city[0].to_i }.first if ip_cities.present?
52
+ end
53
+
54
+ def defined_class_methods
55
+ Configuration.columns.each_with_index do |col, index|
56
+ next if Configuration.non_optional_columns.include?(col)
57
+ instance_eval(<<-METHOD, __FILE__, __LINE__ + 1)
58
+ def ip2#{col.to_s}(ip)
59
+ find_by_ip(ip).try(:[], #{index})
60
+ end
61
+ METHOD
62
+ end
63
+ end
64
+
65
+ def undef_class_methods(symbols)
66
+ symbols.each do |symbol|
67
+ singleton.send :undef_method, "ip2#{symbol.to_s}".to_sym
68
+ end
69
+ end
70
+
71
+ def singleton
72
+ class << Base; self; end
73
+ end
74
+
75
+ protected
76
+ def get_header_and_ip(ip)
77
+ case ip
78
+ when Integer
79
+ [ip.to_ip.split('.').first, ip]
80
+ when String
81
+ [ip.split('.').first, ip.to_s.to_int_ip]
82
+ else
83
+ raise ArgumentError, 'Parameters can only be Integer and String'
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ IPLibrary::Base.defined_class_methods
@@ -0,0 +1,162 @@
1
+ #encoding: utf-8
2
+ require 'csv'
3
+ module IPLibrary
4
+
5
+ class Data
6
+ TITLES = %w(start_ip end_ip province city district area_name_py start_ip1 end_ip1)
7
+ MUNICIPALITIES = %w(北京 上海 天津 重庆)
8
+ DISTRICT_REGEXP = /(自治县|自治旗|特区|林区|县|区|旗)$/
9
+ CITY_REGEXP = /(自治州|地区|市|州|盟)$/
10
+ PROVINCE_REGEXP = /(省|自治区|特别行政区)$/
11
+
12
+ class << self
13
+
14
+ def generate_txt(infile_path, outfile_path = nil)
15
+ outfile_path ||= "#{Rails.root}/doc/#{Time.now.strftime('%y%m%d%H%M%S')}_ip_libraries.txt"
16
+ raise ArgumentError, '请出入正确的文件路径!' unless File.file?(infile_path) || File.extname(infile_path) != '.txt'
17
+
18
+ puts '正在生成txt文件'
19
+ File.open(outfile_path, 'w') do |file|
20
+ ip_cities = load_csv(infile_path).sort_by { |row| row[TITLES.index('start_ip')].to_i }
21
+ ip_cities = ip_cities.group_by { |row| row[TITLES.index('start_ip1')].split('.').first }
22
+ length = ip_cities.keys.size
23
+ index = 0
24
+ ip_cities.each do |key, value|
25
+ index += 1
26
+ file.write("#{key}\n")
27
+ value.each do |v|
28
+ file.write("#{v[0..4].join(',')}\n")
29
+ end
30
+ file.write("#{Configuration.separator}") if length != index
31
+ end
32
+ end
33
+ puts "已经生成txt文件:#{outfile_path}"
34
+ end
35
+
36
+ def generate_custom_ip_library(areas, outfile_path = nil, infile_path = nil)
37
+ infile_path ||= Configuration.file_path
38
+ outfile_path ||= File.join(Rails.root, 'doc', 'custom_ip_libraries.txt')
39
+ ip_city_ids = get_ip_city_ids(areas)
40
+
41
+ writer = []
42
+ File.open(infile_path, 'r') do |file|
43
+ file.each_line do |line|
44
+ if (cols = line.split(',')).size == 5 && ip_city_ids[cols[2]].present? && (city_id = (ip_city_ids[cols[2]][cols[3]] || ip_city_ids[cols[2]][cols[4]])).present?
45
+ writer << "#{cols[0]},#{cols[1]},#{city_id}\n"
46
+ elsif cols.size != 5
47
+ writer << cols.join(',')
48
+ end
49
+ end
50
+ end
51
+
52
+ puts "正在生成#{outfile_path}"
53
+ File.open(outfile_path, 'w') do |file|
54
+ writer.each do |line|
55
+ file.write line
56
+ end
57
+ end
58
+ puts '生成完毕'
59
+ end
60
+
61
+ private
62
+ def get_ip_city_ids(areas)
63
+ ip_city_ids = {}
64
+ ip_datas = Base.ip_cities.values.flatten(1).select { |t| t[2].present? && (t[3].present? || t[4].present?) }
65
+
66
+ size = ip_datas.size
67
+ ip_datas.each_with_index do |ip_city, index|
68
+ pp "------------------#{index + 1}/#{size}--------------------"
69
+ if ip_city[2].present?
70
+ ip_city_ids[ip_city[2]] ||= {}
71
+
72
+ if ip_city_ids[ip_city[2]][ip_city[3]].blank? && ip_city[3].present?
73
+ areas.each do |t|
74
+ if t['province'] =~ %r{#{ip_city[2]}} && t['city'] =~ %r{#{ip_city[3]}}
75
+ ip_city_ids[ip_city[2]][ip_city[3]] = t['city_id'] and break
76
+ end
77
+ end
78
+ unless ip_city_ids[ip_city[2]][ip_city[3]].present?
79
+ areas.each do |t|
80
+ if t['province'] =~ %r{#{ip_city[2]}} && t['district'] =~ %r{#{ip_city[3]}}
81
+ ip_city_ids[ip_city[2]][ip_city[3]] = t['city_id'] and break
82
+ end
83
+ end
84
+ end
85
+ elsif ip_city_ids[ip_city[2]][ip_city[4]].blank? && ip_city[3].blank? && ip_city[4].present?
86
+ areas.each do |t|
87
+ if t['province'] =~ %r{#{ip_city[2]}} && t['district'] =~ %r{#{ip_city[4]}}
88
+ ip_city_ids[ip_city[2]][ip_city[4]] = t['city_id'] and break
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ ip_city_ids
96
+ end
97
+
98
+ def get_areas(province, city)
99
+ if province =~ /北京|上海|天津|重庆/
100
+ province.sub!(CITY_REGEXP, '')
101
+ if city.blank?
102
+ [nil, province, nil]
103
+ elsif city =~ DISTRICT_REGEXP
104
+ [nil, province, city]
105
+ end
106
+ elsif city.blank?
107
+ province.sub!(PROVINCE_REGEXP, '')
108
+ [province, nil, nil]
109
+ elsif city =~ CITY_REGEXP
110
+ province.sub!(PROVINCE_REGEXP, '')
111
+ city.sub!(CITY_REGEXP, '')
112
+ [province, city, nil]
113
+ elsif city =~ DISTRICT_REGEXP
114
+ province.sub!(PROVINCE_REGEXP, '')
115
+ [province, nil, city]
116
+ end
117
+ end
118
+
119
+ def get_areas_array(province, city)
120
+ if province =~ /\//
121
+ province.split('/').inject([]) do |result, p|
122
+ result << get_areas(p, city)
123
+ end
124
+ elsif city =~ /\//
125
+ city.split('/').inject([]) do |result, c|
126
+ result << get_areas(province, c)
127
+ end
128
+ else
129
+ [get_areas(province, city)]
130
+ end
131
+ end
132
+
133
+ def load_csv(path)
134
+ raise ArgumentError, '请出入正确的文件路径!' unless File.file?(path) || File.extname(path) != '.csv'
135
+
136
+ index = -1
137
+ col_index = {}
138
+ writer = []
139
+
140
+ CSV.foreach(path) do |row|
141
+ index += 1
142
+ GC.start if index % 100 == 0
143
+ if index == 0
144
+ (TITLES - ['district', 'area_name_py']).each do |col|
145
+ col_index[col.to_sym] = row.index(col)
146
+ end
147
+ raise "csv文件内容格式不正确,必须有#{(TITLES - ['district', 'area_name_py']).join(', ')}等字段" if col_index.values.include?(nil)
148
+ next
149
+ end
150
+
151
+ province = row[col_index[:province]].to_s.gsub(Configuration.except_regexp, '')
152
+ city = row[col_index[:city]].to_s.gsub(Configuration.except_regexp, '')
153
+ get_areas_array(province, city).each do |area|
154
+ puts [row[col_index[:start_ip]], row[col_index[:end_ip]], area].flatten and next if area.blank?
155
+ writer << [row[col_index[:start_ip]], row[col_index[:end_ip]], area, row[col_index[:start_ip1]], row[col_index[:end_ip1]]].flatten
156
+ end
157
+ end
158
+ writer
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,6 @@
1
+ class Integer
2
+
3
+ def to_ip
4
+ IPLibrary::IP2integer.int2ip(self)
5
+ end
6
+ end
@@ -0,0 +1,25 @@
1
+ module IPLibrary
2
+
3
+ module IP2integer
4
+
5
+ IP_REGEXP = /^(?:(?:2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(?:2[0-4]\d|25[0-5]|[01]?\d\d?)$/
6
+ IP_PERFIX_REGEXP = /^(?:(?:2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}$/
7
+
8
+ class << self
9
+
10
+ # Converts an IP string to integer
11
+ def ip2int(ip)
12
+ return 0 unless ip =~ IP_REGEXP
13
+ ip_segments = []
14
+ ip.split('.').each_with_index { |ip_seg, i| ip_segments << (ip_seg.to_i << 8*(3 - i)) }
15
+ ip_segments.inject(0) { |sum, ip_segment| sum = sum|ip_segment }
16
+ end
17
+
18
+ #Converts an INTEGER to IP string
19
+ def int2ip(intip)
20
+ ip_segments = [3, 2, 1, 0].map { |i| (intip & (255 << i*8)) >> i*8 }
21
+ (ip_str= ip_segments.join('.')) =~ IP_REGEXP ? ip_str : ''
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,6 @@
1
+ class String
2
+
3
+ def to_int_ip
4
+ IPLibrary::IP2integer.ip2int(self)
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module IPLibrary
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ip_library
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - tumayun
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-06 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! 'IPLibrary
15
+
16
+ =========
17
+
18
+
19
+ 顾名思义,这是一个ip库
20
+
21
+
22
+ Example
23
+
24
+ =======
25
+
26
+
27
+ 本gem中已经带有ip库,默认是gem目录下doc/ip_libraries.txt
28
+
29
+ 默认ip库的格式以IPLibrary::Configuration.separator分组
30
+
31
+ 各组第一行为ip头(192.168.1.1的ip头为192),其他行各列以英文逗号隔开
32
+
33
+ 各列分别是:起始ip, 结束ip, 省份, 城市, 县区, 行政划分最小字段的拼音(如果有县区则为县区的拼音)
34
+
35
+
36
+ 当然,您也可以有自己的ip库
37
+
38
+ 设置ip库的path: IPLibrary::Configuration.file_path = ''/home/doc/ip_libraries.txt''
39
+
40
+ 而且,您也可以设置ip库中的列的含义,start_ip、end_ip两列必须有,且必须依次为1、2列
41
+
42
+ 设置其他列:IPLibrary::Configuration.optional_columns = [:province, :city, :district,
43
+ :pinyin]
44
+
45
+ 除了1、2列,其他列一次为province、city、district、pinyin
46
+
47
+ 然后会动态生成方法:
48
+
49
+ IPLibrary::Base#ip2province
50
+
51
+ IPLibrary::Base#ip2city
52
+
53
+ IPLibrary::Base#ip2district
54
+
55
+ IPLibrary::Base#ip2pinyin
56
+
57
+
58
+ =============================================
59
+
60
+
61
+ IPLibrary::Base 的方法有:
62
+
63
+
64
+ IPLibrary::Base.ip2province(''123.132.254.134'')
65
+
66
+ IPLibrary::Base.ip2province(2072313478)
67
+
68
+ #=> "山东"
69
+
70
+
71
+ IPLibrary::Base.ip2city(''123.132.254.134'')
72
+
73
+ IPLibrary::Base.ip2city(2072313478)
74
+
75
+ #=> "临沂"
76
+
77
+
78
+ IPLibrary::Base.ip2district(''123.132.254.134'')
79
+
80
+ IPLibrary::Base.ip2district(2072313478)
81
+
82
+ # => ""
83
+
84
+
85
+ IPLibrary::Base.ip2pinyin(''123.132.254.134'')
86
+
87
+ IPLibrary::Base.ip2pinyin(2072313478)
88
+
89
+ #=> "linyi"
90
+
91
+ '
92
+ email:
93
+ - tumayun.2010@gmail.com
94
+ executables: []
95
+ extensions: []
96
+ extra_rdoc_files: []
97
+ files:
98
+ - Gemfile
99
+ - ip_library.gemspec
100
+ - LICENSE
101
+ - Rakefile
102
+ - README.md
103
+ - lib/ip_library.rb
104
+ - lib/ip_library/version.rb
105
+ - lib/ip_library/base.rb
106
+ - lib/ip_library/data.rb
107
+ - lib/ip_library/integer.rb
108
+ - lib/ip_library/ip2integer.rb
109
+ - lib/ip_library/string.rb
110
+ - doc/ip_libraries.txt
111
+ homepage: https://github.com/tumayun/ip_library
112
+ licenses: []
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ! '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 1.8.24
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: IPLibrary是一个ip库的gem,它能通过类似ip2city等方法得到ip所在城市
135
+ test_files: []