summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShugo Maeda <shugo@ruby-lang.org>2022-01-05 17:47:29 +0900
committerShugo Maeda <shugo@ruby-lang.org>2022-01-05 17:47:29 +0900
commit54198c7b97d3d353f7ac233e0360034b6e7b6cb6 (patch)
tree62959e7071f3f044c860d28a20e985d6cea479f5
parent21ee5341f8fc4ca513295dff2148f7c203c908a7 (diff)
downloadruby-54198c7b97d3d353f7ac233e0360034b6e7b6cb6.tar.gz
Add Module#refinements and Refinement#refined_class [Feature #12737]
-rw-r--r--NEWS.md4
-rw-r--r--eval.c44
-rw-r--r--test/ruby/test_refinement.rb29
3 files changed, 76 insertions, 1 deletions
diff --git a/NEWS.md b/NEWS.md
index 82eb55b877..de0c5d37a9 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -28,6 +28,10 @@ Note: We're only listing outstanding class updates.
* Module
* Module.used_refinements has been added. [[Feature #14332]]
+ * Module#refinements has been added. [[Feature #12737]]
+
+* Refinement
+ * Refinement#refined_class has been added. [[Feature #12737]]
## Stdlib updates
diff --git a/eval.c b/eval.c
index 8103f52fa5..34c5d6ff85 100644
--- a/eval.c
+++ b/eval.c
@@ -1322,7 +1322,12 @@ rb_using_module(const rb_cref_t *cref, VALUE module)
rb_clear_method_cache_all();
}
-/*! \private */
+/*
+ * call-seq:
+ * refined_class -> class
+ *
+ * Return the class refined by the receiver.
+ */
VALUE
rb_refinement_module_get_refined_class(VALUE module)
{
@@ -1457,6 +1462,41 @@ mod_using(VALUE self, VALUE module)
return self;
}
+
+/*
+ * call-seq:
+ * refinements -> array
+ *
+ * Returns an array of modules defined within the receiver.
+ *
+ * module A
+ * refine Integer do
+ * end
+ *
+ * refine String do
+ * end
+ * end
+ *
+ * p A.refinements
+ *
+ * <em>produces:</em>
+ *
+ * [#<refinement:Integer@A>, #<refinement:String@A>]
+ */
+static VALUE
+mod_refinements(VALUE self)
+{
+ ID id_refinements;
+ VALUE refinements;
+
+ CONST_ID(id_refinements, "__refinements__");
+ refinements = rb_attr_get(self, id_refinements);
+ if (NIL_P(refinements)) {
+ return rb_ary_new();
+ }
+ return rb_hash_values(refinements);
+}
+
static int
used_modules_i(VALUE _, VALUE mod, VALUE ary)
{
@@ -1993,12 +2033,14 @@ Init_eval(void)
rb_define_private_method(rb_cModule, "prepend_features", rb_mod_prepend_features, 1);
rb_define_private_method(rb_cModule, "refine", rb_mod_refine, 1);
rb_define_private_method(rb_cModule, "using", mod_using, 1);
+ rb_define_method(rb_cModule, "refinements", mod_refinements, 0);
rb_define_singleton_method(rb_cModule, "used_modules",
rb_mod_s_used_modules, 0);
rb_define_singleton_method(rb_cModule, "used_refinements",
rb_mod_s_used_refinements, 0);
rb_undef_method(rb_cClass, "refine");
rb_define_private_method(rb_cRefinement, "import_methods", refinement_import_methods, -1);
+ rb_define_method(rb_cRefinement, "refined_class", rb_refinement_module_get_refined_class, 0);
rb_undef_method(rb_cClass, "module_function");
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
index c6de9ed958..017e4e33c1 100644
--- a/test/ruby/test_refinement.rb
+++ b/test/ruby/test_refinement.rb
@@ -1748,6 +1748,35 @@ class TestRefinement < Test::Unit::TestCase
assert_equal [ref::RefB::REF, ref::RefA::REF], ref::Combined::USED_REFS
end
+ def test_refinements
+ int_refinement = nil
+ str_refinement = nil
+ m = Module.new {
+ refine Integer do
+ int_refinement = self
+ end
+
+ refine String do
+ str_refinement = self
+ end
+ }
+ assert_equal([int_refinement, str_refinement], m.refinements)
+ end
+
+ def test_refined_class
+ refinements = Module.new {
+ refine Integer do
+ int_refinement = self
+ end
+
+ refine String do
+ str_refinement = self
+ end
+ }.refinements
+ assert_equal(Integer, refinements[0].refined_class)
+ assert_equal(String, refinements[1].refined_class)
+ end
+
def test_warn_setconst_in_refinmenet
bug10103 = '[ruby-core:64143] [Bug #10103]'
warnings = [