Which approach is better: parametric module or an injecting class
method.

  # Generates identity/key methods based on specified attributes.
  #
  #   include EquateOn(:a, :b)
  #
  # is equivalent to including a module containing:
  #
  #   def ==(other)
  #     self.a == other.a && self.b == other.b
  #   end
  #
  #   def eql?(other)
  #     self.a.eql?(other.a) && self.b.eql?(other.b)
  #   end
  #
  #   def hash()
  #     self.a.hash ^ self.b.hash
  #   end
  #

  def EquateOn(*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"
    mod = Module.new
    mod.module_eval( code )
    mod
  end

- Or -

  # 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

T.