lib/better_ipaddr/classes.rb in better_ipaddr-0.5.0 vs lib/better_ipaddr/classes.rb in better_ipaddr-0.6.0
- old
+ new
@@ -1,10 +1,11 @@
require "better_ipaddr/constants"
require "better_ipaddr/methods"
require "better_ipaddr/host_methods"
class IPAddr
+ # An intermediate superclass for all BetterIpaddr classes
class Base < IPAddr
include BetterIpaddr::Constants
include BetterIpaddr::InstanceMethods
include Comparable
include Enumerable
@@ -15,21 +16,22 @@
# IPAddr.
#
# @param address [Integer, IPAddr, String]
# @param mask [Integer, IPAddr, String, Nil]
# @param family [Integer]
+ # @param classful [Boolean] see Base.from_string
# @return [IPAddr, Nil]
- def self.[](address, mask = nil, family: self::FAMILY)
+ def self.[](address, mask = nil, family: self::FAMILY, classful: false)
prefix_length = mask && object_to_prefix_length(mask, family)
case address
when Integer
from_integer(address, prefix_length, family: family)
when IPAddr
from_ipaddr(address, prefix_length, family: family)
when String
- from_string(address, prefix_length, family: family)
+ from_string(address, prefix_length, family: family, classful: classful)
end
end
# Create an IPAddr from the given object, guessing the type of address given
# based on its type and content.
@@ -40,33 +42,45 @@
#
# Returns nil if the object can't be converted based on its type and
# content.
#
# @param address [Integer, IPAddr, String]
+ # @param exception [Boolean] If true, then when the given object can't be
+ # converted to an IPAddr, a TypeError will be raise rather than returning
+ # nil.
+ # @param classful [Boolean] see Base.from_string
# @return [IPAddr, Nil]
- def self.from(address)
+ def self.from(address, exception: false, classful: false)
case address
when IPAddr
specialize address
when Regex::IPV4, 0..V4::MAX_INT
- V4[address]
+ V4[address, classful: classful]
when Regex::IPV6, 0..V6::MAX_INT
V6[address]
- end
+ end || (
+ if exception
+ raise TypeError, "can't convert #{address.inspect} to #{self}"
+ end
+ )
end
# Create an IPAddr host subclass from the given object, guessing the type of
# address given based on its type and content.
#
# Uses .from internally, so the same concerns apply, though the returned
# object is guaranteed to be of a Host class or nil.
+ #
+ # @param address [Integer, IPAddr, String]
+ # @param exception [Boolean] See IPAddr::Base.from
+ # @return [IPAddr::Host, Nil]
- def self.host_from(address)
- ip = from(address)
- if ip.ipv4?
+ def self.host_from(address, exception: false)
+ ip = from(address, exception: exception)
+ if ip && ip.ipv4?
V4::Host[ip]
- elsif ip.ipv6?
+ elsif ip && ip.ipv6?
V6::Host[ip]
end
end
# Create an IPAddr from an Integer.
@@ -93,16 +107,30 @@
# Create an IPAddr from a String.
#
# @param address [String]
# @param mask [Integer, String] a netmask or prefix length
# @param family [Integer, Nil]
+ # @param classful [Boolean] controls the conversion of IPv4 addresses
+ # without a prefix length in CIDR notation. When false, these are assumed
+ # to be host networks (/32). When true, these are assumed to be classful
+ # (rfc791) networks, with an implicit prefix length. Has no effect on IPv6
+ # addresses.
# @return [IPAddr]
- def self.from_string(address, mask = nil, family: self::FAMILY)
+ def self.from_string(
+ address,
+ mask = nil,
+ family: self::FAMILY,
+ classful: false
+ )
if mask
new(address, family).mask(mask)
- else
+ elsif !classful || address.include?('/')
new(address, family)
+ else
+ ipaddr = new(address, family)
+ return ipaddr unless ipaddr.ipv4?
+ ipaddr.classful || ipaddr
end
end
# Convert an object to a prefix length.
#
@@ -228,29 +256,68 @@
def to_s(cidr: false, full: false)
better_to_s(cidr: cidr, full: full)
end
end
+ # An IPv4 address, 32 bits
class V4 < Base
specialize_constants Family::IPV4
REGEX = Regex::IPV4
+ NETWORK_CLASSES = {
+ new('0.0.0.0/1') => 8, # A
+ new('128.0.0.0/2') => 16, # B
+ new('192.0.0.0/3') => 24 # C
+ }.freeze
+
+ # If the address falls in one of the address classes defined in rfc791,
+ # return a new IPAddr with the appropriate prefix length, otherwise return
+ # nil.
+ #
+ # * Class A: networks of 16,777,216 addresses each,
+ # from 0.0.0.0/8 to 127.0.0.0/8
+ # * Class B: networks of 65,537 addresses each,
+ # from 128.0.0.0/16 to 191.255.0.0/16
+ # * Class C: networks of 256 addresses each,
+ # from 192.0.0.0/24 to 223.255.255.0/24
+ #
+ # @return [IPAddr::V4, nil]
+ def classful
+ prefix_length = classful_prefix_length || return
+ mask(prefix_length)
+ end
+
+ # If the address falls in one of the address classes defined in rfc791,
+ # return the corresponding prefix length, otherwise return nil.
+ #
+ # @return [Integer, nil]
+ def classful_prefix_length
+ key = NETWORK_CLASSES.keys.find do |block|
+ block.to_range(&:to_i).cover?(to_i)
+ end
+ NETWORK_CLASSES[key]
+ end
+
+ # An IPv4 host address, 32 bits
class Host < V4
include BetterIpaddr::HostMethods
end
end
+ # An IPv6 address, 128 bits
class V6 < Base
specialize_constants Family::IPV6
REGEX = Regex::IPV6
+ # An IPv6 host address, 128 bits
class Host < V6
include BetterIpaddr::HostMethods
end
end
+ # A MAC address, 48 bits
class MAC < Base
specialize_constants Family::EUI48
end
end