#--
# NOTE Better off as a parameterized module?
#++

class Module

  # Generates identity/key methods based on specified attributes.
  #
  #  equate_on :a, :b
  #
  # _is equivalent to_
  #
  #   def ==(o)
  #     self.a == o.a && self.b == o.b
  #   end
  #
  #   def eql?(o)
  #     self.a.eql?(o.a) && self.b.eql?(o.b)
  #   end
  #
  #   def hash()
  #     self.a.hash ^ self.b.hash
  #   end
  #
  def equate_on(*fields)
    code = ""
    code << "def ==(o) "   << fields.map {|f| "self.#{f} == o.#{f}" }.join(" && ")    << " end\n"
    code << "def eql?(o) " << fields.map {|f| "self.#{f}.eql?(o.#{f})" }.join(" && ") << " end\n"
    code << "def hash() "  << fields.map {|f| "self.#{f}.hash" }.join(" ^ ")          << " end\n"
    class_eval( code )
    fields
  end

  # Deprecated usage.
  alias_method :key_attributes, :equate_on

end



#  _____         _
# |_   _|__  ___| |_
#   | |/ _ \/ __| __|
#   | |  __/\__ \ |_
#   |_|\___||___/\__|
#
=begin test

  require 'test/unit'

  class TCModule < Test::Unit::TestCase

    def test_equate_on
      c = Class.new
      c.class_eval { attr_accessor :a, :b ; equate_on :a,:b }
      c1,c2 = c.new,c.new
      c1.a = 10; c1.b = 20
      c2.a = 10; c2.b = 20
      assert_equal( c1, c2 )
      c1.a = 10; c1.b = 10
      c2.a = 10; c2.b = 20
      assert_not_equal( c1, c2 )
      c1.a = 10; c1.b = 20
      c2.a = 20; c2.b = 20
      assert_not_equal( c1, c2 )
    end

  end

=end
