Hi Tanaka,

I don't understand why DNS::Name#== requires both to be absolute if one
is.

Is this really necessary/useful? It surprises me.

Also, I have a set of comparison operations for Resolv::DNS::Name.

I copied the style (and docs) from Module/hierarchy comparisons, because
I think there is some similarity.

Comments?

If you will accept, I will send patch and changelog.

Thanks,
Sam

Below is implementation, followed by unit test so you can see behaviour.


    # DNS names are hierarchical in a similar sense to ruby classes/modules, and the
    # comparison operators are defined similarly to those of Module. A name is
    # +<+ another if it is a subdomain.
    #   www.example.com < example.com # -> true
    #   example.com < example.com # -> false
    #   example.com <= example.com # -> true
    #   com < example.com # -> false
    #   bar.com < example.com # -> nil
    #
    # Note that #== does not consider two names equal if they differ in whether
    # they are #absolute?, but #equal? considers only the label when comparing
    # names.
    class Name
      def inspect
        n = to_s
        n << '.' if absolute?
        return n
      end

      def equal?(name)
        n = Name.create(name)

        @labels == n.to_a
      end

      def related?(name)
        n = Name.create(name)

        l = length < n.length ? length : n.length

        @labels[-l, l] == n.to_a[-l, l]
      end

      def lt?(name)
        n = Name.create(name)
        length > n.length && to_a[-n.length, n.length] == n.to_a
      end


      # Summary:
      #   name < other   =>  true, false, or nil
      # 
      # Returns true if +name+ is a subdomain of +other+. Returns 
      # <code>nil</code> if there's no relationship between the two. 
      def <(name)
        n = Name.create(name)

        return nil unless self.related?(n)

        lt?(n)
      end

      # Summary:
      #   name > other   =>  true, false, or nil
      # 
      # Same as +other < name+, see #<.
      def >(name)
        n = Name.create(name)

        n < self
      end

      # Summary:
      #   name <= other   =>  true, false, or nil
      # 
      # Returns true if +name+ is a subdomain of +other+ or is the same as
      # +other+. Returns <code>nil</code> if there's no relationship between
      # the two. 
      def <=(name)
        n = Name.create(name)
        self.equal?(n) || self < n
      end

      # Summary:
      #   name >= other   =>  true, false, or nil
      # 
      # Returns true if +name+ is an ancestor of +other+, or the two DNS names
      # are the same. Returns <code>nil</code> if there's no relationship
      # between the two. 
      def >=(name)
        n = Name.create(name)
        self.equal?(n) || self > n
      end

      # Summary:
      #     name <=> other   => -1, 0, +1, nil
      #  
      # Returns -1 if +name+ is a subdomain of +other+, 0 if
      # +name+ is the same as +other+, and +1 if +other+ is a subdomain of
      # +name+, or nil if +name+ has no relationship with +other+.
      def <=>(name)
        n = Name.create(name)

        return nil unless self.related?(n)

        return -1 if self.lt?(n)
        return +1 if n.lt?(self)
        # must be #equal?
        return  0
      end

    end

require 'test/unit'

Name = Resolv::DNS::Name

class TestDnsName < Test::Unit::TestCase

  def test_what_I_think_are_odd_behaviours
    # Why can't test against strings?
    assert_equal(false, Name.create("example.CoM") ==   "example.com")
    assert_equal(false, Name.create("example.CoM").eql?("example.com"))

    # Why does making it absolute mean they aren't equal?
    assert_equal(false, Name.create("example.CoM").eql?(Name.create("example.com.")))
    assert_equal(false, Name.create("example.CoM") ==   Name.create("example.com."))
  end

  def test_CoMparisons

    assert_equal(true,  Name.create("example.CoM").eql?(Name.create("example.com")))
    assert_equal(true,  Name.create("example.CoM") ==   Name.create("example.com"))

    assert_equal(true,  Name.create("example.CoM").equal?("example.com."))
    assert_equal(true,  Name.create("example.CoM").equal?("example.com"))

    assert_equal(true,  Name.create("www.example.CoM") <   "example.com")
    assert_equal(true,  Name.create("www.example.CoM") <=  "example.com")
    assert_equal(-1,    Name.create("www.example.CoM") <=> "example.com")
    assert_equal(false, Name.create("www.example.CoM") >=  "example.com")
    assert_equal(false, Name.create("www.example.CoM") >   "example.com")

    assert_equal(false, Name.create("example.CoM") <   "example.com")
    assert_equal(true,  Name.create("example.CoM") <=  "example.com")
    assert_equal(0,     Name.create("example.CoM") <=> "example.com")
    assert_equal(true,  Name.create("example.CoM") >=  "example.com")
    assert_equal(false, Name.create("example.CoM") >   "example.com")

    assert_equal(false, Name.create("CoM") <   "example.com")
    assert_equal(false, Name.create("CoM") <=  "example.com")
    assert_equal(+1,    Name.create("CoM") <=> "example.com")
    assert_equal(true,  Name.create("CoM") >=  "example.com")
    assert_equal(true,  Name.create("CoM") >   "example.com")

    assert_equal(nil,   Name.create("bar.CoM") <   "example.com")
    assert_equal(nil,   Name.create("bar.CoM") <=  "example.com")
    assert_equal(nil,   Name.create("bar.CoM") <=> "example.com")
    assert_equal(nil,   Name.create("bar.CoM") >=  "example.com")
    assert_equal(nil,   Name.create("bar.CoM") >   "example.com")

    assert_equal(nil,   Name.create("net.") <   "com")
    assert_equal(nil,   Name.create("net.") <=  "com")
    assert_equal(nil,   Name.create("net.") <=> "com")
    assert_equal(nil,   Name.create("net.") >=  "com")
    assert_equal(nil,   Name.create("net.") >   "com")

  end
end