ip_address_simple 1.0.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 ADDED
@@ -0,0 +1,15 @@
1
+ == IP Address Simple
2
+ IpAddress is a class that makes common IP address handling a doddle.
3
+ It provides support for...
4
+
5
+ * interchange between string and integer IP representations
6
+ * masking / sub-netting
7
+ * IPv4 and IPv6
8
+
9
+ == Author
10
+ Copyright 2007 Andre Ben Hamou
11
+ mailto:andre@prfsa.com
12
+
13
+ == License
14
+ This library and all associated materials are release under the terms of
15
+ version 3 of the GNU Public License (http://www.gnu.org/copyleft/gpl.html).
data/lib/ip_address.rb ADDED
@@ -0,0 +1,118 @@
1
+ require "ip_address_range"
2
+
3
+ class IpAddress
4
+ IP_BITS = {4 => 32, 6 => 128}
5
+ IP_MAX = {4 => (1 << 32) - 1, 6 => (1 << 128) - 1}
6
+
7
+ # Takes an Integer or a String representation of an IP address and coerces it to a representation of the requested type (:integer / :string).
8
+ # If the version (4 / 6) is not specified then it will be guessed with guess_version.
9
+ def self.coerce(value, to_type, version = nil)
10
+ raise "unknown type #{to_type.inspect} requested" unless [:integer, :string].include?(to_type)
11
+ version ||= guess_version(value)
12
+
13
+ case value
14
+ when Integer
15
+ if to_type == :integer then value
16
+ elsif version == 4 then [24, 16, 8, 0].map { |shift| (value >> shift) & 255 }.join(".")
17
+ else sprintf("%.32x", value).scan(/.{4}/).join(":")
18
+ end
19
+ when String
20
+ if to_type == :string then value
21
+ elsif version == 4 then value.split(".").inject(0) { |total, octet| (total << 8) + octet.to_i }
22
+ else value.delete(":").to_i(16)
23
+ end
24
+ end
25
+ end
26
+
27
+ # Takes an Integer or a String and guesses whether it represents an IPv4 or IPv6 address.
28
+ # For an Integer, IPv4 is assumed unless the value is greater than IP_MAX[4].
29
+ # For a String, IPv6 is assumed if it contains at least one colon (:).
30
+ def self.guess_version(value)
31
+ case value
32
+ when Integer then value > IP_MAX[4] ? 6 : 4
33
+ when String then value =~ /:/ ? 6 : 4
34
+ end
35
+ end
36
+
37
+ # Takes an Integer bitcount (bits) and returns an appropriate masking Integer.
38
+ # For example, a /24 network (in IPv4) corresponds to a mask of 255.255.255.0 or the number 4294967040.
39
+ # If the version (4 / 6) is not specified then it will be assumed to be 4 unless bits > 32.
40
+ def self.mask_from_slash_bits(bits, version = nil)
41
+ raise "bits > 128" if bits > 128
42
+ version ||= bits > 32 ? 6 : 4
43
+
44
+ max = IP_MAX[version]
45
+ left_shift = IP_BITS[version] - bits
46
+ (max << left_shift) & max
47
+ end
48
+
49
+ # Takes an Integer or a String representation of a network mask and returns the number of addresses it encodes.
50
+ # If the version (4 / 6) is not specified then it will be guessed with guess_version.
51
+ def self.mask_size(value, version = nil)
52
+ version ||= guess_version(value)
53
+ (coerce(value, :integer, version) ^ IP_MAX[version]) + 1
54
+ end
55
+
56
+ include Comparable
57
+
58
+ attr_reader :integer, :string, :version
59
+
60
+ # Takes an Integer or a String representation of an IP address and creates a new IpAddress object with it.
61
+ # If the version (4 / 6) is not specified then it will be guessed with guess_version.
62
+ def initialize(value, version = nil)
63
+ @version = version || IpAddress.guess_version(value)
64
+ @integer = IpAddress.coerce(value, :integer, @version)
65
+ @string = IpAddress.coerce(value, :string, @version)
66
+ end
67
+
68
+ # Adds the specified Integer value to that of the IpAddress and returns a new IpAddress based on the sum.
69
+ def +(value)
70
+ IpAddress.new(@integer + value, @version)
71
+ end
72
+
73
+ # Subtracts the specified Integer value from that of the IpAddress and returns a new IpAddress based on the difference.
74
+ def -(value)
75
+ IpAddress.new(@integer - value, @version)
76
+ end
77
+
78
+ # Returns the range of IpAddresses in the specified /bits network. Basically a convenience wrapper around mask.
79
+ def /(bits)
80
+ mask(IpAddress.mask_from_slash_bits(bits, @version))
81
+ end
82
+
83
+ # Compares one IpAddress with another based on the Integer representation of their values.
84
+ def <=>(other)
85
+ @integer <=> other.integer
86
+ end
87
+
88
+ # Takes an Integer or a String representation of a network mask and returns the range of IpAddresses in that network.
89
+ def mask(value)
90
+ base_int = @integer & IpAddress.coerce(value, :integer, @version)
91
+ IpAddressRange.new(IpAddress.new(base_int, @version), IpAddress.new(base_int + IpAddress.mask_size(value, @version) - 1))
92
+ end
93
+
94
+ # Returns the next IpAddress after this one.
95
+ def succ
96
+ self + 1
97
+ end
98
+
99
+ def to_i
100
+ @integer
101
+ end
102
+
103
+ def to_s
104
+ @string
105
+ end
106
+ end
107
+
108
+ class Integer
109
+ def to_ip(version = nil)
110
+ IpAddress.new(self, version)
111
+ end
112
+ end
113
+
114
+ class String
115
+ def to_ip(version = nil)
116
+ IpAddress.new(self, version)
117
+ end
118
+ end
@@ -0,0 +1,5 @@
1
+ class IpAddressRange < Range
2
+ def size
3
+ last.integer - first.integer + 1
4
+ end
5
+ end
@@ -0,0 +1,42 @@
1
+ require "test/unit"
2
+ require "ip_address"
3
+
4
+ class TestIpAddress < Test::Unit::TestCase # :nodoc:
5
+ def setup
6
+ @ip = IpAddress.new("10.0.0.1")
7
+ end
8
+
9
+ def test_basics
10
+ [@ip, IpAddress.new(167772161)].each do |ip|
11
+ assert_equal(4, ip.version)
12
+ assert_equal(167772161, ip.integer)
13
+ assert_equal(167772161, ip.to_i)
14
+ assert_equal("10.0.0.1", ip.string)
15
+ assert_equal("10.0.0.1", ip.to_s)
16
+ end
17
+
18
+ ip = IpAddress.new(182735, 6)
19
+ assert_equal(6, ip.version)
20
+ assert_equal(182735, ip.integer)
21
+ assert_equal("0000:0000:0000:0000:0000:0000:0002:c9cf", ip.string)
22
+ end
23
+
24
+ def test_arithmetic
25
+ other = @ip + 256
26
+ assert_kind_of(IpAddress, other)
27
+ assert_equal("10.0.1.1", other.string)
28
+ other = @ip - 256
29
+ assert_kind_of(IpAddress, other)
30
+ assert_equal("9.255.255.1", other.string)
31
+ end
32
+
33
+ def test_comparison
34
+ other = @ip + 20
35
+ assert(@ip < other)
36
+ end
37
+
38
+ def test_conversion
39
+ assert_equal(@ip, "10.0.0.1".to_ip)
40
+ assert_equal(@ip, 167772161.to_ip)
41
+ end
42
+ end
@@ -0,0 +1,19 @@
1
+ require "test/unit"
2
+ require "ip_address"
3
+
4
+ class TestIpAddressRange < Test::Unit::TestCase # :nodoc:
5
+ def setup
6
+ @ip = IpAddress.new("10.0.0.1")
7
+ end
8
+
9
+ def test_range_masking
10
+ [@ip.mask("255.255.255.252"), @ip / 30].each do |range|
11
+ assert_kind_of(IpAddressRange, range)
12
+ assert_kind_of(IpAddress, range.first)
13
+ assert_equal("10.0.0.0", range.first.string)
14
+ assert_kind_of(IpAddress, range.last)
15
+ assert_equal("10.0.0.3", range.last.string)
16
+ assert_equal(4, range.size)
17
+ end
18
+ end
19
+ end
data/test/ts_all.rb ADDED
@@ -0,0 +1,3 @@
1
+ require "test/unit"
2
+ require "tc_ip_address"
3
+ require "tc_ip_address_range"
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.2
3
+ specification_version: 1
4
+ name: ip_address_simple
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.0.0
7
+ date: 2007-10-13 00:00:00 +01:00
8
+ summary: Simple IP address manipulation library
9
+ require_paths:
10
+ - lib
11
+ email: andre@prfsa.com
12
+ homepage:
13
+ rubyforge_project: ip-addr-simple
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Andre Ben Hamou
31
+ files:
32
+ - README
33
+ - lib/ip_address.rb
34
+ - lib/ip_address_range.rb
35
+ - test/tc_ip_address.rb
36
+ - test/tc_ip_address_range.rb
37
+ - test/ts_all.rb
38
+ test_files:
39
+ - test/tc_ip_address.rb
40
+ - test/tc_ip_address_range.rb
41
+ rdoc_options:
42
+ - --main
43
+ - README
44
+ extra_rdoc_files:
45
+ - README
46
+ executables: []
47
+
48
+ extensions: []
49
+
50
+ requirements: []
51
+
52
+ dependencies: []
53
+