summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2021-10-27 15:36:00 -0700
committerJeremy Evans <code@jeremyevans.net>2021-12-09 12:59:37 -0800
commit27278150685e738f84105d09843d3ba371146c7a (patch)
tree2999a2683e67b9c63a9d44faac52e2d67152ee37
parent74159f7f3e58d8e5ef2e6ee430b7ffa2ade5d952 (diff)
downloadruby-27278150685e738f84105d09843d3ba371146c7a.tar.gz
Add {Method,UnboundMethod}#{public?,private?,protected?}
These methods allow for checking whether the method has that visibility. Implements [Feature #11689]
-rw-r--r--NEWS.md8
-rw-r--r--proc.c51
-rw-r--r--test/ruby/test_method.rb19
3 files changed, 77 insertions, 1 deletions
diff --git a/NEWS.md b/NEWS.md
index e1918b445e..d747db3f56 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -7,7 +7,7 @@ Note that each entry is kept to a minimum, see links for details.
## Language changes
-* The block arguments can be now be anonymous, if the block will
+* The block argument can be now be anonymous, if the block will
only be passed to another method. [[Feature #11256]]
```ruby
@@ -190,6 +190,11 @@ Outstanding ones only.
* MatchData#match_length is added [[Feature #18172]]
+* Method/UnboundMethod
+
+ * #public?, #private?, #protected have been added to both
+ Method and UnboundMethod. [[Feature #11689]]
+
* Module
* Module#prepend now modifies the ancestor chain if the receiver
@@ -459,6 +464,7 @@ See [the repository](https://github.com/ruby/error_highlight) in detail.
[Bug #4443]: https://bugs.ruby-lang.org/issues/4443
[Feature #6210]: https://bugs.ruby-lang.org/issues/6210
[Feature #11256]: https://bugs.ruby-lang.org/issues/11256
+[Feature #11689]: https://bugs.ruby-lang.org/issues/11689
[Feature #12194]: https://bugs.ruby-lang.org/issues/12194
[Feature #12495]: https://bugs.ruby-lang.org/issues/12495
[Feature #12913]: https://bugs.ruby-lang.org/issues/12913
diff --git a/proc.c b/proc.c
index 94b269d694..90ecf1e59b 100644
--- a/proc.c
+++ b/proc.c
@@ -3228,6 +3228,51 @@ method_super_method(VALUE method)
}
/*
+ * call-seq:
+ * meth.public? -> true or false
+ *
+ * Returns whether the method is public.
+ */
+
+static VALUE
+method_public_p(VALUE method)
+{
+ const struct METHOD *data;
+ TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
+ return RBOOL(METHOD_ENTRY_VISI(data->me) == METHOD_VISI_PUBLIC);
+}
+
+/*
+ * call-seq:
+ * meth.protected? -> true or false
+ *
+ * Returns whether the method is protected.
+ */
+
+static VALUE
+method_protected_p(VALUE method)
+{
+ const struct METHOD *data;
+ TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
+ return RBOOL(METHOD_ENTRY_VISI(data->me) == METHOD_VISI_PROTECTED);
+}
+
+/*
+ * call-seq:
+ * meth.private? -> true or false
+ *
+ * Returns whether the method is private.
+ */
+
+static VALUE
+method_private_p(VALUE method)
+{
+ const struct METHOD *data;
+ TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
+ return RBOOL(METHOD_ENTRY_VISI(data->me) == METHOD_VISI_PRIVATE);
+}
+
+/*
* call-seq:
* local_jump_error.exit_value -> obj
*
@@ -4163,6 +4208,9 @@ Init_Proc(void)
rb_define_method(rb_cMethod, "source_location", rb_method_location, 0);
rb_define_method(rb_cMethod, "parameters", rb_method_parameters, 0);
rb_define_method(rb_cMethod, "super_method", method_super_method, 0);
+ rb_define_method(rb_cMethod, "public?", method_public_p, 0);
+ rb_define_method(rb_cMethod, "protected?", method_protected_p, 0);
+ rb_define_method(rb_cMethod, "private?", method_private_p, 0);
rb_define_method(rb_mKernel, "method", rb_obj_method, 1);
rb_define_method(rb_mKernel, "public_method", rb_obj_public_method, 1);
rb_define_method(rb_mKernel, "singleton_method", rb_obj_singleton_method, 1);
@@ -4186,6 +4234,9 @@ Init_Proc(void)
rb_define_method(rb_cUnboundMethod, "source_location", rb_method_location, 0);
rb_define_method(rb_cUnboundMethod, "parameters", rb_method_parameters, 0);
rb_define_method(rb_cUnboundMethod, "super_method", method_super_method, 0);
+ rb_define_method(rb_cUnboundMethod, "public?", method_public_p, 0);
+ rb_define_method(rb_cUnboundMethod, "protected?", method_protected_p, 0);
+ rb_define_method(rb_cUnboundMethod, "private?", method_private_p, 0);
/* Module#*_method */
rb_define_method(rb_cModule, "instance_method", rb_mod_instance_method, 1);
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
index daf0ec73ca..da68787933 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -1181,6 +1181,25 @@ class TestMethod < Test::Unit::TestCase
assert_nil(super_method)
end
+ def test_method_visibility_predicates
+ v = Visibility.new
+ assert_equal(true, v.method(:mv1).public?)
+ assert_equal(true, v.method(:mv2).private?)
+ assert_equal(true, v.method(:mv3).protected?)
+ assert_equal(false, v.method(:mv2).public?)
+ assert_equal(false, v.method(:mv3).private?)
+ assert_equal(false, v.method(:mv1).protected?)
+ end
+
+ def test_unbound_method_visibility_predicates
+ assert_equal(true, Visibility.instance_method(:mv1).public?)
+ assert_equal(true, Visibility.instance_method(:mv2).private?)
+ assert_equal(true, Visibility.instance_method(:mv3).protected?)
+ assert_equal(false, Visibility.instance_method(:mv2).public?)
+ assert_equal(false, Visibility.instance_method(:mv3).private?)
+ assert_equal(false, Visibility.instance_method(:mv1).protected?)
+ end
+
def rest_parameter(*rest)
rest
end