summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2022-06-06 09:57:32 -0700
committerGitHub <noreply@github.com>2022-06-06 09:57:32 -0700
commit7cda7fbbdc14f4262afaa94cdeb5a5987f1eb01a (patch)
tree6f7da1ed9ce694564c932f9dcc15fd6b04b86c0b
parentb737998d25f1379117fbf11a578462e6ba12037e (diff)
downloadruby-7cda7fbbdc14f4262afaa94cdeb5a5987f1eb01a.tar.gz
Add Module#undefined_instance_methods
Implements [Feature #12655] Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
-rw-r--r--NEWS.md2
-rw-r--r--class.c24
-rw-r--r--internal/class.h1
-rw-r--r--object.c2
-rw-r--r--test/ruby/test_module.rb9
5 files changed, 38 insertions, 0 deletions
diff --git a/NEWS.md b/NEWS.md
index 556338bbda..fb43e86e7b 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -112,6 +112,7 @@ Note: We're only listing outstanding class updates.
* Module.used_refinements has been added. [[Feature #14332]]
* Module#refinements has been added. [[Feature #12737]]
* Module#const_added has been added. [[Feature #17881]]
+ * Module#undefined_instance_methods has been added. [[Feature #12655]]
* Proc
* Proc#dup returns an instance of subclass. [[Bug #17545]]
@@ -235,6 +236,7 @@ The following deprecated APIs are removed.
## Miscellaneous changes
[Feature #12005]: https://bugs.ruby-lang.org/issues/12005
+[Feature #12655]: https://bugs.ruby-lang.org/issues/12655
[Feature #12737]: https://bugs.ruby-lang.org/issues/12737
[Feature #13110]: https://bugs.ruby-lang.org/issues/13110
[Feature #14332]: https://bugs.ruby-lang.org/issues/14332
diff --git a/class.c b/class.c
index 7b91f06229..6db373edc1 100644
--- a/class.c
+++ b/class.c
@@ -1638,6 +1638,15 @@ ins_methods_pub_i(st_data_t name, st_data_t type, st_data_t ary)
return ins_methods_type_i(name, type, ary, METHOD_VISI_PUBLIC);
}
+static int
+ins_methods_undef_i(st_data_t name, st_data_t type, st_data_t ary)
+{
+ if ((rb_method_visibility_t)type == METHOD_VISI_UNDEF) {
+ ins_methods_push(name, ary);
+ }
+ return ST_CONTINUE;
+}
+
struct method_entry_arg {
st_table *list;
int recur;
@@ -1809,6 +1818,21 @@ rb_class_public_instance_methods(int argc, const VALUE *argv, VALUE mod)
/*
* call-seq:
+ * mod.undefined_instance_methods -> array
+ *
+ * Returns a list of the undefined instance methods defined in <i>mod</i>.
+ * The undefined methods of any ancestors are not included.
+ */
+
+VALUE
+rb_class_undefined_instance_methods(VALUE mod)
+{
+ VALUE include_super = Qfalse;
+ return class_instance_method_list(1, &include_super, mod, 0, ins_methods_undef_i);
+}
+
+/*
+ * call-seq:
* obj.methods(regular=true) -> array
*
* Returns a list of the names of public and protected methods of
diff --git a/internal/class.h b/internal/class.h
index 70e671b2c2..ae680564a6 100644
--- a/internal/class.h
+++ b/internal/class.h
@@ -149,6 +149,7 @@ VALUE rb_obj_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_obj_protected_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_obj_private_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_obj_public_methods(int argc, const VALUE *argv, VALUE obj);
+VALUE rb_class_undefined_instance_methods(VALUE mod);
VALUE rb_special_singleton_class(VALUE);
VALUE rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach);
VALUE rb_singleton_class_get(VALUE obj);
diff --git a/object.c b/object.c
index a07915606c..951cbdcf3a 100644
--- a/object.c
+++ b/object.c
@@ -4398,6 +4398,8 @@ InitVM_Object(void)
rb_class_protected_instance_methods, -1); /* in class.c */
rb_define_method(rb_cModule, "private_instance_methods",
rb_class_private_instance_methods, -1); /* in class.c */
+ rb_define_method(rb_cModule, "undefined_instance_methods",
+ rb_class_undefined_instance_methods, 0); /* in class.c */
rb_define_method(rb_cModule, "constants", rb_mod_constants, -1); /* in variable.c */
rb_define_method(rb_cModule, "const_get", rb_mod_const_get, -1);
diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb
index c7245ab2db..3dae3916ff 100644
--- a/test/ruby/test_module.rb
+++ b/test/ruby/test_module.rb
@@ -994,6 +994,15 @@ class TestModule < Test::Unit::TestCase
assert_equal([:bClass1], BClass.public_instance_methods(false))
end
+ def test_undefined_instance_methods
+ assert_equal([], AClass.undefined_instance_methods)
+ assert_equal([], BClass.undefined_instance_methods)
+ c = Class.new(AClass) {undef aClass}
+ assert_equal([:aClass], c.undefined_instance_methods)
+ c = Class.new(c)
+ assert_equal([], c.undefined_instance_methods)
+ end
+
def test_s_public
o = (c = Class.new(AClass)).new
assert_raise(NoMethodError, /private method/) {o.aClass1}