Preview Ruby 4.1 is a preview. It can change before the final release. Switch to Ruby 4.0 →
Module#ruby2_keywords
static VALUE
rb_mod_ruby2_keywords(int argc, VALUE *argv, VALUE module)
{
int i;
VALUE origin_class = RCLASS_ORIGIN(module);
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
rb_check_frozen(module);
rb_class_owner_check(module);
for (i = 0; i < argc; i++) {
VALUE v = argv[i];
ID name = rb_check_id(&v);
rb_method_entry_t *me;
VALUE defined_class;
if (!name) {
rb_print_undef_str(module, v);
}
me = search_method(origin_class, name, &defined_class);
if (!me && RB_TYPE_P(module, T_MODULE)) {
me = search_method(rb_cObject, name, &defined_class);
}
if (UNDEFINED_METHOD_ENTRY_P(me) ||
UNDEFINED_REFINED_METHOD_P(me->def)) {
rb_print_undef(module, name, METHOD_VISI_UNDEF);
}
if (module == defined_class || origin_class == defined_class) {
switch (me->def->type) {
case VM_METHOD_TYPE_ISEQ:
if (ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_rest &&
!ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_post &&
!ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_kw &&
!ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_kwrest) {
ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.ruby2_keywords = 1;
rb_clear_method_cache(module, name);
}
else {
rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or post arguments or method does not accept argument splat)", QUOTE_ID(name));
}
break;
case VM_METHOD_TYPE_BMETHOD: {
VALUE procval = me->def->body.bmethod.proc;
if (vm_block_handler_type(procval) == block_handler_type_proc) {
procval = vm_proc_to_block_handler(VM_BH_TO_PROC(procval));
}
if (vm_block_handler_type(procval) == block_handler_type_iseq) {
const struct rb_captured_block *captured = VM_BH_TO_ISEQ_BLOCK(procval);
const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
if (ISEQ_BODY(iseq)->param.flags.has_rest &&
!ISEQ_BODY(iseq)->param.flags.has_post &&
!ISEQ_BODY(iseq)->param.flags.has_kw &&
!ISEQ_BODY(iseq)->param.flags.has_kwrest) {
ISEQ_BODY(iseq)->param.flags.ruby2_keywords = 1;
rb_clear_method_cache(module, name);
}
else {
rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or post arguments or method does not accept argument splat)", QUOTE_ID(name));
}
break;
}
}
/* fallthrough */
default:
rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method not defined in Ruby)", QUOTE_ID(name));
break;
}
}
else {
rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (can only set in method defining module)", QUOTE_ID(name));
}
}
return Qnil;
}
Deprecated: will be removed in Ruby 4.4. Use ... argument forwarding or other delegation styles instead; they work correctly on Ruby 3.0 and later. See bugs.ruby-lang.org/issues/22205 for the schedule.
For the given method names, marks the method as passing keywords through a normal argument splat. This should only be called on methods that accept an argument splat (*args) but not explicit keywords or a keyword splat. It marks the method such that if the method is called with keyword arguments, the final hash argument is marked with a special flag such that if it is the final element of a normal argument splat to another method call, and that method call does not include explicit keywords or a keyword splat, the final element is interpreted as keywords. In other words, keywords will be passed through the method to other methods.
This should only be used for methods that delegate keywords to another method, and only for backwards compatibility with Ruby versions before 3.0. See www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/ for details on why ruby2_keywords exists and when and how to use it.
Ruby version changes
-
4.1
-
Module#ruby2_keywordsand top-levelruby2_keywordsare deprecated and will be removed in Ruby 4.4. [Feature #22205]
-