Better way to make struct with defaults?

I'm using the same ideas as Struct to quickly create a class that:
a) Has default values for the properties
b) Uses symbols inside #new to set the values (instead of argument order)

I have it working (code below) but whenever I construct a string for use with *_eval, I feel that I'm probably being boneheaded, and there's a better way to do it. What suggestions do people have for cleaning up and/or simplifying the following code?

def Struct.with_defaults( property_hash )
     klass = self.new( *property_hash.keys )
     klass.class_eval <<-ENDCODE
         def initialize( values={} )
             #{property_hash.map{ |prop,default|
                 "self.#{prop} = values[#{prop.inspect}] || #{default.inspect}"
             }.join("\n")}
         end
     ENDCODE
     klass
end

Person = Struct.with_defaults :sex=>'male', :age=>0, :name=>nil
gk = Person.new :name=>'Gavin', :age=>32
p gk
#=> #<struct Person sex="male", name="Gavin", age=32>

Gavin Kistner wrote:

I'm using the same ideas as Struct to quickly create a class that:
a) Has default values for the properties
b) Uses symbols inside #new to set the values (instead of argument order)

I have it working (code below) but whenever I construct a string for
use with *_eval, I feel that I'm probably being boneheaded, and there's
a better way to do it. What suggestions do people have for cleaning up
and/or simplifying the following code?

def Struct.with_defaults( property_hash )
    klass = self.new( *property_hash.keys )
    klass.class_eval <<-ENDCODE
        def initialize( values={} )
            #{property_hash.map{ |prop,default|
                "self.#{prop} = values[#{prop.inspect}] || #
{default.inspect}"
            }.join("\n")}
        end
    ENDCODE
    klass
end

Person = Struct.with_defaults :sex=>'male', :age=>0, :name=>nil
gk = Person.new :name=>'Gavin', :age=>32
p gk
#=> #<struct Person sex="male", name="Gavin", age=32>

def Struct.with_defaults( property_hash )
    klass = self.new( *property_hash.keys )

    default_setters = property_hash.map do |prop,default|
        ["#{prop}=".intern, prop, default]
    end

    klass.class_eval do
        define_method :initialize do |values|
            values ||= {}
            default_setters.each do |setter,prop,default|
                value = values.key?(prop) ? values[prop] : default
                send setter, value
            end
        end
    end
    klass
end

Person = Struct.with_defaults :sex=>'male', :age=>0, :name=>nil
gk = Person.new :name=>'Gavin', :age=>32
p gk

__END__

output:

#<struct Person sex="male", age=32, name="Gavin">

···

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407