mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Support initializing structs via keyword arguments
This commit is contained in:
@@ -317,6 +317,46 @@ mrb_struct_initialize_withArg(mrb_state *mrb, mrb_int argc, const mrb_value *arg
|
||||
return self;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_struct_initialize_withKw(mrb_state *mrb, mrb_value hash, mrb_value self)
|
||||
{
|
||||
mrb_value members = struct_members(mrb, self);
|
||||
mrb_int member_count = num_members(mrb, self);
|
||||
|
||||
/* Initialize members from hash, defaulting to nil */
|
||||
for (mrb_int i = 0; i < member_count; i++) {
|
||||
mrb_value member = RARRAY_PTR(members)[i];
|
||||
if (mrb_hash_key_p(mrb, hash, member)) {
|
||||
mrb_value val = mrb_hash_get(mrb, hash, member);
|
||||
mrb_ary_set(mrb, self, i, val);
|
||||
}
|
||||
else {
|
||||
mrb_ary_set(mrb, self, i, mrb_nil_value());
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if all keys in the hash are valid members */
|
||||
mrb_value keys = mrb_hash_keys(mrb, hash);
|
||||
mrb_value invalid_keys = mrb_ary_new(mrb);
|
||||
|
||||
for (mrb_int i = 0; i < RARRAY_LEN(keys); i++) {
|
||||
mrb_value key = RARRAY_PTR(keys)[i];
|
||||
mrb_value include_result = mrb_funcall(mrb, members, "include?", 1, key);
|
||||
if (mrb_test(include_result) == FALSE) {
|
||||
mrb_ary_push(mrb, invalid_keys, key);
|
||||
}
|
||||
}
|
||||
|
||||
/* If there are any invalid keys, raise an error with all of them */
|
||||
if (RARRAY_LEN(invalid_keys) > 0) {
|
||||
mrb_value keys_str = mrb_funcall(mrb, invalid_keys, "join", 1, mrb_str_new_lit(mrb, ", "));
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown keyword%s: %S",
|
||||
RARRAY_LEN(invalid_keys) > 1 ? "s" : "", keys_str);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_struct_initialize(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
@@ -324,7 +364,13 @@ mrb_struct_initialize(mrb_state *mrb, mrb_value self)
|
||||
mrb_int argc;
|
||||
|
||||
mrb_get_args(mrb, "*", &argv, &argc);
|
||||
return mrb_struct_initialize_withArg(mrb, argc, argv, self);
|
||||
|
||||
/* If we get a single hash argument, treat it as keyword arguments */
|
||||
if (argc == 1 && mrb_hash_p(argv[0])) {
|
||||
return mrb_struct_initialize_withKw(mrb, argv[0], self);
|
||||
} else {
|
||||
return mrb_struct_initialize_withArg(mrb, argc, argv, self);
|
||||
}
|
||||
}
|
||||
|
||||
/* 15.2.18.4.9 */
|
||||
|
||||
@@ -229,3 +229,23 @@ assert 'method visibility with Struct' do
|
||||
c.new.bad!
|
||||
end
|
||||
end
|
||||
|
||||
assert "Struct initialize with keyword arguments" do
|
||||
c = Struct.new(:foo, :bar)
|
||||
|
||||
o = c.new(foo: 1, bar: 2)
|
||||
assert_equal 1, o.foo
|
||||
assert_equal 2, o.bar
|
||||
|
||||
o2 = c.new(bar: 1, foo: 2)
|
||||
assert_equal 2, o2.foo
|
||||
assert_equal 1, o2.bar
|
||||
|
||||
o3 = c.new(foo: :test)
|
||||
assert_equal :test, o3.foo
|
||||
assert_equal nil, o3.bar
|
||||
|
||||
assert_raise_with_message_pattern(ArgumentError, "unknown keywords: roo, baq") do
|
||||
c.new(foo: 1, roo: nil, baq: :test)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user