summaryrefslogtreecommitdiff
path: root/class.c
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2021-10-28 14:07:11 +0200
committerJean Boussier <jean.boussier@gmail.com>2021-11-23 10:50:44 +0100
commitc0c2b31a35e19a47b499b57807bc0a0f9325f6d3 (patch)
treeab7ee0710597903b43a8d086a3805059693de928 /class.c
parenta88b19d3d08447eeb7045621f02a844173d64203 (diff)
downloadruby-c0c2b31a35e19a47b499b57807bc0a0f9325f6d3.tar.gz
Add Class#subclasses
Implements [Feature #18273] Returns an array containing the receiver's direct subclasses without singleton classes.
Diffstat (limited to 'class.c')
-rw-r--r--class.c73
1 files changed, 55 insertions, 18 deletions
diff --git a/class.c b/class.c
index 52750aad79..6ad64a6efe 100644
--- a/class.c
+++ b/class.c
@@ -1377,6 +1377,7 @@ struct subclass_traverse_data
VALUE buffer;
long count;
long maxcount;
+ bool immediate_only;
};
static void
@@ -1390,8 +1391,38 @@ class_descendants_recursive(VALUE klass, VALUE v)
rb_ary_push(data->buffer, klass);
}
data->count++;
+ if (!data->immediate_only) {
+ rb_class_foreach_subclass(klass, class_descendants_recursive, v);
+ }
+ }
+ else {
+ rb_class_foreach_subclass(klass, class_descendants_recursive, v);
+ }
+}
+
+static VALUE
+class_descendants(VALUE klass, bool immediate_only)
+{
+ struct subclass_traverse_data data = { Qfalse, 0, -1, immediate_only };
+
+ // estimate the count of subclasses
+ rb_class_foreach_subclass(klass, class_descendants_recursive, (VALUE) &data);
+
+ // the following allocation may cause GC which may change the number of subclasses
+ data.buffer = rb_ary_new_capa(data.count);
+ data.maxcount = data.count;
+ data.count = 0;
+
+ size_t gc_count = rb_gc_count();
+
+ // enumerate subclasses
+ rb_class_foreach_subclass(klass, class_descendants_recursive, (VALUE) &data);
+
+ if (gc_count != rb_gc_count()) {
+ rb_bug("GC must not occur during the subclass iteration of Class#descendants");
}
- rb_class_foreach_subclass(klass, class_descendants_recursive, v);
+
+ return data.buffer;
}
/*
@@ -1415,26 +1446,32 @@ class_descendants_recursive(VALUE klass, VALUE v)
VALUE
rb_class_descendants(VALUE klass)
{
- struct subclass_traverse_data data = { Qfalse, 0, -1 };
-
- // estimate the count of subclasses
- rb_class_foreach_subclass(klass, class_descendants_recursive, (VALUE) &data);
-
- // the following allocation may cause GC which may change the number of subclasses
- data.buffer = rb_ary_new_capa(data.count);
- data.maxcount = data.count;
- data.count = 0;
-
- size_t gc_count = rb_gc_count();
+ return class_descendants(klass, false);
+}
- // enumerate subclasses
- rb_class_foreach_subclass(klass, class_descendants_recursive, (VALUE) &data);
- if (gc_count != rb_gc_count()) {
- rb_bug("GC must not occur during the subclass iteration of Class#descendants");
- }
+/*
+ * call-seq:
+ * subclasses -> array
+ *
+ * Returns an array of classes where the receiver is the
+ * direct superclass of the class, excluding singleton classes.
+ * The order of the returned array is not defined.
+ *
+ * class A; end
+ * class B < A; end
+ * class C < B; end
+ * class D < A; end
+ *
+ * A.subclasses #=> [D, B]
+ * B.subclasses #=> [C]
+ * C.subclasses #=> []
+ */
- return data.buffer;
+VALUE
+rb_class_subclasses(VALUE klass)
+{
+ return class_descendants(klass, true);
}
static void