Project

General

Profile

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

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

View differences:

class.c
1065 1065
    return ary;
1066 1066
}
1067 1067

  
1068
static void
1069
add_descendents(VALUE klass, VALUE hash)
1070
{
1071
    rb_subclass_entry_t *e;
1072

  
1073
    if (CLASS_OF(klass) &&
1074
	BUILTIN_TYPE(klass) != T_ICLASS) {
1075
	rb_hash_aset(hash, klass, Qnil);
1076
    }
1077
    for (e = RCLASS_EXT(klass)->subclasses; e; e = e->next) {
1078
	add_descendents(e->klass, hash);
1079
    }
1080
}
1081

  
1082
/*
1083
 *  call-seq:
1084
 *     mod.descendents -> array
1085
 *
1086
 *  Returns a list of modules including <i>mod</i> or a subclass of
1087
 *  <i>mod</i> (including <i>mod</i> itself).
1088
 *
1089
 *     module A
1090
 *     end
1091
 *
1092
 *     module B
1093
 *       include A
1094
 *     end
1095
 *
1096
 *     module C
1097
 *       include A
1098
 *     end
1099
 *
1100
 *     A.descendents    #=> [A, C, B]
1101
 */
1102

  
1103
VALUE
1104
rb_mod_descendents(VALUE mod)
1105
{
1106
    VALUE hash = rb_hash_new();
1107

  
1108
    rb_funcall(hash, rb_intern("compare_by_identity"), 0);
1109
    add_descendents(mod, hash);
1110
    return rb_funcall(hash, rb_intern("keys"), 0);
1111
}
1112

  
1068 1113
#define VISI(x) ((x)&NOEX_MASK)
1069 1114
#define VISI_CHECK(x,f) (VISI(x) == (f))
1070 1115

  
include/ruby/intern.h
199 199
VALUE rb_mod_included_modules(VALUE);
200 200
VALUE rb_mod_include_p(VALUE, VALUE);
201 201
VALUE rb_mod_ancestors(VALUE);
202
VALUE rb_mod_descendents(VALUE);
202 203
VALUE rb_class_instance_methods(int, VALUE*, VALUE);
203 204
VALUE rb_class_public_instance_methods(int, VALUE*, VALUE);
204 205
VALUE rb_class_protected_instance_methods(int, VALUE*, VALUE);
object.c
3377 3377
    rb_define_method(rb_cModule, "include?", rb_mod_include_p, 1); /* in class.c */
3378 3378
    rb_define_method(rb_cModule, "name", rb_mod_name, 0);  /* in variable.c */
3379 3379
    rb_define_method(rb_cModule, "ancestors", rb_mod_ancestors, 0); /* in class.c */
3380
    rb_define_method(rb_cModule, "descendents", rb_mod_descendents, 0); /* in class.c */
3380 3381

  
3381 3382
    rb_define_private_method(rb_cModule, "attr", rb_mod_attr, -1);
3382 3383
    rb_define_private_method(rb_cModule, "attr_reader", rb_mod_attr_reader, -1);
test/ruby/test_module.rb
208 208
    assert_equal([String, Comparable, Object, Kernel, BasicObject], String.ancestors - mixins)
209 209
  end
210 210

  
211
  private def assert_same_set(expected, actual)
212
    assert_equal(expected.sort_by(&:object_id),
213
                 actual.sort_by(&:object_id))
214
  end
215

  
216
  def test_descendents
217
    assert_same_set([Mixin, User], Mixin.descendents)
218
    assert_same_set([User], User.descendents)
219

  
220
    m1 = Module.new
221
    m2 = Module.new { include m1 }
222
    m3 = Module.new { include m2 }
223
    assert_same_set([m1, m2, m3], m1.descendents)
224
    assert_same_set([m2, m3], m2.descendents)
225
    assert_same_set([m3], m3.descendents)
226

  
227
    c1 = Class.new
228
    c2 = Class.new(c1)
229
    c3 = Class.new(c2)
230
    assert_same_set([c1, c2, c3], c1.descendents)
231
    assert_same_set([c2, c3], c2.descendents)
232
    assert_same_set([c3], c3.descendents)
233
  end
234

  
211 235
  CLASS_EVAL = 2
212 236
  @@class_eval = 'b'
213 237

  
214
-