aboutsummaryrefslogtreecommitdiffstats
path: root/eval.c
diff options
context:
space:
mode:
authorShugo Maeda <shugo@ruby-lang.org>2021-10-21 16:21:08 +0900
committerShugo Maeda <shugo@ruby-lang.org>2021-10-21 16:31:54 +0900
commit6606597109bdb535a150606323ce3d8f5750e1f6 (patch)
tree153eac378825ad9b17be9e8ae10d80572641f2c5 /eval.c
parent7185c00fcc330db8951b684f548ba3d10983bb92 (diff)
downloadruby-6606597109bdb535a150606323ce3d8f5750e1f6.tar.gz
Deprecate include/prepend in refinements and add Refinement#import_methods instead
Refinement#import_methods imports methods from modules. Unlike Module#include, it copies methods and adds them into the refinement, so the refinement is activated in the imported methods. [Bug #17429] [ruby-core:101639]
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c68
1 files changed, 67 insertions, 1 deletions
diff --git a/eval.c b/eval.c
index 880c63b88f..1cc699445f 100644
--- a/eval.c
+++ b/eval.c
@@ -1128,6 +1128,10 @@ rb_mod_include(int argc, VALUE *argv, VALUE module)
CONST_ID(id_append_features, "append_features");
CONST_ID(id_included, "included");
+ if (FL_TEST(module, RMODULE_IS_REFINEMENT)) {
+ rb_warn_deprecated_to_remove_at(3.2, "Refinement#include", NULL);
+ }
+
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
for (i = 0; i < argc; i++)
Check_Type(argv[i], T_MODULE);
@@ -1174,6 +1178,10 @@ rb_mod_prepend(int argc, VALUE *argv, VALUE module)
int i;
ID id_prepend_features, id_prepended;
+ if (FL_TEST(module, RMODULE_IS_REFINEMENT)) {
+ rb_warn_deprecated_to_remove_at(3.2, "Refinement#prepend", NULL);
+ }
+
CONST_ID(id_prepend_features, "prepend_features");
CONST_ID(id_prepended, "prepended");
@@ -1397,7 +1405,7 @@ rb_mod_refine(VALUE module, VALUE klass)
refinement = rb_hash_lookup(refinements, klass);
if (NIL_P(refinement)) {
VALUE superclass = refinement_superclass(klass);
- refinement = rb_module_new();
+ refinement = rb_refinement_new();
RCLASS_SET_SUPER(refinement, superclass);
FL_SET(refinement, RMODULE_IS_REFINEMENT);
CONST_ID(id_refined_class, "__refined_class__");
@@ -1502,6 +1510,63 @@ rb_mod_s_used_modules(VALUE _)
return rb_funcall(ary, rb_intern("uniq"), 0);
}
+struct refinement_import_methods_arg {
+ rb_cref_t *cref;
+ VALUE refinement;
+ VALUE module;
+};
+
+/* vm.c */
+rb_cref_t *rb_vm_cref_dup_without_refinements(const rb_cref_t *cref);
+
+static enum rb_id_table_iterator_result
+refinement_import_methods_i(ID key, VALUE value, void *data)
+{
+ const rb_method_entry_t *me = (const rb_method_entry_t *)value;
+ struct refinement_import_methods_arg *arg = (struct refinement_import_methods_arg *)data;
+
+ if (me->def->type != VM_METHOD_TYPE_ISEQ) {
+ rb_raise(rb_eArgError, "Can't import method: %"PRIsVALUE"#%"PRIsVALUE, rb_class_path(arg->module), rb_id2str(key));
+ }
+ rb_cref_t *new_cref = rb_vm_cref_dup_without_refinements(me->def->body.iseq.cref);
+ CREF_REFINEMENTS_SET(new_cref, CREF_REFINEMENTS(arg->cref));
+ rb_add_method_iseq(arg->refinement, key, me->def->body.iseq.iseqptr, new_cref, METHOD_ENTRY_VISI(me));
+ return ID_TABLE_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * import_methods(module, ...) -> self
+ *
+ * Imports methods from modules. Unlike Module#include,
+ * Refinement#import_methods copies methods and adds them into the refinement,
+ * so the refinement is activated in the imported methods.
+ */
+
+static VALUE
+refinement_import_methods(int argc, VALUE *argv, VALUE refinement)
+{
+ int i;
+ struct refinement_import_methods_arg arg;
+
+ rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
+ for (i = 0; i < argc; i++) {
+ Check_Type(argv[i], T_MODULE);
+ if (RCLASS_SUPER(argv[i])) {
+ rb_warn("%"PRIsVALUE" has ancestors, but Refinement#import_methods doesn't import their methods", rb_class_path(argv[i]));
+ }
+ }
+ arg.cref = rb_vm_cref_replace_with_duplicated_cref();
+ arg.refinement = refinement;
+ for (i = 0; i < argc; i++) {
+ arg.module = argv[i];
+ struct rb_id_table *m_tbl = RCLASS_M_TBL(argv[i]);
+ if (!m_tbl) continue;
+ rb_id_table_foreach(m_tbl, refinement_import_methods_i, &arg);
+ }
+ return refinement;
+}
+
void
rb_obj_call_init(VALUE obj, int argc, const VALUE *argv)
{
@@ -1885,6 +1950,7 @@ Init_eval(void)
rb_define_singleton_method(rb_cModule, "used_modules",
rb_mod_s_used_modules, 0);
rb_undef_method(rb_cClass, "refine");
+ rb_define_private_method(rb_cRefinement, "import_methods", refinement_import_methods, -1);
rb_undef_method(rb_cClass, "module_function");