# = nilcomparable.rb
#
# == Copyright (c) 2005 Thomas Sawyer, Paul Brannan
#
#   Ruby License
#
#   This module is free software. You may use, modify, and/or redistribute this
#   software under the same terms as Ruby.
#
#   This program is distributed in the hope that it will be useful, but WITHOUT
#   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
#   FOR A PARTICULAR PURPOSE.
#
# == Special Thanks
#
# Based on library from Paul Brannan's Ruby Treasures.
#
# == Author(s)
#
# * Thomas Sawyer
# * Paul Brannan

# CREDIT Thomas Sawyer
# CREDIT Paul Brannan

# Author::    Thomas Sawyer, Paul Brannan
# Copyright:: Copyright (c) 2005 Thomas Sawyer, Paul Brannan
# License::   Ruby License

# = NilComparable
#
# This microframework simply makes nil comparable, such that
# all things (except itself) are greater than it.
#
# == Usage
#
# The main effect is this.
#
#   nil <=> any_object  #=> -1
#
# To enable a class to compare against nil (reverse of the above),
# simply prepend a nil comparsion into the #<=> method of that class.
# For example:
#
#   class Foo
#
#     def initialize( value )
#       @value = value
#     end
#
#     def <=>( other )
#       return 1 if other.nil?  # nil comparison
#       @value <=> other
#     end
#
#   end
#
# To do so for a pre-existing class with a pre-existing #<=> method, you'll 
# need to overide the method. As an example let's make Numeric comparable to nil.
#
#   class Numeric
#
#     alias_method :compare_without_nil, :<=>
#     def <=>( other )
#       return 1 if other.nil?
#       compare_without_nil( other )
#     end
#
#   end
#
# Or more conveniently:
#
#   require 'facets/core/module/wrap_method'
#
#   Numeric.wrap_method(:<=>) do |prev, other|
#     return 1 if other.nil?
#     prev.call( other )
#   end
#
# == Note
#
# NilCompariable _was_ a module that could automatically make
# a class comparable to nil. But it only worked if the #<=> was
# previous defined, which isn't ideal. Since it is easy enough
# to use the above examples, we decided to deprecate the module
# and leave this as an explicit task for the end-programmer.
# Changing this behavior for built-in classes is not something
# to be done lightly anyway.

class NilClass

  include Comparable

  def <=>(x)
    x.nil? ? 0 : -1
  end

  alias_method( :cmp, :<=> )

  def succ; nil; end

end



=begin DEPRECATED

module NilComparable
 
  def self.included( mod )
    mod.class_eval %{
      if method_defined?( :<=> )
        alias_method :compare_without_nil, :<=>
      else
        def compare_without_nil( other )
          raise TypeError, "Cannot compare \#{self.inspect} to \#{other.inspect}"
        end
      end

      def <=>( other )
        return 1 if other.nil?
        compare_without_nil( other )
      end
    }
  end

end

=end



#  _____         _
# |_   _|__  ___| |_
#   | |/ _ \/ __| __|
#   | |  __/\__ \ |_
#   |_|\___||___/\__|
#

=begin testing

  require 'test/unit'

  class Mock < String
    alias_method :compare_without_nil, :<=>
    def <=>( other )
      return 1 if other.nil?
      compare_without_nil( other )
    end
  end

  class TC_NilClass_Comparable < Test::Unit::TestCase

    def test001
      assert_equal( 0, nil <=> nil )
      assert_equal( -1, nil <=> 4 )
      assert_equal( -1, nil <=> "a" )
      assert_equal( -1, nil <=> Object.new )
      assert_equal( 0, nil.cmp(nil) )
      assert( nil < 4 )
    end

    def test002
      m = Mock.new("A")
      assert_equal( 1, m <=> nil )
      assert_equal( -1, m <=> "B" )
      #assert_equal( 1, m.cmp(nil) )
      assert( m > nil )
    end

  end

=end

