#include #include #include #include #include #include #include #include static mrb_value mod_name(mrb_state *mrb, mrb_value self) { mrb_value name = mrb_class_path(mrb, mrb_class_ptr(self)); if (mrb_string_p(name)) { mrb_basic_ptr(name)->frozen = 1; } return name; } static mrb_value mod_singleton_class_p(mrb_state *mrb, mrb_value self) { return mrb_bool_value(mrb_sclass_p(self)); } /* * call-seq: * module_exec(arg...) {|var...| block } -> obj * class_exec(arg...) {|var...| block } -> obj * * Evaluates the given block in the context of the * class/module. The method defined in the block will belong * to the receiver. Any arguments passed to the method will be * passed to the block. This can be used if the block needs to * access instance variables. * * class Thing * end * Thing.class_exec{ * def hello() "Hello there!" end * } * puts Thing.new.hello() */ static mrb_value mod_module_exec(mrb_state *mrb, mrb_value self) { return mrb_object_exec(mrb, self, mrb_class_ptr(self)); } 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 class_subclasses(mrb_state *mrb, mrb_value self) { struct RClass *c = mrb_class_ptr(self); mrb_value 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; } /* * call-seq: * attached_object -> object * * Returns the object for which the receiver is the singleton class. * Raises an TypeError if the class is not a singleton class. * * class Foo; end * * Foo.singleton_class.attached_object #=> Foo * Foo.attached_object #=> TypeError: not a singleton class * Foo.new.singleton_class.attached_object #=> # * TrueClass.attached_object #=> TypeError: not a singleton class * NilClass.attached_object #=> TypeError: not a singleton class */ static mrb_value class_attached_object(mrb_state *mrb, mrb_value self) { struct RClass *c = mrb_class_ptr(self); if (c->tt != MRB_TT_SCLASS) { mrb_raise(mrb, E_TYPE_ERROR, "not a singleton class"); } return mrb_obj_iv_get(mrb, (struct RObject*)c, MRB_SYM(__attached__)); } void mrb_mruby_class_ext_gem_init(mrb_state *mrb) { struct RClass *mod = mrb->module_class; mrb_define_method_id(mrb, mod, MRB_SYM(name), mod_name, MRB_ARGS_NONE()); mrb_define_method_id(mrb, mod, MRB_SYM_Q(singleton_class), mod_singleton_class_p, MRB_ARGS_NONE()); mrb_define_method_id(mrb, mod, MRB_SYM(module_exec), mod_module_exec, MRB_ARGS_ANY()|MRB_ARGS_BLOCK()); mrb_define_method_id(mrb, mod, MRB_SYM(class_exec), mod_module_exec, MRB_ARGS_ANY()|MRB_ARGS_BLOCK()); struct RClass *cls = mrb->class_class; mrb_define_method_id(mrb, cls, MRB_SYM(subclasses), class_subclasses, MRB_ARGS_NONE()); mrb_define_method_id(mrb, cls, MRB_SYM(attached_object), class_attached_object, MRB_ARGS_NONE()); } void mrb_mruby_class_ext_gem_final(mrb_state *mrb) { }