summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--struct.c23
-rw-r--r--test/ruby/test_data.rb16
2 files changed, 22 insertions, 17 deletions
diff --git a/struct.c b/struct.c
index d6cad575c5..35715b2258 100644
--- a/struct.c
+++ b/struct.c
@@ -1820,10 +1820,12 @@ rb_data_initialize_m(int argc, const VALUE *argv, VALUE self)
arg.self = self;
arg.unknown_keywords = Qnil;
rb_hash_foreach(argv[0], struct_hash_set_i, (VALUE)&arg);
+ // Freeze early before potentially raising, so that we don't leave an
+ // unfrozen copy on the heap, which could get exposed via ObjectSpace.
+ OBJ_FREEZE_RAW(self);
if (arg.unknown_keywords != Qnil) {
rb_exc_raise(rb_keyword_error_new("unknown", arg.unknown_keywords));
}
- OBJ_FREEZE_RAW(self);
return Qnil;
}
@@ -1875,22 +1877,9 @@ rb_data_with(int argc, const VALUE *argv, VALUE self)
return self;
}
- VALUE copy = rb_obj_alloc(rb_obj_class(self));
- rb_struct_init_copy(copy, self);
-
- struct struct_hash_set_arg arg;
- arg.self = copy;
- arg.unknown_keywords = Qnil;
- rb_hash_foreach(kwargs, struct_hash_set_i, (VALUE)&arg);
- // Freeze early before potentially raising, so that we don't leave an
- // unfrozen copy on the heap, which could get exposed via ObjectSpace.
- RB_OBJ_FREEZE_RAW(copy);
-
- if (arg.unknown_keywords != Qnil) {
- rb_exc_raise(rb_keyword_error_new("unknown", arg.unknown_keywords));
- }
-
- return copy;
+ VALUE h = rb_struct_to_h(self);
+ rb_hash_update_by(h, kwargs, NULL);
+ return rb_class_new_instance_kw(1, &h, rb_obj_class(self), TRUE);
}
/*
diff --git a/test/ruby/test_data.rb b/test/ruby/test_data.rb
index 3cafb365ed..9380076e1b 100644
--- a/test/ruby/test_data.rb
+++ b/test/ruby/test_data.rb
@@ -217,6 +217,22 @@ class TestData < Test::Unit::TestCase
end
end
+ def test_with_initialize
+ oddclass = Data.define(:odd) do
+ def initialize(odd:)
+ raise ArgumentError, "Not odd" unless odd.odd?
+ super(odd: odd)
+ end
+ end
+ assert_raise_with_message(ArgumentError, "Not odd") {
+ oddclass.new(odd: 0)
+ }
+ odd = oddclass.new(odd: 1)
+ assert_raise_with_message(ArgumentError, "Not odd") {
+ odd.with(odd: 2)
+ }
+ end
+
def test_memberless
klass = Data.define