ipaddress 0.5.0 → 0.6.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/Rakefile CHANGED
@@ -1,8 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
3
  require 'rake/clean'
4
- require 'rcov/rcovtask'
5
-
6
4
 
7
5
  begin
8
6
  require 'jeweler'
@@ -12,9 +10,13 @@ begin
12
10
  gem.email = "ceresa@gmail.com"
13
11
  gem.homepage = "http://github.com/bluemonk/ipaddress"
14
12
  gem.authors = ["Marco Ceresa"]
15
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
13
+ gem.description = <<-EOD
14
+ IPAddress is a Ruby library designed to make manipulation
15
+ of IPv4 and IPv6 addresses both powerful and simple. It mantains
16
+ a layer of compatibility with Ruby's own IPAddr, while
17
+ addressing many of its issues.
18
+ EOD
16
19
  end
17
-
18
20
  rescue LoadError
19
21
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
20
22
  end
@@ -59,7 +61,7 @@ end
59
61
 
60
62
  desc "Open an irb session preloaded with this library"
61
63
  task :console do
62
- sh "irb -rubygems -I lib -r ipaddress.rb"
64
+ sh "irb1.9 -rubygems -I lib -r ipaddress.rb"
63
65
  end
64
66
 
65
67
  desc "Look for TODO and FIXME tags in the code"
@@ -79,13 +81,3 @@ task :todo do
79
81
  end
80
82
  egrep /(FIXME|TODO|TBD)/
81
83
  end
82
-
83
- begin
84
- require 'jeweler'
85
- Jeweler::Tasks.new do |gemspec|
86
- # omitted for brevity
87
- end
88
- Jeweler::GemcutterTasks.new
89
- rescue LoadError
90
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
91
- end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.6.0
@@ -1,9 +1,136 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
1
+ #
2
+ # = IPAddress
3
+ #
4
+ # A ruby library to manipulate IPv4 and IPv6 addresses
5
+ #
6
+ #
7
+ # Package:: IPAddress
8
+ # Author:: Marco Ceresa <ceresa@ieee.org>
9
+ # License:: Ruby License
10
+ #
11
+ #--
12
+ #
13
+ #++
3
14
 
4
- require 'ipaddress/ipbase'
5
15
  require 'ipaddress/ipv4'
6
16
  require 'ipaddress/ipv6'
17
+ require 'ipaddress/extensions/extensions'
18
+
19
+
20
+ module IPAddress
21
+
22
+ NAME = "IPAddress"
23
+ GEM = "ipaddress"
24
+ AUTHORS = ["Marco Ceresa <ceresa@ieee.org>"]
25
+
26
+ #
27
+ # Parse the argument string to create a new
28
+ # IPv4, IPv6 or Mapped IP object
29
+ #
30
+ # ip = IPAddress.parse "172.16.10.1/24"
31
+ # ip6 = IPAddress.parse "2001:db8::8:800:200c:417a/64"
32
+ # ip_mapped = IPAddress.parse "::ffff:172.16.10.1/128"
33
+ #
34
+ # All the object created will be instances of the
35
+ # correct class:
36
+ #
37
+ # ip.class
38
+ # #=> IPAddress::IPv4
39
+ # ip6.class
40
+ # #=> IPAddress::IPv6
41
+ # ip_mapped.class
42
+ # #=> IPAddress::IPv6::Mapped
43
+ #
44
+ def IPAddress::parse(str)
45
+ case str
46
+ when /:.+\./
47
+ IPAddress::IPv6::Mapped.new(str)
48
+ else
49
+ begin
50
+ IPAddress::IPv4.new(str)
51
+ rescue ArgumentError
52
+ IPAddress::IPv6.new(str)
53
+ end
54
+ end
55
+ end
56
+
57
+ #
58
+ # Checks if the given string is a valid IP address,
59
+ # either IPv4 or IPv6
60
+ #
61
+ # Example:
62
+ #
63
+ # IPAddress::valid? "2002::1"
64
+ # #=> true
65
+ #
66
+ # IPAddress::valid? "10.0.0.256"
67
+ # #=> false
68
+ #
69
+ def self.valid?(addr)
70
+ valid_ipv4?(addr) || valid_ipv6?(addr)
71
+ end
72
+
73
+ #
74
+ # Checks if the given string is a valid IPv4 address
75
+ #
76
+ # Example:
77
+ #
78
+ # IPAddress::valid_ipv4? "2002::1"
79
+ # #=> false
80
+ #
81
+ # IPAddress::valid_ipv4? "172.16.10.1"
82
+ # #=> true
83
+ #
84
+ def self.valid_ipv4?(addr)
85
+ if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
86
+ return $~.captures.all? {|i| i.to_i < 256}
87
+ end
88
+ false
89
+ end
90
+
91
+ #
92
+ # Checks if the argument is a valid IPv4 netmask
93
+ # expressed in dotted decimal format.
94
+ #
95
+ # IPAddress.valid_ipv4_netmask? "255.255.0.0"
96
+ # #=> true
97
+ #
98
+ def self.valid_ipv4_netmask?(addr)
99
+ arr = addr.split(".").map{|i| i.to_i}.pack("CCCC").unpack("B*").first.scan(/01/)
100
+ arr.empty? && valid_ipv4?(addr)
101
+ rescue
102
+ return false
103
+ end
104
+
105
+ #
106
+ # Checks if the given string is a valid IPv6 address
107
+ #
108
+ # Example:
109
+ #
110
+ # IPAddress::valid_ipv6? "2002::1"
111
+ # #=> true
112
+ #
113
+ # IPAddress::valid_ipv6? "2002::DEAD::BEEF"
114
+ # #=> false
115
+ #
116
+ def self.valid_ipv6?(addr)
117
+ # IPv6 (normal)
118
+ return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ addr
119
+ return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
120
+ return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
121
+ # IPv6 (IPv4 compat)
122
+ return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ addr && valid_ipv4?($')
123
+ return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_ipv4?($')
124
+ return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_ipv4?($')
125
+ false
126
+ end
127
+
128
+ def self.deprecate(message = nil) # :nodoc:
129
+ message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
130
+ warn("DEPRECATION WARNING: #{message}")
131
+ end
132
+
133
+ end # module IPAddress
7
134
 
8
135
  #
9
136
  # IPAddress is a wrapper method built around
@@ -35,18 +162,7 @@ require 'ipaddress/ipv6'
35
162
  # #=> IPAddress::IPv6::Mapped
36
163
  #
37
164
  def IPAddress(str)
38
- case str
39
- when /:.+\./
40
- IPAddress::IPv6::Mapped.new(str)
41
- else
42
- begin
43
- IPAddress::IPv4.new(str)
44
- rescue ArgumentError
45
- IPAddress::IPv6.new(str)
46
- end
47
- end
165
+ IPAddress::parse str
48
166
  end
49
167
 
50
168
 
51
-
52
-
@@ -2,13 +2,19 @@ class << Math
2
2
  def log2(n); log(n) / log(2); end
3
3
  end
4
4
 
5
+ if RUBY_VERSION =~ /1\.8/
6
+ class Hash
7
+ alias :key :index
8
+ end
9
+ end
10
+
5
11
  class Integer
6
12
  def power_of_2?
7
13
  Math::log2(self).to_i == Math::log2(self)
8
14
  end
9
15
 
10
- def closest_power_of_2
11
- self.upto(32) do |i|
16
+ def closest_power_of_2(limit=32)
17
+ self.upto(limit) do |i|
12
18
  return i if i.power_of_2?
13
19
  end
14
20
  end
@@ -1,4 +1,3 @@
1
- require 'ipaddress/ipbase'
2
1
  require 'ipaddress/prefix'
3
2
 
4
3
  module IPAddress;
@@ -15,7 +14,7 @@ module IPAddress;
15
14
  #
16
15
  # Class IPAddress::IPv4 is used to handle IPv4 type addresses.
17
16
  #
18
- class IPv4 < IPBase
17
+ class IPv4
19
18
 
20
19
  include IPAddress
21
20
  include Enumerable
@@ -102,6 +101,7 @@ module IPAddress;
102
101
  # as a string.
103
102
  #
104
103
  # ip = IPAddress("172.16.100.4/22")
104
+ #
105
105
  # ip.address
106
106
  # #=> "172.16.100.4"
107
107
  #
@@ -114,8 +114,10 @@ module IPAddress;
114
114
  # as a IPAddress::Prefix32 object
115
115
  #
116
116
  # ip = IPAddress("172.16.100.4/22")
117
+ #
117
118
  # ip.prefix
118
119
  # #=> 22
120
+ #
119
121
  # ip.prefix.class
120
122
  # #=> IPAddress::Prefix32
121
123
  #
@@ -132,10 +134,12 @@ module IPAddress;
132
134
  # mask.
133
135
  #
134
136
  # ip = IPAddress("172.16.100.4")
137
+ #
135
138
  # puts ip
136
139
  # #=> 172.16.100.4/16
137
140
  #
138
141
  # ip.prefix = 22
142
+ #
139
143
  # puts ip
140
144
  # #=> 172.16.100.4/22
141
145
  #
@@ -147,6 +151,7 @@ module IPAddress;
147
151
  # Returns the address as an array of decimal values
148
152
  #
149
153
  # ip = IPAddress("172.16.100.4")
154
+ #
150
155
  # ip.octets
151
156
  # #=> [172, 16, 100, 4]
152
157
  #
@@ -154,22 +159,38 @@ module IPAddress;
154
159
  @octets
155
160
  end
156
161
 
162
+ #
163
+ # Returns a string with the address portion of
164
+ # the IPv4 object
165
+ #
166
+ # ip = IPAddress("172.16.100.4/22")
167
+ #
168
+ # ip.to_s
169
+ # #=> "172.16.100.4"
170
+ #
171
+ def to_s
172
+ @address
173
+ end
174
+
157
175
  #
158
176
  # Returns a string with the IP address in canonical
159
177
  # form.
160
178
  #
161
179
  # ip = IPAddress("172.16.100.4/22")
162
- # ip.to_s
180
+ #
181
+ # ip.to_string
163
182
  # #=> "172.16.100.4/22"
164
183
  #
165
- def to_s
184
+ def to_string
166
185
  "#@address/#@prefix"
167
186
  end
168
187
 
188
+
169
189
  #
170
190
  # Returns the prefix as a string in IP format
171
191
  #
172
192
  # ip = IPAddress("172.16.100.4/22")
193
+ #
173
194
  # ip.netmask
174
195
  # #=> "255.255.252.0"
175
196
  #
@@ -183,10 +204,12 @@ module IPAddress;
183
204
  # object.
184
205
  #
185
206
  # ip = IPAddress("172.16.100.4")
207
+ #
186
208
  # puts ip
187
209
  # #=> 172.16.100.4/16
188
210
  #
189
211
  # ip.netmask = "255.255.252.0"
212
+ #
190
213
  # puts ip
191
214
  # #=> 172.16.100.4/22
192
215
  #
@@ -203,6 +226,7 @@ module IPAddress;
203
226
  # structure.
204
227
  #
205
228
  # ip = IPAddress("10.0.0.0/8")
229
+ #
206
230
  # ip.to_u32
207
231
  # #=> 167772160
208
232
  #
@@ -216,6 +240,7 @@ module IPAddress;
216
240
  # in a network byte order format.
217
241
  #
218
242
  # ip = IPAddress("172.16.10.1/24")
243
+ #
219
244
  # ip.data
220
245
  # #=> "\254\020\n\001"
221
246
  #
@@ -237,6 +262,7 @@ module IPAddress;
237
262
  # Returns the octet specified by index
238
263
  #
239
264
  # ip = IPAddress("172.16.100.50/24")
265
+ #
240
266
  # ip[0]
241
267
  # #=> 172
242
268
  # ip[1]
@@ -256,6 +282,7 @@ module IPAddress;
256
282
  # as a string containing a sequence of 0 and 1
257
283
  #
258
284
  # ip = IPAddress("127.0.0.1")
285
+ #
259
286
  # ip.bits
260
287
  # #=> "01111111000000000000000000000001"
261
288
  #
@@ -267,8 +294,9 @@ module IPAddress;
267
294
  # Returns the broadcast address for the given IP.
268
295
  #
269
296
  # ip = IPAddress("172.16.10.64/24")
297
+ #
270
298
  # ip.broadcast.to_s
271
- # #=> "172.16.10.255/24"
299
+ # #=> "172.16.10.255"
272
300
  #
273
301
  def broadcast
274
302
  self.class.parse_u32(broadcast_u32, @prefix)
@@ -278,10 +306,12 @@ module IPAddress;
278
306
  # Checks if the IP address is actually a network
279
307
  #
280
308
  # ip = IPAddress("172.16.10.64/24")
309
+ #
281
310
  # ip.network?
282
311
  # #=> false
283
312
  #
284
313
  # ip = IPAddress("172.16.10.64/26")
314
+ #
285
315
  # ip.network?
286
316
  # #=> true
287
317
  #
@@ -294,8 +324,9 @@ module IPAddress;
294
324
  # for the given IP.
295
325
  #
296
326
  # ip = IPAddress("172.16.10.64/24")
327
+ #
297
328
  # ip.network.to_s
298
- # #=> "172.16.10.0/24"
329
+ # #=> "172.16.10.0"
299
330
  #
300
331
  def network
301
332
  self.class.parse_u32(network_u32, @prefix)
@@ -309,15 +340,17 @@ module IPAddress;
309
340
  # host IP address is 192.168.100.1.
310
341
  #
311
342
  # ip = IPAddress("192.168.100.0/24")
343
+ #
312
344
  # ip.first.to_s
313
- # #=> "192.168.100.1/24"
345
+ # #=> "192.168.100.1"
314
346
  #
315
347
  # The object IP doesn't need to be a network: the method
316
348
  # automatically gets the network number from it
317
349
  #
318
350
  # ip = IPAddress("192.168.100.50/24")
351
+ #
319
352
  # ip.first.to_s
320
- # #=> "192.168.100.1/24"
353
+ # #=> "192.168.100.1"
321
354
  #
322
355
  def first
323
356
  self.class.parse_u32(network_u32+1, @prefix)
@@ -329,18 +362,20 @@ module IPAddress;
329
362
  # last host IP address in the range.
330
363
  #
331
364
  # Example: given the 192.168.100.0/24 network, the last
332
- # host IP address is 192.168.100.1.
365
+ # host IP address is 192.168.100.254
333
366
  #
334
367
  # ip = IPAddress("192.168.100.0/24")
368
+ #
335
369
  # ip.last.to_s
336
- # #=> "192.168.100.254/24"
370
+ # #=> "192.168.100.254"
337
371
  #
338
372
  # The object IP doesn't need to be a network: the method
339
373
  # automatically gets the network number from it
340
374
  #
341
375
  # ip = IPAddress("192.168.100.50/24")
376
+ #
342
377
  # ip.last.to_s
343
- # #=> "192.168.100.254/24"
378
+ # #=> "192.168.100.254"
344
379
  #
345
380
  def last
346
381
  self.class.parse_u32(broadcast_u32-1, @prefix)
@@ -350,9 +385,10 @@ module IPAddress;
350
385
  # Iterates over all the hosts IP addresses for the given
351
386
  # network (or IP address).
352
387
  #
353
- # ip = IPaddress("10.0.0.1/29")
388
+ # ip = IPAddress("10.0.0.1/29")
389
+ #
354
390
  # ip.each do |i|
355
- # p i
391
+ # p i.to_s
356
392
  # end
357
393
  # #=> "10.0.0.1"
358
394
  # #=> "10.0.0.2"
@@ -374,7 +410,8 @@ module IPAddress;
374
410
  # The object yielded is a new IPv4 object created
375
411
  # from the iteration.
376
412
  #
377
- # ip = IPaddress("10.0.0.1/29")
413
+ # ip = IPAddress("10.0.0.1/29")
414
+ #
378
415
  # ip.each do |i|
379
416
  # p i.address
380
417
  # end
@@ -406,8 +443,8 @@ module IPAddress;
406
443
  # Example:
407
444
  #
408
445
  # ip1 = IPAddress "10.100.100.1/8"
409
- # ip2 = IPAddress ""172.16.0.1/16"
410
- # ip3 = IPAddress ""10.100.100.1/16"
446
+ # ip2 = IPAddress "172.16.0.1/16"
447
+ # ip3 = IPAddress "10.100.100.1/16"
411
448
  #
412
449
  # ip1 < ip2
413
450
  # #=> true
@@ -434,7 +471,8 @@ module IPAddress;
434
471
  # in the network. It also counts the network
435
472
  # address and the broadcast address.
436
473
  #
437
- # ip = IPaddress("10.0.0.1/29")
474
+ # ip = IPAddress("10.0.0.1/29")
475
+ #
438
476
  # ip.size
439
477
  # #=> 8
440
478
  #
@@ -446,7 +484,8 @@ module IPAddress;
446
484
  # Returns an array with the IP addresses of
447
485
  # all the hosts in the network.
448
486
  #
449
- # ip = IPaddress("10.0.0.1/29")
487
+ # ip = IPAddress("10.0.0.1/29")
488
+ #
450
489
  # ip.hosts.map {|i| i.address}
451
490
  # #=> ["10.0.0.1",
452
491
  # #=> "10.0.0.2",
@@ -462,7 +501,8 @@ module IPAddress;
462
501
  #
463
502
  # Returns the network number in Unsigned 32bits format
464
503
  #
465
- # ip = IPaddress("10.0.0.1/29")
504
+ # ip = IPAddress("10.0.0.1/29")
505
+ #
466
506
  # ip.network_u32
467
507
  # #=> 167772160
468
508
  #
@@ -474,6 +514,7 @@ module IPAddress;
474
514
  # Returns the broadcast address in Unsigned 32bits format
475
515
  #
476
516
  # ip = IPaddress("10.0.0.1/29")
517
+ #
477
518
  # ip.broadcast_u32
478
519
  # #=> 167772167
479
520
  #
@@ -490,6 +531,7 @@ module IPAddress;
490
531
  # ip = IPAddress("192.168.10.100/24")
491
532
  #
492
533
  # addr = IPAddress("192.168.10.102/24")
534
+ #
493
535
  # ip.include? addr
494
536
  # #=> true
495
537
  #
@@ -505,12 +547,14 @@ module IPAddress;
505
547
  # for DNS lookups
506
548
  #
507
549
  # ip = IPAddress("172.16.100.50/24")
550
+ #
508
551
  # ip.reverse
509
552
  # #=> "50.100.16.172.in-addr.arpa"
510
553
  #
511
554
  def reverse
512
555
  @octets.reverse.join(".") + ".in-addr.arpa"
513
556
  end
557
+ alias_method :arpa, :reverse
514
558
 
515
559
  #
516
560
  # Subnetting a network
@@ -524,7 +568,8 @@ module IPAddress;
524
568
  # networks will be divided evenly from the supernet.
525
569
  #
526
570
  # network = IPAddress("172.16.10.0/24")
527
- # network / 4 # implies map{|i| i.to_s}
571
+ #
572
+ # network / 4 # implies map{|i| i.to_string}
528
573
  # #=> ["172.16.10.0/26",
529
574
  # "172.16.10.64/26",
530
575
  # "172.16.10.128/26",
@@ -535,7 +580,8 @@ module IPAddress;
535
580
  # other networks with the remaining addresses.
536
581
  #
537
582
  # network = IPAddress("172.16.10.0/24")
538
- # network / 3 # implies map{|i| i.to_s}
583
+ #
584
+ # network / 3 # implies map{|i| i.to_string}
539
585
  # #=> ["172.16.10.0/26",
540
586
  # "172.16.10.64/26",
541
587
  # "172.16.10.128/25"]
@@ -546,7 +592,6 @@ module IPAddress;
546
592
  unless (1..(2**(32-prefix.to_i))).include? subnets
547
593
  raise ArgumentError, "Value #{subnets} out of range"
548
594
  end
549
-
550
595
  calculate_subnets(subnets)
551
596
  end
552
597
  alias_method :/, :subnet
@@ -564,13 +609,13 @@ module IPAddress;
564
609
  #
565
610
  # you can supernet it with a new /23 prefix
566
611
  #
567
- # ip.supernet(23).to_s
612
+ # ip.supernet(23).to_string
568
613
  # #=> "172.16.10.0/23"
569
614
  #
570
615
  # However if you supernet it with a /22 prefix, the
571
616
  # network address will change:
572
617
  #
573
- # ip.supernet(22).to_s
618
+ # ip.supernet(22).to_string
574
619
  # #=> "172.16.8.0/22"
575
620
  #
576
621
  def supernet(new_prefix)
@@ -583,6 +628,14 @@ module IPAddress;
583
628
  # Returns the difference between two IP addresses
584
629
  # in unsigned int 32 bits format
585
630
  #
631
+ # Example:
632
+ #
633
+ # ip1 = IPAddress("172.16.10.0/24")
634
+ # ip2 = IPAddress("172.16.11.0/24")
635
+ #
636
+ # puts ip1 - ip2
637
+ # #=> 256
638
+ #
586
639
  def -(oth)
587
640
  return (to_u32 - oth.to_u32).abs
588
641
  end
@@ -596,14 +649,21 @@ module IPAddress;
596
649
  #
597
650
  # ip1 = IPAddress("172.16.10.1/24")
598
651
  # ip2 = IPAddress("172.16.11.2/24")
599
- # puts ip1 + ip2
600
- # #=>"172.16.10.0/23"
652
+ #
653
+ # p (ip1 + ip2).map {|i| i.to_string}
654
+ # #=> ["172.16.10.0/23"]
601
655
  #
602
656
  # If the networks are not contiguous, returns
603
657
  # the two network numbers from the objects
604
658
  #
659
+ # ip1 = IPAddress("10.0.0.1/24")
660
+ # ip2 = IPAddress("10.0.2.1/24")
661
+ #
662
+ # p (ip1 + ip2).map {|i| i.to_string}
663
+ # #=> ["10.0.0.0/24","10.0.2.0/24"]
664
+ #
605
665
  def +(oth)
606
- self.class.summarize(self,oth)
666
+ aggregate(*[self,oth].sort.map{|i| i.network})
607
667
  end
608
668
 
609
669
  #
@@ -614,11 +674,12 @@ module IPAddress;
614
674
  # Example:
615
675
  #
616
676
  # ip = IPAddress("10.0.0.1/24")
677
+ #
617
678
  # ip.a?
618
679
  # #=> true
619
680
  #
620
681
  def a?
621
- CLASSFUL.index(8) === bits
682
+ CLASSFUL.key(8) === bits
622
683
  end
623
684
 
624
685
  #
@@ -629,11 +690,12 @@ module IPAddress;
629
690
  # Example:
630
691
  #
631
692
  # ip = IPAddress("172.16.10.1/24")
693
+ #
632
694
  # ip.b?
633
695
  # #=> true
634
696
  #
635
697
  def b?
636
- CLASSFUL.index(16) === bits
698
+ CLASSFUL.key(16) === bits
637
699
  end
638
700
 
639
701
  #
@@ -644,11 +706,12 @@ module IPAddress;
644
706
  # Example:
645
707
  #
646
708
  # ip = IPAddress("192.168.1.1/30")
709
+ #
647
710
  # ip.c?
648
711
  # #=> true
649
712
  #
650
713
  def c?
651
- CLASSFUL.index(24) === bits
714
+ CLASSFUL.key(24) === bits
652
715
  end
653
716
 
654
717
  #
@@ -658,6 +721,7 @@ module IPAddress;
658
721
  # Example:
659
722
  #
660
723
  # ip = IPAddress("172.16.10.1/24")
724
+ #
661
725
  # ip.to_ipv6
662
726
  # #=> "ac10:0a01"
663
727
  #
@@ -670,14 +734,16 @@ module IPAddress;
670
734
  # unsigned 32bits integer.
671
735
  #
672
736
  # ip = IPAddress::IPv4::parse_u32(167772160)
737
+ #
673
738
  # ip.prefix = 8
674
- # ip.to_s
739
+ # ip.to_string
675
740
  # #=> "10.0.0.0/8"
676
741
  #
677
742
  # The +prefix+ parameter is optional:
678
743
  #
679
744
  # ip = IPAddress::IPv4::parse_u32(167772160, 8)
680
- # ip.to_s
745
+ #
746
+ # ip.to_string
681
747
  # #=> "10.0.0.0/8"
682
748
  #
683
749
  def self.parse_u32(u32, prefix=nil)
@@ -699,7 +765,7 @@ module IPAddress;
699
765
  # ip = IPAddress::IPv4::parse_data "\254\020\n\001"
700
766
  # ip.prefix = 24
701
767
  #
702
- # ip.to_s
768
+ # ip.to_string
703
769
  # #=> "172.16.10.1/24"
704
770
  #
705
771
  def self.parse_data(str)
@@ -713,10 +779,10 @@ module IPAddress;
713
779
  # Example:
714
780
  #
715
781
  # str = "foobar172.16.10.1barbaz"
716
- # ip = self.extract str
782
+ # ip = IPAddress::IPv4::extract str
717
783
  #
718
784
  # ip.to_s
719
- # #=> "172.16.10.1/16"
785
+ # #=> "172.16.10.1"
720
786
  #
721
787
  def self.extract(str)
722
788
  self.new REGEXP.match(str).to_s
@@ -770,7 +836,8 @@ module IPAddress;
770
836
  # ip2 = IPAddress("10.0.1.1/24")
771
837
  # ip3 = IPAddress("10.0.2.1/24")
772
838
  # ip4 = IPAddress("10.0.3.1/24")
773
- # IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).to_s
839
+ #
840
+ # IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).to_string
774
841
  # #=> "10.0.0.0/22",
775
842
  #
776
843
  # But the following networks can't be summarized in a single network:
@@ -779,27 +846,28 @@ module IPAddress;
779
846
  # ip2 = IPAddress("10.0.2.1/24")
780
847
  # ip3 = IPAddress("10.0.3.1/24")
781
848
  # ip4 = IPAddress("10.0.4.1/24")
782
- # IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_s}
849
+ #
850
+ # IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
783
851
  # #=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
784
852
  #
785
853
  def self.summarize(*args)
786
854
  # one network? no need to summarize
787
- return args.flatten.first if args.size == 1
855
+ return [args.first.network] if args.size == 1
788
856
 
789
- result, arr, last = [], args.sort, args.sort.last.network
790
- arr.each_cons(2) do |x,y|
791
- snet = x.supernet(x.prefix.to_i-1)
792
- if snet.include? y
793
- result << snet
794
- else
795
- result << x.network unless result.any?{|i| i.include? x}
796
- end
857
+ i = 0
858
+ result = args.dup.sort.map{|ip| ip.network}
859
+ while i < result.size-1
860
+ sum = result[i] + result[i+1]
861
+ result[i..i+1] = sum.first if sum.size == 1
862
+ i += 1
797
863
  end
798
- result << last unless result.any?{|i| i.include? last}
799
864
 
865
+ result.flatten!
800
866
  if result.size == args.size
867
+ # nothing more to summarize
801
868
  return result
802
869
  else
870
+ # keep on summarizing
803
871
  return self.summarize(*result)
804
872
  end
805
873
  end
@@ -815,12 +883,12 @@ module IPAddress;
815
883
 
816
884
  def prefix_from_ip(ip)
817
885
  bits = bits_from_address(ip)
818
- CLASSFUL.each {|reg,prefix| return prefix if bits =~ reg}
886
+ CLASSFUL.each {|reg,prefix| return Prefix32.new(prefix) if bits =~ reg}
819
887
  end
820
888
 
821
889
  def calculate_subnets(subnets)
822
890
  po2 = subnets.closest_power_of_2
823
- new_prefix = @prefix.to_i + Math::log2(po2).to_i
891
+ new_prefix = @prefix + Math::log2(po2).to_i
824
892
  networks = Array.new
825
893
  (0..po2-1).each do |i|
826
894
  mul = i * (2**(32-new_prefix))
@@ -843,6 +911,21 @@ module IPAddress;
843
911
  end
844
912
  return dup.reverse
845
913
  end
914
+
915
+ def aggregate(ip1,ip2)
916
+ if ip1.include? ip2
917
+ return [ip1]
918
+ else
919
+ snet = ip1.supernet(ip1.prefix-1)
920
+ arr1 = ip1.subnet(2**(ip2.prefix-ip1.prefix)).map{|i| i.to_string}
921
+ arr2 = snet.subnet(2**(ip2.prefix-snet.prefix)).map{|i| i.to_string}
922
+ if (arr2 - [ip2.to_string] - arr1).empty?
923
+ return [snet]
924
+ else
925
+ return [ip1, ip2]
926
+ end
927
+ end
928
+ end
846
929
 
847
930
  end # class IPv4
848
931
  end # module IPAddress