iplogic 0.1.4 → 0.2.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/README.md +1 -1
- data/Rakefile +14 -8
- data/iplogic.gemspec +1 -1
- data/lib/iplogic.rb +1 -1
- data/lib/iplogic/cidr.rb +103 -18
- data/lib/iplogic/ip.rb +21 -15
- data/spec/cidr_spec.rb +56 -52
- data/spec/ip_spec.rb +28 -24
- data/spec/radix_spec.rb +4 -6
- data/spec/spec_helper.rb +1 -1
- metadata +28 -51
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -1,12 +1,18 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/testtask'
|
3
3
|
|
4
|
-
begin
|
5
|
-
|
6
|
-
|
7
|
-
t.spec_files = FileList['spec/**/*_spec.rb']
|
8
|
-
t.ruby_opts = ["-r spec/spec_helper.rb"]
|
9
|
-
end
|
10
|
-
rescue LoadError
|
11
|
-
#pass. rspec is not required
|
4
|
+
# begin
|
5
|
+
task :spec do
|
6
|
+
sh "rspec -I spec/ spec/*_spec.rb"
|
12
7
|
end
|
8
|
+
|
9
|
+
# require 'rspec/rake'
|
10
|
+
# Spec::Rake::SpecTask.new('spec') do |t|
|
11
|
+
# t.spec_files = FileList['spec/**/*_spec.rb']
|
12
|
+
# t.ruby_opts = ["-r spec/spec_helper.rb"]
|
13
|
+
# end
|
14
|
+
|
15
|
+
task :default => [:spec]
|
16
|
+
# rescue LoadError
|
17
|
+
# #pass. rspec is not required
|
18
|
+
# end
|
data/iplogic.gemspec
CHANGED
data/lib/iplogic.rb
CHANGED
data/lib/iplogic/cidr.rb
CHANGED
@@ -2,8 +2,38 @@ module IPLogic
|
|
2
2
|
class CIDR
|
3
3
|
include Enumerable
|
4
4
|
|
5
|
-
|
5
|
+
# raised if bad arguments are passed to CIDR.wrap
|
6
|
+
FormatError = Class.new(ArgumentError)
|
7
|
+
|
8
|
+
# matches a shortened CIDR: `xxx.xxx.xxx/xx`
|
9
|
+
SHORTENED_CIDR_REGEX = /^(\d{1,3}(\.\d{1,3}){1,3})\/(\d+)$/
|
10
|
+
|
6
11
|
class << self
|
12
|
+
# Where the magic happens.
|
13
|
+
# @raise FormatError
|
14
|
+
# @overload CIDR.wrap(cidr)
|
15
|
+
# @param [CIDR] cidr
|
16
|
+
# Returns the cidr. Useful for typecasting.
|
17
|
+
# @return [CIDR] a CIDR
|
18
|
+
# @overload CIDR.wrap(string)
|
19
|
+
# @param [String] string
|
20
|
+
# Parses `string` as a CIDR. The following formats are accepted:
|
21
|
+
#
|
22
|
+
# "#{partial_ip}/#{bits}":
|
23
|
+
# CIDR.wrap('11.22.33.44/16') # => #<CIDR[ 11.22.33.44/16 ]>
|
24
|
+
# CIDR.wrap('10.0.1/24') # => #<CIDR[ 10.0.1.0/24 ]>
|
25
|
+
#
|
26
|
+
# "#{partial_ip}/#{netmask}":
|
27
|
+
# CIDR.wrap('11.22.33.44/255.255.0.0') # => #<CIDR[ 11.22.33.44/16 ]>
|
28
|
+
# CIDR.wrap('10.0.1/255.255.255.0') # => #<CIDR[ 10.0.1.0/24 ]>
|
29
|
+
# @return [CIDR] a CIDR
|
30
|
+
# @overload CIDR.wrap(ip_ish, netmask_or_bits)
|
31
|
+
# @param [IP] ip_ish
|
32
|
+
# the address of the network. Will be passed through `IP.wrap`.
|
33
|
+
# @param [Fixnum IP] netmask_or_bits
|
34
|
+
# the netmask or the number of addressable bits
|
35
|
+
# (the thing after the / in standard CIDR notation)
|
36
|
+
#
|
7
37
|
def wrap(*args)
|
8
38
|
return args.first if args.first.is_a? CIDR
|
9
39
|
if args.size == 2
|
@@ -34,11 +64,11 @@ module IPLogic
|
|
34
64
|
# one argument means it's gotta be a string to parse
|
35
65
|
format_error(arg) unless arg.is_a? String
|
36
66
|
|
37
|
-
if arg =~
|
67
|
+
if arg =~ SHORTENED_CIDR_REGEX
|
38
68
|
new(parse_shortened_ip($1), $3)
|
39
|
-
elsif (
|
40
|
-
ip = parse_shortened_ip(
|
41
|
-
mask = IP.wrap(
|
69
|
+
elsif (octets = arg.split('/')).size == 2
|
70
|
+
ip = parse_shortened_ip(octets[0])
|
71
|
+
mask = IP.wrap(octets[1])
|
42
72
|
return new(ip, netmask_to_bits(mask))
|
43
73
|
else
|
44
74
|
format_error(arg)
|
@@ -46,6 +76,14 @@ module IPLogic
|
|
46
76
|
end
|
47
77
|
end
|
48
78
|
|
79
|
+
alias [] wrap
|
80
|
+
|
81
|
+
# @return a random CIDR
|
82
|
+
def rand
|
83
|
+
# both /32 and /0 are valid
|
84
|
+
wrap(IP.rand, Kernel.rand(33))
|
85
|
+
end
|
86
|
+
|
49
87
|
private
|
50
88
|
# helper for formats like 11.22.33/24
|
51
89
|
# just adds some .0's to the end
|
@@ -56,20 +94,34 @@ module IPLogic
|
|
56
94
|
|
57
95
|
def netmask_to_bits(netmask)
|
58
96
|
raise FormatError, "CIDR: #{netmask} is not a netmask" unless netmask.netmask?
|
59
|
-
|
60
|
-
|
61
|
-
netmask.to_i
|
62
|
-
|
97
|
+
|
98
|
+
maxint32 = 0xFFFFFFFF
|
99
|
+
t = 1 + (maxint32 - netmask.to_i)
|
100
|
+
|
101
|
+
# netmask.to_i.to_s(2) =~ /^(1*)0*$/
|
102
|
+
# $1.length
|
103
|
+
|
104
|
+
# poor man's log_2
|
105
|
+
res = -1
|
106
|
+
while t > 0
|
107
|
+
res += 1
|
108
|
+
t >>= 1
|
109
|
+
end
|
110
|
+
|
111
|
+
32 - res
|
63
112
|
end
|
64
113
|
|
65
|
-
FormatError = Class.new(ArgumentError)
|
66
114
|
def format_error(*args)
|
67
115
|
args = args.map { |a| a.inspect }.join(', ')
|
68
116
|
raise FormatError, "CIDR: unable to parse #{args}"
|
69
117
|
end
|
70
118
|
end
|
71
119
|
|
72
|
-
|
120
|
+
# @return [IP] the address of the network
|
121
|
+
attr_reader :ip
|
122
|
+
|
123
|
+
# @return [Fixnum] the /n value
|
124
|
+
attr_reader :bits
|
73
125
|
alias prefix_length bits
|
74
126
|
|
75
127
|
def initialize(ip, bits)
|
@@ -77,33 +129,47 @@ module IPLogic
|
|
77
129
|
@ip = IP.wrap(ip)
|
78
130
|
end
|
79
131
|
|
132
|
+
# CIDR of all possible IP addresses.
|
133
|
+
# Equivalent to `CIDR('0.0.0.0/0')`
|
80
134
|
ALL = self.new(0,0)
|
135
|
+
|
136
|
+
# Getter for CIDR::ALL
|
137
|
+
# @see ALL
|
81
138
|
def self.all
|
82
139
|
ALL
|
83
140
|
end
|
84
141
|
|
142
|
+
# The number of bits allocated to the network
|
85
143
|
def inv_bits
|
86
144
|
32 - bits
|
87
145
|
end
|
88
146
|
|
147
|
+
# @return [String] `#<CIDR [ 10.0.1.0/24 ]>`
|
89
148
|
def inspect
|
90
149
|
"#<CIDR [ #{self} ]>"
|
91
150
|
end
|
92
151
|
|
152
|
+
# the CIDR's netmask
|
153
|
+
# @return [IP] the netmask
|
93
154
|
def netmask
|
94
155
|
@netmask ||= IP.wrap(
|
95
156
|
((1 << bits) - 1) << (32 - bits)
|
96
157
|
)
|
97
158
|
end
|
98
159
|
|
160
|
+
# The number of addresses in the CIDR
|
99
161
|
def size
|
100
162
|
@size ||= (1 << inv_bits)
|
101
163
|
end
|
102
164
|
|
165
|
+
# Test whether an address is on the network
|
166
|
+
# @param [IP] ip_ish the IP-ish to test.
|
103
167
|
def include?(ip)
|
104
168
|
IP.wrap(ip).min(bits) == min
|
105
169
|
end
|
106
170
|
|
171
|
+
# the lowest address on the network
|
172
|
+
# @return [IP] the minimum address
|
107
173
|
def min
|
108
174
|
@min ||= IP.wrap(
|
109
175
|
(ip.to_i >> inv_bits) << inv_bits
|
@@ -113,38 +179,57 @@ module IPLogic
|
|
113
179
|
alias first min
|
114
180
|
alias prefix min
|
115
181
|
|
182
|
+
# the maximum address on the network
|
183
|
+
# @return [IP] the maximum address
|
116
184
|
def max
|
117
185
|
@max ||= min + (size - 1)
|
118
186
|
end
|
119
187
|
alias :end :max
|
120
188
|
alias last max
|
121
189
|
|
190
|
+
# the "rest" field is the part of the address after the
|
191
|
+
# netmask is applied.
|
192
|
+
# See RFC 791.
|
122
193
|
def rest_field
|
123
194
|
@rest_field ||= ip - min
|
124
195
|
end
|
125
196
|
alias rest rest_field
|
126
197
|
|
198
|
+
# The usual CIDR representation
|
127
199
|
def to_s
|
128
200
|
"#{ip}/#{bits}"
|
129
201
|
end
|
130
202
|
alias to_str to_s
|
131
203
|
|
204
|
+
# The number of significant octets in an address on this network.
|
205
|
+
#
|
206
|
+
# @example
|
207
|
+
# CIDR('0.0.0.0/0').significant_octets # => 4
|
208
|
+
# CIDR('10.0.0.0/8').significant_octets # => 3
|
209
|
+
# CIDR('10.10.0.0/16').significant_octets # => 2
|
210
|
+
# CIDR('10.10.0.0/20').significant_octets # => 2
|
211
|
+
# CIDR('10.10.0.0/24').significant_octets # => 1
|
212
|
+
# CIDR('10.10.0.1/32').significant_octets # => 0
|
132
213
|
def significant_octets
|
133
214
|
4 - (bits / 8)
|
134
215
|
end
|
135
216
|
|
217
|
+
# The smallest classful DNS zone that will capture the range.
|
218
|
+
# NB: may not be applicable to your DNS configs, see RFC 2317
|
219
|
+
# @example
|
220
|
+
# CIDR('10.0.1/24').zone # => "1.0.10"
|
221
|
+
# @return [String] the zone
|
136
222
|
def zone
|
137
|
-
ip.
|
223
|
+
ip.octets[0..-(1+significant_octets)].reverse.join('.')
|
138
224
|
end
|
139
225
|
|
226
|
+
# Iterates over every address in the CIDR.
|
227
|
+
# NB: this might be huge - 2**bits
|
228
|
+
# @yield [IP] an address in the CIDR
|
229
|
+
# @return [CIDR] self
|
140
230
|
def each(&blk)
|
141
231
|
(min..max).each(&blk)
|
232
|
+
self
|
142
233
|
end
|
143
234
|
end
|
144
|
-
|
145
|
-
def CIDR(*args)
|
146
|
-
return CIDR if args.empty?
|
147
|
-
|
148
|
-
CIDR.wrap(*args)
|
149
|
-
end
|
150
235
|
end
|
data/lib/iplogic/ip.rb
CHANGED
@@ -34,9 +34,9 @@ module IPLogic
|
|
34
34
|
|
35
35
|
int = case arg
|
36
36
|
when Array
|
37
|
-
|
37
|
+
octets_to_int(arg)
|
38
38
|
when String
|
39
|
-
|
39
|
+
octets_to_int(arg.split('.'))
|
40
40
|
when Fixnum
|
41
41
|
arg
|
42
42
|
when nil
|
@@ -45,16 +45,27 @@ module IPLogic
|
|
45
45
|
raise FormatError, "IP: Unable to parse #{arg.inspect}"
|
46
46
|
end
|
47
47
|
|
48
|
+
unless (0..0xFFFFFFFF).include? int
|
49
|
+
raise FormatError, "IP: Address #{arg.inspect} out of range"
|
50
|
+
end
|
51
|
+
|
48
52
|
return new(int)
|
49
53
|
end
|
50
54
|
|
55
|
+
alias [] wrap
|
56
|
+
|
51
57
|
FormatError = Class.new(ArgumentError)
|
52
58
|
|
59
|
+
# Return a random IP address. Useful for mocks / tests
|
60
|
+
def rand
|
61
|
+
wrap(Kernel.rand(0x100000000))
|
62
|
+
end
|
63
|
+
|
53
64
|
private
|
54
|
-
def
|
65
|
+
def octets_to_int(octets)
|
55
66
|
r = 0
|
56
|
-
|
57
|
-
r += (
|
67
|
+
octets.reverse.each_with_index do |octet, i|
|
68
|
+
r += (octet.to_i << 8*i)
|
58
69
|
end
|
59
70
|
r
|
60
71
|
end
|
@@ -65,7 +76,7 @@ module IPLogic
|
|
65
76
|
alias to_i int
|
66
77
|
alias to_int int
|
67
78
|
|
68
|
-
def initialize(int)
|
79
|
+
def initialize(int, extra={})
|
69
80
|
@int = int
|
70
81
|
end
|
71
82
|
|
@@ -75,17 +86,17 @@ module IPLogic
|
|
75
86
|
MAXIP
|
76
87
|
end
|
77
88
|
|
78
|
-
def
|
79
|
-
@
|
89
|
+
def octets
|
90
|
+
@octets ||= begin
|
80
91
|
rad = int.radix(256)
|
81
92
|
[0]*([4-rad.size,0].max) + rad
|
82
93
|
end
|
83
94
|
end
|
95
|
+
alias parts octets
|
84
96
|
|
85
97
|
def to_s
|
86
|
-
|
98
|
+
octets.join('.')
|
87
99
|
end
|
88
|
-
alias to_str to_s
|
89
100
|
|
90
101
|
def inspect
|
91
102
|
"#<IP [ #{self} ]>"
|
@@ -145,9 +156,4 @@ module IPLogic
|
|
145
156
|
msg
|
146
157
|
end
|
147
158
|
end
|
148
|
-
|
149
|
-
def IP(*args)
|
150
|
-
return IP if args.empty?
|
151
|
-
IP.wrap(args.first)
|
152
|
-
end
|
153
159
|
end
|
data/spec/cidr_spec.rb
CHANGED
@@ -2,27 +2,27 @@ require File.join(File.dirname(__FILE__), 'spec_helper')
|
|
2
2
|
|
3
3
|
describe CIDR do
|
4
4
|
it "parses an IP-ish and netmask-ish" do
|
5
|
-
r = CIDR
|
5
|
+
r = CIDR['4.33.222.111', '255.255.240.0']
|
6
6
|
r.should be_a CIDR
|
7
7
|
r.inspect.should include '4.33.222.111/20'
|
8
8
|
|
9
|
-
r = CIDR
|
9
|
+
r = CIDR[IP['4.33.222.111'], 20]
|
10
10
|
r.should be_a CIDR
|
11
11
|
r.inspect.should include '4.33.222.111/20'
|
12
12
|
|
13
|
-
r = CIDR
|
13
|
+
r = CIDR['4.33.222.111', IP['255.255.240.0']]
|
14
14
|
r.should be_a CIDR
|
15
15
|
r.inspect.should include '4.33.222.111/20'
|
16
16
|
end
|
17
17
|
|
18
18
|
it "parses slash notation" do
|
19
|
-
r = CIDR
|
19
|
+
r = CIDR['11.22.33.44/8']
|
20
20
|
r.should be_a CIDR
|
21
21
|
r.inspect.should include '11.22.33.44/8'
|
22
22
|
end
|
23
23
|
|
24
24
|
it "parses slash notation with a netmask" do
|
25
|
-
r = CIDR
|
25
|
+
r = CIDR['11.22.33.44/255.255.255.0']
|
26
26
|
r.ip.should be_a IP
|
27
27
|
r.ip.to_s.should == '11.22.33.44'
|
28
28
|
r.bits.should == 24
|
@@ -30,7 +30,7 @@ describe CIDR do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it "parses shortened slash notation" do
|
33
|
-
r = CIDR
|
33
|
+
r = CIDR['11.22.33/24']
|
34
34
|
r.ip.should be_a IP
|
35
35
|
r.ip.to_s.should == '11.22.33.0'
|
36
36
|
r.bits.should == 24
|
@@ -38,7 +38,7 @@ describe CIDR do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
it "parses shortened slash notation with a netmask" do
|
41
|
-
r = CIDR
|
41
|
+
r = CIDR['11.22/255.255.0.0']
|
42
42
|
r.ip.should be_a IP
|
43
43
|
r.ip.to_s.should == '11.22.0.0'
|
44
44
|
r.bits.should == 16
|
@@ -46,95 +46,99 @@ describe CIDR do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
it "supports wrapping" do
|
49
|
-
r = CIDR
|
50
|
-
wrapped = CIDR
|
49
|
+
r = CIDR['11.22.33.44/24']
|
50
|
+
wrapped = CIDR[r]
|
51
51
|
wrapped.should be_a CIDR
|
52
52
|
r.object_id.should == wrapped.object_id
|
53
53
|
end
|
54
54
|
|
55
|
+
it "fetches a random CIDR" do
|
56
|
+
CIDR.rand.should be_a CIDR
|
57
|
+
end
|
58
|
+
|
55
59
|
it "knows its bits" do
|
56
60
|
i = rand(33)
|
57
|
-
CIDR
|
61
|
+
CIDR["1.1.1.1/#{i}"].bits.
|
58
62
|
should == i
|
59
63
|
end
|
60
64
|
|
61
65
|
it "knows its ip" do
|
62
|
-
CIDR
|
63
|
-
should == IP
|
66
|
+
CIDR['11.22.33.44/20'].ip.
|
67
|
+
should == IP['11.22.33.44']
|
64
68
|
end
|
65
69
|
|
66
70
|
it "knows its netmask" do
|
67
|
-
CIDR
|
68
|
-
should == IP
|
71
|
+
CIDR['11.22.33.44/20'].netmask.
|
72
|
+
should == IP['255.255.240.0']
|
69
73
|
|
70
|
-
CIDR
|
71
|
-
should == IP
|
74
|
+
CIDR['11.22.33.44/8'].netmask.
|
75
|
+
should == IP['255.0.0.0']
|
72
76
|
|
73
|
-
CIDR
|
74
|
-
should == IP
|
77
|
+
CIDR['11.22.33.44/32'].netmask.
|
78
|
+
should == IP['255.255.255.255']
|
75
79
|
|
76
|
-
CIDR
|
77
|
-
should == IP
|
80
|
+
CIDR['1.1.1.1/0'].netmask.
|
81
|
+
should == IP['0.0.0.0']
|
78
82
|
end
|
79
83
|
|
80
84
|
it "knows its min" do
|
81
|
-
CIDR
|
82
|
-
should == IP
|
85
|
+
CIDR['11.22.33.44/20'].min.
|
86
|
+
should == IP['11.22.32.0']
|
83
87
|
|
84
|
-
CIDR
|
85
|
-
should == IP
|
88
|
+
CIDR['11.22.33.44/8'].min.
|
89
|
+
should == IP['11.0.0.0']
|
86
90
|
|
87
|
-
CIDR
|
88
|
-
should == IP
|
91
|
+
CIDR['11.22.33.44/32'].min.
|
92
|
+
should == IP['11.22.33.44']
|
89
93
|
|
90
|
-
CIDR
|
91
|
-
should == IP
|
94
|
+
CIDR['11.22.33.44/0'].min.
|
95
|
+
should == IP['0.0.0.0']
|
92
96
|
end
|
93
97
|
|
94
98
|
it "knows its max" do
|
95
|
-
CIDR
|
96
|
-
should == IP
|
99
|
+
CIDR['11.22.33.44/20'].max.
|
100
|
+
should == IP['11.22.47.255']
|
97
101
|
|
98
|
-
CIDR
|
99
|
-
should == IP
|
102
|
+
CIDR['11.22.33.44/8'].max.
|
103
|
+
should == IP['11.255.255.255']
|
100
104
|
|
101
|
-
CIDR
|
102
|
-
should == IP
|
105
|
+
CIDR['11.22.33.44/32'].max.
|
106
|
+
should == IP['11.22.33.44']
|
103
107
|
|
104
|
-
CIDR
|
105
|
-
should == IP
|
108
|
+
CIDR['11.22.33.44/0'].max.
|
109
|
+
should == IP['255.255.255.255']
|
106
110
|
end
|
107
111
|
|
108
112
|
it "knows its rest field" do
|
109
|
-
CIDR
|
110
|
-
should == IP
|
113
|
+
CIDR['11.22.33.44/20'].rest_field.
|
114
|
+
should == IP['0.0.1.44']
|
111
115
|
|
112
|
-
CIDR
|
113
|
-
should == IP
|
116
|
+
CIDR['11.22.33.44/8'].rest_field.
|
117
|
+
should == IP['0.22.33.44']
|
114
118
|
|
115
|
-
CIDR
|
116
|
-
should == IP
|
119
|
+
CIDR['11.22.33.44/32'].rest_field.
|
120
|
+
should == IP['0.0.0.0']
|
117
121
|
|
118
|
-
CIDR
|
119
|
-
should == IP
|
122
|
+
CIDR['11.22.33.44/0'].rest_field.
|
123
|
+
should == IP['11.22.33.44']
|
120
124
|
end
|
121
125
|
|
122
126
|
it "knows its size" do
|
123
|
-
CIDR
|
127
|
+
CIDR['11.22.33.44/20'].size.
|
124
128
|
should == 0x1000
|
125
129
|
|
126
|
-
CIDR
|
130
|
+
CIDR['11.22.33.44/8'].size.
|
127
131
|
should == 0x1000000
|
128
132
|
|
129
|
-
CIDR
|
133
|
+
CIDR['11.22.33.44/32'].size.
|
130
134
|
should == 1
|
131
135
|
|
132
|
-
CIDR
|
136
|
+
CIDR['11.22.33.44/0'].size.
|
133
137
|
should == 0x100000000
|
134
138
|
end
|
135
139
|
|
136
140
|
it "is enumerable" do
|
137
|
-
r = CIDR
|
141
|
+
r = CIDR['11.22.33.44/24']
|
138
142
|
r.should respond_to :each
|
139
143
|
CIDR.included_modules.should include Enumerable
|
140
144
|
|
@@ -146,11 +150,11 @@ describe CIDR do
|
|
146
150
|
end
|
147
151
|
|
148
152
|
it "tests inclusion" do
|
149
|
-
r = CIDR
|
153
|
+
r = CIDR['11.22.33.44/24']
|
150
154
|
r.should respond_to :include?
|
151
155
|
r.should include '11.22.33.0'
|
152
|
-
r.should include IP
|
153
|
-
r.should_not include IP
|
156
|
+
r.should include IP['11.22.33.255']
|
157
|
+
r.should_not include IP['11.22.32.44'].to_i
|
154
158
|
r.should_not include '11.22.34.44'
|
155
159
|
end
|
156
160
|
|
data/spec/ip_spec.rb
CHANGED
@@ -2,17 +2,17 @@ require File.join(File.dirname(__FILE__), 'spec_helper')
|
|
2
2
|
|
3
3
|
describe IP do
|
4
4
|
it "parses a string" do
|
5
|
-
ip = IP
|
5
|
+
ip = IP['11.22.33.44']
|
6
6
|
ip.should be_a IP
|
7
7
|
ip.inspect.should include '11.22.33.44'
|
8
8
|
end
|
9
9
|
|
10
10
|
it "parses an integer" do
|
11
|
-
ip = IP
|
11
|
+
ip = IP[255]
|
12
12
|
ip.should be_a IP
|
13
13
|
ip.inspect.should include '0.0.0.255'
|
14
14
|
|
15
|
-
ip = IP
|
15
|
+
ip = IP[0xA00A10FF]
|
16
16
|
ip.should be_a IP
|
17
17
|
ip.inspect.should include '160.10.16.255'
|
18
18
|
end
|
@@ -24,34 +24,34 @@ describe IP do
|
|
24
24
|
end
|
25
25
|
end.new
|
26
26
|
|
27
|
-
ip = IP
|
27
|
+
ip = IP[[7, '42', four, nil]]
|
28
28
|
ip.should be_a IP
|
29
29
|
ip.inspect.should include '7.42.4.0'
|
30
30
|
end
|
31
31
|
|
32
32
|
it "parses nil" do
|
33
|
-
ip = IP
|
33
|
+
ip = IP[nil]
|
34
34
|
ip.should be_a IP
|
35
35
|
ip.inspect.should include '0.0.0.0'
|
36
36
|
end
|
37
37
|
|
38
38
|
it "parses an IP" do
|
39
|
-
ip = IP
|
40
|
-
IP
|
41
|
-
IP
|
39
|
+
ip = IP['11.22.33.44']
|
40
|
+
IP[ip].should be_a IP
|
41
|
+
IP[ip].object_id.should == ip.object_id
|
42
42
|
end
|
43
43
|
|
44
44
|
it "knows its integer representation" do
|
45
45
|
i = rand(0xFFFFFFFF)
|
46
|
-
IP
|
46
|
+
IP[i].to_i.should == i
|
47
47
|
end
|
48
48
|
|
49
49
|
it "knows its string representation" do
|
50
|
-
IP
|
50
|
+
IP['11.22.33.44'].to_s.should == '11.22.33.44'
|
51
51
|
end
|
52
52
|
|
53
|
-
it "knows its
|
54
|
-
IP
|
53
|
+
it "knows its octets" do
|
54
|
+
IP['44.33.22.11'].octets.should == [44, 33, 22, 11]
|
55
55
|
end
|
56
56
|
|
57
57
|
it "knows the max" do
|
@@ -60,18 +60,22 @@ describe IP do
|
|
60
60
|
IP.max.to_s.should == '255.255.255.255'
|
61
61
|
end
|
62
62
|
|
63
|
+
it "fetches a random ip" do
|
64
|
+
IP.rand.should be_a IP
|
65
|
+
end
|
66
|
+
|
63
67
|
it "is comparable" do
|
64
68
|
IP.included_modules.should include Comparable
|
65
|
-
IP.public_methods.should include
|
69
|
+
IP.public_methods.should include :<=>
|
66
70
|
|
67
71
|
i1, i2 = rand(0xFFFFFFFF), rand(0xFFFFFFFF)
|
68
|
-
(IP
|
72
|
+
(IP[i1] <=> IP[i2]).should == (i1 <=> i2)
|
69
73
|
end
|
70
74
|
|
71
75
|
it "can add, subtract, and succ" do
|
72
76
|
i1, i2 = rand(0xFFFFFFF), rand(0xFFFFFFF)
|
73
|
-
ip1 = IP
|
74
|
-
ipsum = IP
|
77
|
+
ip1 = IP[i1]
|
78
|
+
ipsum = IP[i1] + i2
|
75
79
|
ipsum.should be_a IP
|
76
80
|
ipsum.to_i.should == i1 + i2
|
77
81
|
|
@@ -81,15 +85,15 @@ describe IP do
|
|
81
85
|
end
|
82
86
|
|
83
87
|
it "knows its prefix and rest field given a netmask" do
|
84
|
-
ip = IP
|
88
|
+
ip = IP['11.22.33.44']
|
85
89
|
|
86
|
-
ip.prefix('255.255.255.0').should == IP
|
87
|
-
ip.rest_field('255.255.255.0').should == IP
|
90
|
+
ip.prefix('255.255.255.0').should == IP['11.22.33.00']
|
91
|
+
ip.rest_field('255.255.255.0').should == IP['0.0.0.44']
|
88
92
|
(ip.prefix('255.255.255.0') + ip.rest_field('255.255.255.0')).
|
89
93
|
should == ip
|
90
94
|
|
91
|
-
ip.prefix('255.255.240.0').should == IP
|
92
|
-
ip.rest_field('255.255.240.0').should == IP
|
95
|
+
ip.prefix('255.255.240.0').should == IP['11.22.32.00']
|
96
|
+
ip.rest_field('255.255.240.0').should == IP['0.0.1.44']
|
93
97
|
(ip.prefix('255.255.240.0') + ip.rest_field('255.255.240.0')).
|
94
98
|
should == ip
|
95
99
|
end
|
@@ -97,10 +101,10 @@ describe IP do
|
|
97
101
|
it "knows whether it's a netmask" do
|
98
102
|
zero_bits = rand(32)
|
99
103
|
(0..32).each do |bits|
|
100
|
-
IP(
|
104
|
+
IP[(0xFFFFFFFF >> bits) << bits].should be_netmask
|
101
105
|
end
|
102
106
|
|
103
|
-
IP
|
104
|
-
IP
|
107
|
+
IP['1.2.3.4'].should_not be_netmask
|
108
|
+
IP['0.255.0.0'].should_not be_netmask
|
105
109
|
end
|
106
110
|
end
|
data/spec/radix_spec.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "Radix" do
|
4
|
-
|
5
|
-
|
6
|
-
@rad = 2 + rand(9)
|
7
|
-
end
|
4
|
+
let(:lim) { 50 + rand(100) }
|
5
|
+
let(:rad) { 2 + rand(9) }
|
8
6
|
|
9
7
|
it "calculates radix" do
|
10
|
-
(1
|
11
|
-
i.radix(
|
8
|
+
(1..lim).each do |i|
|
9
|
+
i.radix(rad).join.should == i.to_s(rad)
|
12
10
|
end
|
13
11
|
end
|
14
12
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,48 +1,35 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: iplogic
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 4
|
10
|
-
version: 0.1.4
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Jay Adkisson
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2010-11-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
22
15
|
name: rspec
|
23
|
-
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &12043080 !ruby/object:Gem::Requirement
|
25
17
|
none: false
|
26
|
-
requirements:
|
18
|
+
requirements:
|
27
19
|
- - ~>
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 1
|
32
|
-
- 0
|
33
|
-
version: "1.0"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.0'
|
34
22
|
type: :development
|
35
|
-
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *12043080
|
36
25
|
description: An IPv4 swiss-army chainsaw
|
37
26
|
email: jay@causes.com
|
38
27
|
executables: []
|
39
|
-
|
40
28
|
extensions: []
|
41
|
-
|
42
|
-
extra_rdoc_files:
|
29
|
+
extra_rdoc_files:
|
43
30
|
- LICENSE
|
44
31
|
- README.md
|
45
|
-
files:
|
32
|
+
files:
|
46
33
|
- Rakefile
|
47
34
|
- LICENSE
|
48
35
|
- README.md
|
@@ -56,41 +43,31 @@ files:
|
|
56
43
|
- spec/cidr_spec.rb
|
57
44
|
- spec/spec_helper.rb
|
58
45
|
- spec/radix_spec.rb
|
59
|
-
has_rdoc: true
|
60
46
|
homepage: http://github.com/causes/iplogic
|
61
47
|
licenses: []
|
62
|
-
|
63
48
|
post_install_message:
|
64
49
|
rdoc_options: []
|
65
|
-
|
66
|
-
require_paths:
|
50
|
+
require_paths:
|
67
51
|
- lib
|
68
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
53
|
none: false
|
70
|
-
requirements:
|
71
|
-
- -
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
|
74
|
-
|
75
|
-
- 0
|
76
|
-
version: "0"
|
77
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
59
|
none: false
|
79
|
-
requirements:
|
80
|
-
- -
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
|
83
|
-
segments:
|
84
|
-
- 0
|
85
|
-
version: "0"
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
86
64
|
requirements: []
|
87
|
-
|
88
65
|
rubyforge_project:
|
89
|
-
rubygems_version: 1.
|
66
|
+
rubygems_version: 1.8.11
|
90
67
|
signing_key:
|
91
68
|
specification_version: 3
|
92
69
|
summary: Because it's just a 32-bit integer.
|
93
|
-
test_files:
|
70
|
+
test_files:
|
94
71
|
- spec/ip_spec.rb
|
95
72
|
- spec/cidr_spec.rb
|
96
73
|
- spec/spec_helper.rb
|