ip_library 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.
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: []