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 + * + * produces: + * + * [#, #] + */ +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 = [