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