Skip to content
119 changes: 117 additions & 2 deletions lib/ipaddress/ipv4.rb
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,18 @@ def network?
def network
self.class.parse_u32(network_u32, @prefix)
end

#
# Returns a new IPv4 object containing only the host part of this IP.
#
# ip = IPAddress("172.16.10.64/24")
#
# ip.hostpart.to_s
# #=> "0.0.0.64"
#
def hostpart
self.class.parse_u32(hostpart_u32, 32)
end

#
# Returns a new IPv4 object with the
Expand Down Expand Up @@ -505,6 +517,18 @@ def hosts
def network_u32
@u32 & @prefix.to_u32
end

#
# Returns this address' host part in unsigned 32bits format
#
# ip = IPAddress("10.0.0.42/24")
#
# ip.host_u32
# #=> 42
#
def hostpart_u32
@u32 & ~@prefix.to_u32
end

#
# Returns the broadcast address in Unsigned 32bits format
Expand Down Expand Up @@ -565,8 +589,8 @@ def include_all?(*others)
#
def private?
[self.class.new("10.0.0.0/8"),
self.class.new("172.16.0.0/12"),
self.class.new("192.168.0.0/16")].any? {|i| i.include? self}
self.class.new("172.16.0.0/12"),
self.class.new("192.168.0.0/16")].any? {|i| i.include? self}
end

#
Expand Down Expand Up @@ -729,6 +753,97 @@ def -(oth)
def +(oth)
aggregate(*[self,oth].sort.map{|i| i.network})
end

#
# Returns a new IPv4 object which is the result
# of advancing this IP address by a given value.
# In other words, this arithmetically adds IP addresses.
#
# Will raise an error if the resulting address is in a different subnet,
# except validating is set to false.
#
# Example:
#
# ip = IPAddress::IPv4.new("172.16.10.1/24")
# ip.add(5).to_string
# #=> "172.16.10.6/24"
def add(oth, validating=true)
oth = oth.to_i if oth.kind_of? IPAddress::IPv4 # oth shall be integer

new_obj = self.class.parse_u32(self.to_i + oth, prefix)

if validating and self.network_u32 != new_obj.network_u32
raise ArgumentError, "Subnet (/#{@prefix}) is not large enough."
end

return new_obj
end

#
# Returns a new IPv4 object which is the result
# of decreasing this IP address by a given value.
# In other words, this arithmetically subtracts IP addresses.
#
# Will raise an error if the resulting address is in a different subnet,
# except validating is set to false.
#
# Example:
#
# ip = IPAddress::IPv4.new("172.16.10.10/24")
# ip.subtract(5).to_string
# #=> "172.16.10.5/24"
def subtract(oth, validating=true)
oth = oth.to_i if oth.kind_of? IPAddress::IPv4 # oth shall be integer
return add(-oth, validating)
end

#
# Returns the network address of the n-th network succeeding this one.
#
# Example:
#
# ip = IPAddress::IPv4.new("172.16.10.0/24")
# ip.advance_network(24).to_string
# #=> "172.16.52.0/24"
def advance_network(amount)
IPAddress::IPv4.parse_u32(self.network.u32 + amount*self.size, @prefix)
end

#
# Returns the network address of the network succeeding this one.
#
# Example:
#
# ip = IPAddress::IPv4.new("172.16.10.0/24")
# ip.next_network.to_string
# #=> "172.16.11.0/24"
def next_network
advance_network 1
end

#
# Returns the network address of the n-th network preceeding this one.
#
# Example:
#
# ip = IPAddress::IPv4.new("172.16.10.0/24")
# ip.regress_network(5).to_string
# #=> "172.16.5.0/24"
def regress_network(amount)
advance_network -amount
end

#
# Returns the network address of the network preceeding this one.
#
# Example:
#
# ip = IPAddress::IPv4.new("172.16.10.0/24")
# ip.previous_network.to_string
# #=> "172.16.9.0/24"
def previous_network
regress_network 1
end

#
# Checks whether the ip address belongs to a
Expand Down
115 changes: 115 additions & 0 deletions lib/ipaddress/ipv6.rb
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,110 @@ def reverse
to_hex.reverse.gsub(/./){|c| c+"."} + "ip6.arpa"
end
alias_method :arpa, :reverse

#
# Returns a new IPv6 object which is the result
# of advancing this IP address by a given value.
# In other words, this arithmetically adds IP addresses.
#
# Will raise an error if the resulting address is in a different subnet,
# except validating is set to false.
#
# Example:
#
# ip = IPAddress::IPv6.new("fc42:1337::/64")
# ip.add(5).to_string
# #=> "fc42:1337::5/64"
def add(oth, validating=true)
oth = oth.to_i if oth.kind_of? IPAddress::IPv6 # oth shall be integer

new_obj = self.class.parse_u128(self.to_i + oth, prefix)

if validating and self.network_u128 != new_obj.network_u128
raise ArgumentError, "Subnet (/#{@prefix}) is not large enough."
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you think about changing this to a RuntimeError. The reason why I suggest this is that there isn't a problem with argument per se, rather you have reached a state of exhaustion.

end

return new_obj
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/bbatsov/ruby-style-guide#no-explicit-return

(ditto all of the return expressions below)

end

#
# Returns a new IPv6 object which is the result
# of decreasing this IP address by a given value.
# In other words, this arithmetically subtracts IP addresses.
#
# Will raise an error if the resulting address is in a different subnet,
# except validating is set to false.
#
# Example:
#
# ip = IPAddress::IPv6.new("fc42:1337::a/64")
# ip.subtract(5).to_string
# #=> "fc42:1337::5/64"
def subtract(oth, validating=true)
oth = oth.to_i if oth.kind_of? IPAddress::IPv6 # oth shall be integer
return add(-oth, validating)
end

#
# Returns the network address of the n-th network succeeding this one.
#
# Example:
#
# ip = IPAddress::IPv6.new("fc42:1337:0:0::/64")
# ip.advance_network(5).to_string
# #=> "fc42:1337:0:5::/64"
def advance_network(amount)
IPAddress::IPv6.parse_u128(self.network.to_i + amount*self.size, @prefix)
end

#
# Returns the network address of the network succeeding this one.
#
# Example:
#
# ip = IPAddress::IPv6.new("fc42:1337:0:0::/64")
# ip.next_network.to_string
# #=> "fc42:1337:0:1::/64"
def next_network
advance_network 1
end

#
# Returns the network address of the n-th network preceeding this one.
#
# Example:
#
# ip = IPAddress::IPv6.new("fc42:1337:0:5::/64")
# ip.regress_network(4).to_string
# #=> "fc42:1337:0:1::/64"
def regress_network(amount)
advance_network -amount
end

#
# Returns the network address of the network preceeding this one.
#
# Example:
#
# ip = IPAddress::IPv6.new("fc42:1337:0:5::/64")
# ip.previous_network.to_string
# #=> "fc42:1337:0:4::/64"
def previous_network
regress_network 1
end

#
# Returns a new IPv6 object containing only the host part of this IP.
#
# ip = IPAddress::IPv6.new("fc42:1337:0:5::7/64")
#
# ip.hostpart.to_s
# #=> "::7"
#
def hostpart
self.class.parse_u128(hostpart_u128, 128)
end

#
# Returns the network number in Unsigned 128bits format
#
Expand All @@ -327,6 +430,18 @@ def reverse
def network_u128
to_u128 & @prefix.to_u128
end

#
# Returns this address' host part in unsigned 128bits format
#
# ip = IPAddress::IPv6.new("fc42:1337:0:5::7/64")
#
# ip.host_u128
# #=> 7
#
def hostpart_u128
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please supply unit testing for this method

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disregard... implied in testing of #hostpart

to_u128 & ~@prefix.to_u128
end

#
# Returns the broadcast address in Unsigned 128bits format
Expand Down
Loading