いまいです。

#1877 はありがとうございました。

IPAddr のインスタンスがハッシュのキーに出来るようになったので、簡単な
Access Control List を書いてみたのですが、

>> RUBY_DESCRIPTION
=> "ruby 1.9.2dev (2009-08-07 trunk 24440) [i686-linux]"
>> acl = {
?>   IPAddr.new("192.168.2.0/29") => :admin,
?>   IPAddr.new("192.168.2.0/24") => :user,
?> }
=> {#<IPAddr: IPv4:192.168.2.0/255.255.255.248>=>:admin, #<IPAddr: IPv4:192.168.2.0/255.255.255.0>=>:user}
>> acl.select{|r, | r === "192.168.2.56"}.max.last
=> :user
>> acl.select{|r, | r === "192.168.2.1"}.max.last
=> :user

と、ちょっと残念な感じです。<=> で、@addr が同じ場合は @mask_addr の大
きい方が IPAddr として大きいとすると、ネットマスクの長い方が採用される
ようなイメージでうれしい気がするのですが、どうでしょうか?

また、これで(というか元から?) IPAddr#== は不要な気がするのですが、何
か見落としてるでしょうか? 

IPAddr.new("192.168.2.0/24") == IPAddr.new("192.168.2.0/32")

が true から false に変わるという仕様変更なのですが、どうでしょうか?
--
Nobuhiro IMAI <nov / yo.rim.or.jp>
Key fingerprint = F39E D552 545D 7C64 D690  F644 5A15 746C BD8E 7106


Index: lib/ipaddr.rb
===================================================================
--- lib/ipaddr.rb	(revision 24440)
+++ lib/ipaddr.rb	(working copy)
@@ -133,16 +133,10 @@ class IPAddr
   # Returns a new ipaddr built by bitwise negation.
   def ~
     return self.clone.set(addr_mask(~@addr))
   end
 
-  # Returns true if two ipaddrs are equal.
-  def ==(other)
-    other = coerce_other(other)
-    return @family == other.family && @addr == other.to_i
-  end
-
   # Returns a new ipaddr built by masking IP address with the given
   # prefixlen/netmask. (e.g. 8, 64, "255.255.255.0", etc.)
   def mask(prefixlen)
     return self.clone.mask!(prefixlen)
   end
@@ -325,11 +319,11 @@ class IPAddr
   def <=>(other)
     other = coerce_other(other)
 
     return nil if other.family != @family
 
-    return @addr <=> other.to_i
+    return [@addr, @mask_addr] <=> [other.to_i, other.mask_addr]
   end
   include Comparable
 
   # Checks equality used by Hash.
   def eql?(other)
@@ -372,10 +366,12 @@ class IPAddr
 		   af, _to_string(@addr), _to_string(@mask_addr))
   end
 
   protected
 
+  attr_reader :mask_addr
+
   def set(addr, *family)
     case family[0] ? family[0] : @family
     when Socket::AF_INET
       if addr < 0 || addr > IN4MASK
 	raise ArgumentError, "invalid address"
@@ -789,15 +785,24 @@ class TC_Operator < Test::Unit::TestCase
     a = ~@in6_addr_any
     assert_equal(IN6MASK128, a.to_s)
     assert_equal("::", @in6_addr_any.to_s)
   end
 
-  def test_equal
-    assert_equal(true, @a == IPAddr.new("3ffe:505:2::"))
+  def test_compare
+    assert_equal(true, @a == IPAddr.new("3ffe:505:2::/48"))
+    assert_equal(false, @a == IPAddr.new("3ffe:505:2::"))
     assert_equal(false, @a == IPAddr.new("3ffe:505:3::"))
     assert_equal(true, @a != IPAddr.new("3ffe:505:3::"))
-    assert_equal(false, @a != IPAddr.new("3ffe:505:2::"))
+    assert_equal(false, @a != IPAddr.new("3ffe:505:2::/48"))
+    x = IPAddr.new("3ffe:505:3::/48")
+    y = IPAddr.new("3ffe:505:2::/64")
+    assert_equal(true, @a < x)
+    assert_equal(true, @a < y)
+    assert_equal(false, x < y)
+    min, max = [y, x, @a].minmax
+    assert_equal(@a, min)
+    assert_equal(x, max)
   end
 
   def test_mask
     a = @a.mask(32)
     assert_equal("3ffe:505::", a.to_s)