Project

General

Profile

Feature #9779 ยป 0001-Add-Module-descendents.patch

shugo (Shugo Maeda), 04/28/2014 07:00 AM

View differences:

class.c
return ary;
}
static void
add_descendents(VALUE klass, VALUE hash)
{
rb_subclass_entry_t *e;
if (CLASS_OF(klass) &&
BUILTIN_TYPE(klass) != T_ICLASS) {
rb_hash_aset(hash, klass, Qnil);
}
for (e = RCLASS_EXT(klass)->subclasses; e; e = e->next) {
add_descendents(e->klass, hash);
}
}
/*
* call-seq:
* mod.descendents -> array
*
* Returns a list of modules including <i>mod</i> or a subclass of
* <i>mod</i> (including <i>mod</i> itself).
*
* module A
* end
*
* module B
* include A
* end
*
* module C
* include A
* end
*
* A.descendents #=> [A, C, B]
*/
VALUE
rb_mod_descendents(VALUE mod)
{
VALUE hash = rb_hash_new();
rb_funcall(hash, rb_intern("compare_by_identity"), 0);
add_descendents(mod, hash);
return rb_funcall(hash, rb_intern("keys"), 0);
}
#define VISI(x) ((x)&NOEX_MASK)
#define VISI_CHECK(x,f) (VISI(x) == (f))
include/ruby/intern.h
VALUE rb_mod_included_modules(VALUE);
VALUE rb_mod_include_p(VALUE, VALUE);
VALUE rb_mod_ancestors(VALUE);
VALUE rb_mod_descendents(VALUE);
VALUE rb_class_instance_methods(int, VALUE*, VALUE);
VALUE rb_class_public_instance_methods(int, VALUE*, VALUE);
VALUE rb_class_protected_instance_methods(int, VALUE*, VALUE);
object.c
rb_define_method(rb_cModule, "include?", rb_mod_include_p, 1); /* in class.c */
rb_define_method(rb_cModule, "name", rb_mod_name, 0); /* in variable.c */
rb_define_method(rb_cModule, "ancestors", rb_mod_ancestors, 0); /* in class.c */
rb_define_method(rb_cModule, "descendents", rb_mod_descendents, 0); /* in class.c */
rb_define_private_method(rb_cModule, "attr", rb_mod_attr, -1);
rb_define_private_method(rb_cModule, "attr_reader", rb_mod_attr_reader, -1);
test/ruby/test_module.rb
assert_equal([String, Comparable, Object, Kernel, BasicObject], String.ancestors - mixins)
end
private def assert_same_set(expected, actual)
assert_equal(expected.sort_by(&:object_id),
actual.sort_by(&:object_id))
end
def test_descendents
assert_same_set([Mixin, User], Mixin.descendents)
assert_same_set([User], User.descendents)
m1 = Module.new
m2 = Module.new { include m1 }
m3 = Module.new { include m2 }
assert_same_set([m1, m2, m3], m1.descendents)
assert_same_set([m2, m3], m2.descendents)
assert_same_set([m3], m3.descendents)
c1 = Class.new
c2 = Class.new(c1)
c3 = Class.new(c2)
assert_same_set([c1, c2, c3], c1.descendents)
assert_same_set([c2, c3], c2.descendents)
assert_same_set([c3], c3.descendents)
end
CLASS_EVAL = 2
@@class_eval = 'b'
    (1-1/1)