Skip to content

Commit 90ae6c9

Browse files
committed
Implement and spec rb_class_new_instance_kw()
1 parent 22b204b commit 90ae6c9

File tree

6 files changed

+58
-16
lines changed

6 files changed

+58
-16
lines changed

lib/cext/ABI_check.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
5
1+
6

lib/truffle/truffle/cext.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,15 @@ def rb_class_new_instance(klass, args)
11831183
obj
11841184
end
11851185

1186+
def rb_class_new_instance_kw(klass, args)
1187+
*args, kwargs = args
1188+
kwargs = Truffle::Type.rb_convert_type kwargs, Hash, :to_hash
1189+
1190+
obj = klass.send(:__allocate__)
1191+
obj.send(:initialize, *args, **kwargs)
1192+
obj
1193+
end
1194+
11861195
def rb_f_sprintf(args)
11871196
sprintf(*args)
11881197
end

spec/ruby/optional/capi/class_spec.rb

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,37 @@
108108

109109
describe "rb_class_new_instance" do
110110
it "allocates and initializes a new object" do
111-
o = @s.rb_class_new_instance(0, nil, CApiClassSpecs::Alloc)
111+
o = @s.rb_class_new_instance([], CApiClassSpecs::Alloc)
112112
o.class.should == CApiClassSpecs::Alloc
113113
o.initialized.should be_true
114114
end
115115

116116
it "passes arguments to the #initialize method" do
117-
o = @s.rb_class_new_instance(2, [:one, :two], CApiClassSpecs::Alloc)
117+
o = @s.rb_class_new_instance([:one, :two], CApiClassSpecs::Alloc)
118118
o.arguments.should == [:one, :two]
119119
end
120120
end
121121

122+
ruby_version_is "3.0" do
123+
describe "rb_class_new_instance_kw" do
124+
it "passes arguments and keywords to the #initialize method" do
125+
obj = @s.rb_class_new_instance_kw([{pos: 1}, {kw: 2}], CApiClassSpecs::KeywordAlloc)
126+
obj.args.should == [{pos: 1}]
127+
obj.kwargs.should == {kw: 2}
128+
129+
obj = @s.rb_class_new_instance_kw([{}], CApiClassSpecs::KeywordAlloc)
130+
obj.args.should == []
131+
obj.kwargs.should == {}
132+
end
133+
134+
it "raises TypeError if the last argument is not a Hash" do
135+
-> {
136+
@s.rb_class_new_instance_kw([42], CApiClassSpecs::KeywordAlloc)
137+
}.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
138+
end
139+
end
140+
end
141+
122142
describe "rb_include_module" do
123143
it "includes a module into a class" do
124144
c = Class.new

spec/ruby/optional/capi/ext/class_spec.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,15 @@ static VALUE class_spec_rb_class_new(VALUE self, VALUE super) {
6161
return rb_class_new(super);
6262
}
6363

64-
static VALUE class_spec_rb_class_new_instance(VALUE self,
65-
VALUE nargs, VALUE args,
66-
VALUE klass) {
67-
int c_nargs = FIX2INT(nargs);
68-
VALUE *c_args = (VALUE*)alloca(sizeof(VALUE) * c_nargs);
69-
int i;
70-
71-
for (i = 0; i < c_nargs; i++)
72-
c_args[i] = rb_ary_entry(args, i);
64+
static VALUE class_spec_rb_class_new_instance(VALUE self, VALUE args, VALUE klass) {
65+
return rb_class_new_instance(RARRAY_LENINT(args), RARRAY_PTR(args), klass);
66+
}
7367

74-
return rb_class_new_instance(c_nargs, c_args, klass);
68+
#ifdef RUBY_VERSION_IS_3_0
69+
static VALUE class_spec_rb_class_new_instance_kw(VALUE self, VALUE args, VALUE klass) {
70+
return rb_class_new_instance_kw(RARRAY_LENINT(args), RARRAY_PTR(args), klass, RB_PASS_KEYWORDS);
7571
}
72+
#endif
7673

7774
static VALUE class_spec_rb_class_real(VALUE self, VALUE object) {
7875
if(rb_type_p(object, T_FIXNUM)) {
@@ -171,7 +168,10 @@ void Init_class_spec(void) {
171168
rb_define_method(cls, "rb_class_protected_instance_methods", class_spec_rb_class_protected_instance_methods, -1);
172169
rb_define_method(cls, "rb_class_private_instance_methods", class_spec_rb_class_private_instance_methods, -1);
173170
rb_define_method(cls, "rb_class_new", class_spec_rb_class_new, 1);
174-
rb_define_method(cls, "rb_class_new_instance", class_spec_rb_class_new_instance, 3);
171+
rb_define_method(cls, "rb_class_new_instance", class_spec_rb_class_new_instance, 2);
172+
#ifdef RUBY_VERSION_IS_3_0
173+
rb_define_method(cls, "rb_class_new_instance_kw", class_spec_rb_class_new_instance_kw, 2);
174+
#endif
175175
rb_define_method(cls, "rb_class_real", class_spec_rb_class_real, 1);
176176
rb_define_method(cls, "rb_class_superclass", class_spec_rb_class_superclass, 1);
177177
rb_define_method(cls, "rb_cvar_defined", class_spec_cvar_defined, 2);

spec/ruby/optional/capi/fixtures/class.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ def initialize(*args)
1515
end
1616
end
1717

18+
class KeywordAlloc
19+
attr_reader :initialized, :args, :kwargs
20+
21+
def initialize(*args, **kwargs)
22+
@initialized = true
23+
@args = args
24+
@kwargs = kwargs
25+
end
26+
end
27+
1828
class Attr
1929
def initialize
2030
@foo, @bar, @baz = 1, 2, 3

src/main/c/cext/class.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,11 @@ VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass) {
8686
}
8787

8888
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat) {
89-
// Ignoring kw_splat for now
90-
return rb_class_new_instance(argc, argv, klass);
89+
if (kw_splat && argc > 0) {
90+
return RUBY_CEXT_INVOKE("rb_class_new_instance_kw", klass, rb_ary_new4(argc, argv));
91+
} else {
92+
return rb_class_new_instance(argc, argv, klass);
93+
}
9194
}
9295

9396
VALUE rb_cvar_defined(VALUE klass, ID id) {

0 commit comments

Comments
 (0)