Skip to content

Commit cf7c4f1

Browse files
committed
Add specs for rb_get_kwargs.
1 parent a44e30c commit cf7c4f1

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,30 @@ VALUE util_spec_rb_scan_args(VALUE self, VALUE argv, VALUE fmt, VALUE expected,
4444
return INT2NUM(result);
4545
}
4646

47+
static VALUE util_spec_rb_get_kwargs(VALUE self, VALUE keyword_hash, VALUE keys, VALUE required, VALUE optional) {
48+
int req = FIX2INT(required);
49+
int opt = FIX2INT(optional);
50+
int len = RARRAY_LEN(keys);
51+
52+
int values_len = req + (opt < 0 ? -1 - opt : opt);
53+
int i = 0;
54+
55+
ID *ids = malloc(sizeof(VALUE) * len);
56+
VALUE *results = malloc(sizeof(VALUE) * values_len);
57+
int extracted = 0;
58+
VALUE ary = Qundef;
59+
60+
for (i = 0; i < len; i++) {
61+
ids[i] = SYM2ID(rb_ary_entry(keys, i));
62+
}
63+
64+
extracted = rb_get_kwargs(keyword_hash, ids, req, opt, results);
65+
ary = rb_ary_new_from_values(extracted, results);
66+
free(results);
67+
free(ids);
68+
return ary;
69+
}
70+
4771
static VALUE util_spec_rb_long2int(VALUE self, VALUE n) {
4872
return INT2NUM(rb_long2int(NUM2LONG(n)));
4973
}
@@ -64,6 +88,7 @@ static VALUE util_spec_rb_sourceline(VALUE self) {
6488
void Init_util_spec(void) {
6589
VALUE cls = rb_define_class("CApiUtilSpecs", rb_cObject);
6690
rb_define_method(cls, "rb_scan_args", util_spec_rb_scan_args, 4);
91+
rb_define_method(cls, "rb_get_kwargs", util_spec_rb_get_kwargs, 4);
6792
rb_define_method(cls, "rb_long2int", util_spec_rb_long2int, 1);
6893
rb_define_method(cls, "rb_iter_break", util_spec_rb_iter_break, 0);
6994
rb_define_method(cls, "rb_sourcefile", util_spec_rb_sourcefile, 0);

spec/ruby/optional/capi/util_spec.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,50 @@
154154
end
155155
end
156156

157+
describe "rb_get_kwargs" do
158+
it "extracts required arguments in the order requested" do
159+
h = { :a => 7, :b => 5 }
160+
@o.rb_get_kwargs(h, [:b, :a], 2, 0).should == [5, 7]
161+
h.should == {}
162+
end
163+
164+
it "extracts required and optional arguments in the order requested" do
165+
h = { :a => 7, :c => 12, :b => 5 }
166+
@o.rb_get_kwargs(h, [:b, :a, :c], 2, 1).should == [5, 7, 12]
167+
h.should == {}
168+
end
169+
170+
it "accepts nil instead of a hash when only optional arguments are requested" do
171+
h = nil
172+
@o.rb_get_kwargs(h, [:b, :a, :c], 0, 3).should == []
173+
h.should == nil
174+
end
175+
176+
it "raises an error if a required argument is not in the hash" do
177+
h = { :a => 7, :c => 12, :b => 5 }
178+
lambda { @o.rb_get_kwargs(h, [:b, :d], 2, 0) }.should raise_error(ArgumentError, /missing keyword: d/)
179+
h.should == {:a => 7, :c => 12}
180+
end
181+
182+
it "does not raise an error for an optional argument not in the hash" do
183+
h = { :a => 7, :b => 5 }
184+
@o.rb_get_kwargs(h, [:b, :a, :c], 2, 1).should == [5, 7]
185+
h.should == {}
186+
end
187+
188+
it "raises an error if there are additional arguments and optional is positive" do
189+
h = { :a => 7, :c => 12, :b => 5 }
190+
lambda { @o.rb_get_kwargs(h, [:b, :a], 2, 0) }.should raise_error(ArgumentError, /unknown keyword: c/)
191+
h.should == {:c => 12}
192+
end
193+
194+
it "leaves additional arguments in the hash if optional is negative" do
195+
h = { :a => 7, :c => 12, :b => 5 }
196+
@o.rb_get_kwargs(h, [:b, :a], 2, -1).should == [5, 7]
197+
h.should == {:c => 12}
198+
end
199+
end
200+
157201
platform_is wordsize: 64 do
158202
describe "rb_long2int" do
159203
it "raises a RangeError if the value is outside the range of a C int" do

0 commit comments

Comments
 (0)