mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
a196d8a5f3
Pointed out by @matz. https://github.com/mruby/mruby/pull/6391#issuecomment-2433662139
143 lines
3.9 KiB
C
143 lines
3.9 KiB
C
#include <mruby.h>
|
|
#include <mruby/class.h>
|
|
#include <mruby/string.h>
|
|
#include <mruby/array.h>
|
|
#include <mruby/proc.h>
|
|
#include <mruby/variable.h>
|
|
#include <mruby/internal.h>
|
|
#include <mruby/presym.h>
|
|
|
|
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_SET_FROZEN_FLAG(mrb_basic_ptr(name));
|
|
}
|
|
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 #=> #<Foo:0x000000010491a370>
|
|
* 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)
|
|
{
|
|
}
|