aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorshugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-09-07 16:15:45 +0000
committershugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-09-07 16:15:45 +0000
commitaf654b835c062009ab1175cf86fdad02d6498b98 (patch)
tree63366f8cd8af5234df80982933c574af1f376326
parent86a6dc2ca9f573395545823889521fc168a828e3 (diff)
downloadruby-af654b835c062009ab1175cf86fdad02d6498b98.tar.gz
* eval.c (rb_mod_s_used_refinements): new method
Module.used_refinements. based on the patch by Charlie Somerville. [Feature #7418] [ruby-core:49805] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56094 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog6
-rw-r--r--eval.c55
-rw-r--r--test/ruby/test_refinement.rb49
3 files changed, 110 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index fefbea8b9d..0e8c8a0d2c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Thu Sep 8 01:12:47 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * eval.c (rb_mod_s_used_refinements): new method
+ Module.used_refinements. based on the patch by Charlie
+ Somerville. [Feature #7418] [ruby-core:49805]
+
Wed Sep 7 17:50:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
* include/ruby/util.h (setenv): remove POSIX-noncompliant
diff --git a/eval.c b/eval.c
index 8c23603b5c..b66095735e 100644
--- a/eval.c
+++ b/eval.c
@@ -1311,6 +1311,59 @@ mod_using(VALUE self, VALUE module)
return self;
}
+static int
+used_refinements_i(VALUE _, VALUE mod, VALUE ary)
+{
+ ID id_defined_at;
+ CONST_ID(id_defined_at, "__defined_at__");
+ while (FL_TEST(rb_class_of(mod), RMODULE_IS_REFINEMENT)) {
+ rb_ary_push(ary, rb_attr_get(rb_class_of(mod), id_defined_at));
+ mod = RCLASS_SUPER(mod);
+ }
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * used_refinements -> array
+ *
+ * Returns an array of all active refinements in the current scope. The
+ * ordering of modules in the resulting array is not defined.
+ *
+ * module A
+ * refine Object do
+ * end
+ * end
+ *
+ * module B
+ * refine Object do
+ * end
+ * end
+ *
+ * using A
+ * using B
+ * p Module.used_refinements
+ *
+ * <em>produces:</em>
+ *
+ * [B, A]
+ */
+static VALUE
+rb_mod_s_used_refinements(void)
+{
+ const rb_cref_t *cref = rb_vm_cref();
+ VALUE ary = rb_ary_new();
+
+ while(cref) {
+ if(!NIL_P(CREF_REFINEMENTS(cref))) {
+ rb_hash_foreach(CREF_REFINEMENTS(cref), used_refinements_i, ary);
+ }
+ cref = CREF_NEXT(cref);
+ }
+
+ return rb_funcall(ary, rb_intern("uniq"), 0);
+}
+
void
rb_obj_call_init(VALUE obj, int argc, const VALUE *argv)
{
@@ -1645,6 +1698,8 @@ 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_singleton_method(rb_cModule, "used_refinements",
+ rb_mod_s_used_refinements, 0);
rb_undef_method(rb_cClass, "refine");
rb_undef_method(rb_cClass, "module_function");
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
index c9de8e83e5..1a82ad8373 100644
--- a/test/ruby/test_refinement.rb
+++ b/test/ruby/test_refinement.rb
@@ -1624,6 +1624,55 @@ class TestRefinement < Test::Unit::TestCase
MethodMissing.call_undefined_method
end
end
+
+ module VisibleRefinements
+ module RefA
+ refine Object do
+ def in_ref_a
+ end
+ end
+ end
+
+ module RefB
+ refine Object do
+ def in_ref_b
+ end
+ end
+ end
+
+ module RefC
+ using RefA
+
+ refine Object do
+ def in_ref_c
+ end
+ end
+ end
+
+ module Foo
+ using RefB
+ USED_REFS = Module.used_refinements
+ end
+
+ module Bar
+ using RefC
+ USED_REFS = Module.used_refinements
+ end
+
+ module Combined
+ using RefA
+ using RefB
+ USED_REFS = Module.used_refinements
+ end
+ end
+
+ def test_used_refinements
+ ref = VisibleRefinements
+ assert_equal [], Module.used_refinements
+ assert_equal [ref::RefB], ref::Foo::USED_REFS
+ assert_equal [ref::RefC], ref::Bar::USED_REFS
+ assert_equal [ref::RefB, ref::RefA], ref::Combined::USED_REFS
+ end
private