RubyのIPAddrクラスが使いにくい

使いにくいというか、ネットワーク向きではない?
だからいくつかメソッドを追加してみた。
 

追加したメソッド

bit_count

selfのIPのビット数を返す。
IPv4なら32、IPv6なら128を返す。
 

cidr

selfのCIDRを返す。
なんでこれが取得出来ないのか不思議な位。
 

host_count

selfのネットワークに存在するホスト数。
 

network

selfが存在するネットワークアドレスを返す。
第1引数でCIDRの変更も出来る。
 

broadcast

selfが存在するブロードキャストアドレスを返す。
第1引数でCIDRの変更も出来る。
 

ソース

ネットワーク全体にPingを送るスクリプトを作った。

#!/usr/bin/ruby

require 'ipaddr'
require 'ping'


class IPAddr
  # Bit数
  def bit_count
    case @family
    when Socket::AF_INET
      return 32
    when Socket::AF_INET6
      return 128
    end
  end

  # CIDR
  def cidr
    cidr = 0
    i = 0
    bit = self.bit_count
    loop do
      if 0 < ((1<<i) & @mask_addr)
        return bit - i
      elsif bit<=i
        return 0
      end
      i += 1
    end
  end

  # ネットワークのホスト数
  def host_count
    return 2 ** (self.bit_count - self.cidr)
  end

  # ネットワークアドレス
  def network(cidr=nil)
    unless cidr
      cidr = IPAddr.new(@mask_addr, @family).to_s
    end
    return IPAddr.new("#{self.to_s}/#{cidr}")
  end

  # ブロードキャストアドレス
  def broadcast(cidr=nil)
    net = self.network(cidr)
    return net + net.host_count - 1
  end

  # 演算子 +
  def +(o)
    return IPAddr.new(self.to_i + o.to_i, @family)
  end

  # 演算子 -
  def -(o)
    return IPAddr.new(self.to_i - o.to_i, @family)
  end
end


class BroadcastPing
  def initialize(ipaddr)
    @ipaddr = ipaddr
    @t = []
    @ping = {}
  end

  def start
    network = @ipaddr.network
    broadcast = @ipaddr.broadcast
    i = 0
    loop do
      ip = network + i
      if @ipaddr.include?(ip)
        @t.push(Thread.new {
           @ping[ip] = self.run(ip)
        })
      else
        break
      end
      i += 1
    end
  end

  def join
    @t.each {|t| t.join}
  end

  def show
    @ping.keys.sort.each { |ip|
      result = @ping[ip]
      puts "#{ip}: #{result}"
    }
  end

  def run(ip)
    return Ping.pingecho(ip.to_s)
  end
end


def main
  network = nil
  begin
    network = IPAddr.new(ARGV.shift)
  rescue
    puts "Usage: bping.rb addr/cidr"
    return
  end

  bp = BroadcastPing.new(network)
  bp.start
  bp.join
  bp.show
end


main