mruby-class-ext: add `Class#subclasses` method.

parent d9bf7982
#include "mruby.h"
#include "mruby/class.h"
#include "mruby/string.h"
#include "mruby/array.h"
#include "mruby/proc.h"
static mrb_value
......@@ -56,6 +57,57 @@ mrb_mod_module_exec(mrb_state *mrb, mrb_value self)
return mrb_yield_cont(mrb, blk, self, argc, argv);
}
struct subclass_args {
struct RClass *c;
mrb_value ary;
};
static int
add_subclasses(mrb_state *mrb, struct RBasic *obj, void *data)
{
struct subclass_args *args = (struct subclass_args*)data;
if (obj->tt == MRB_TT_CLASS) {
struct RClass *c = (struct RClass*)obj;
if (mrb_class_real(c->super) == args->c) {
mrb_ary_push(mrb, args->ary, mrb_obj_value(obj));
}
}
return MRB_EACH_OBJ_OK;
}
/*
* 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 #=> []
*/
static mrb_value
mrb_class_subclasses(mrb_state *mrb, mrb_value self)
{
struct RClass *c;
mrb_value ary;
c = mrb_class_ptr(self);
ary = mrb_ary_new(mrb);
if (c->flags & MRB_FL_CLASS_IS_INHERITED) {
struct subclass_args arg = {c, ary};
mrb_objspace_each_objects(mrb, add_subclasses, &arg);
}
return ary;
}
void
mrb_mruby_class_ext_gem_init(mrb_state *mrb)
{
......@@ -65,6 +117,9 @@ mrb_mruby_class_ext_gem_init(mrb_state *mrb)
mrb_define_method(mrb, mod, "singleton_class?", mrb_mod_singleton_class_p, MRB_ARGS_NONE());
mrb_define_method(mrb, mod, "module_exec", mrb_mod_module_exec, MRB_ARGS_ANY()|MRB_ARGS_BLOCK());
mrb_define_method(mrb, mod, "class_exec", mrb_mod_module_exec, MRB_ARGS_ANY()|MRB_ARGS_BLOCK());
struct RClass *cls = mrb->module_class;
mrb_define_method(mrb, cls, "subclasses", mrb_class_subclasses, MRB_ARGS_NONE());
}
void
......
assert 'Class#subclasses' do
a = Class.new
b = Class.new(a)
c = Class.new(b)
d = Class.new(a)
a_sub = a.subclasses
assert_equal(2, a_sub.size)
assert_true(a_sub.include?(b))
assert_true(a_sub.include?(d))
assert_equal([c], b.subclasses)
assert_equal([], c.subclasses)
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment