Reputation: 1874
I'm working on a C extension for Ruby and I want to call a method which has required keyword arguments, like this:
class Word
def initialize(line:, col:, value:)
end
end
In C, I'm familiar, with calling Ruby methods via rb_funcall
and rb_funcallv
, but I can't figure out how to pass keyword arguments!
Here are a few things I've tried:
Pass a hash as the last positional argument with rb_funcall
:
VALUE kwargs = rb_hash_new();
rb_hash_aset(kwargs, rb_intern("name"), rb_str_new2(name));
// ...
rb_funcall(Word_Class, rb_intern("new"), 1, kwargs);
// result: ArgumentError: wrong number of arguments (given 1, expected 0)
Pass it as the last member of the argv
array with rb_funcallv
:
// initialize `kwargs` as above
VALUE argv = rb_ary_new();
rb_ary_push(argv, kwargs);
rb_funcallv(Word_Class, rb_intern("new"), 1, &argv);
// result: ArgumentError: wrong number of arguments (given 1, expected 0)
Pass 0
as argc
, even though argv
is length 1
:
// initialize `argv` as above
rb_funcallv(Word_Class, rb_intern("new"), 0, &argv);
// ArgumentError: missing keywords: line, col, value
Is it possible? How is it done? Is there anything else I can try?
Upvotes: 2
Views: 284
Reputation: 66837
You can pass in a hash. Note that to create symbol keys you need a call of the form ID2SYM(rb_intern(char*))
since rb_intern
returns an ID
, which ID2SYM
turns into an actual Ruby symbol.
VALUE kwargs = rb_hash_new();
rb_hash_aset(kwargs, ID2SYM(rb_intern("name")), rb_str_new2(name));
// ...
rb_funcall(Word_Class, ID2SYM(rb_intern("new")), 1, kwargs);
Upvotes: 2