diff options
| author | Satoshi Tagomori <s-tagomori@sakura.ad.jp> | 2025-07-27 11:02:52 +0900 |
|---|---|---|
| committer | Satoshi Tagomori <tagomoris@gmail.com> | 2025-09-29 01:15:38 +0900 |
| commit | a5df24fe010d3631b324a6aadcb2db5b32c270e5 (patch) | |
| tree | 176135508c4dbc535aaf156a0c523f0e835ba9a1 /namespace.c | |
| parent | bb21b619f01926fa99f6cca5ec8ac89389207d10 (diff) | |
Define a debug method Kernel#dump_classext only when RUBY_DEBUG is set
Diffstat (limited to 'namespace.c')
| -rw-r--r-- | namespace.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/namespace.c b/namespace.c index 7fc45f1688..e30d426d68 100644 --- a/namespace.c +++ b/namespace.c @@ -950,6 +950,140 @@ Init_enable_namespace(void) } } +#ifdef RUBY_DEBUG + +static const char * +classname(VALUE klass) +{ + VALUE p = RCLASS_CLASSPATH(klass); + if (RTEST(p)) + return RSTRING_PTR(p); + if (RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS)) + return RSTRING_PTR(rb_inspect(klass)); + return "NonClassValue"; +} + +static enum rb_id_table_iterator_result +dump_classext_methods_i(ID mid, VALUE _val, void *data) +{ + VALUE ary = (VALUE)data; + rb_ary_push(ary, rb_id2str(mid)); + return ID_TABLE_CONTINUE; +} + +static enum rb_id_table_iterator_result +dump_classext_constants_i(ID mid, VALUE _val, void *data) +{ + VALUE ary = (VALUE)data; + rb_ary_push(ary, rb_id2str(mid)); + return ID_TABLE_CONTINUE; +} + +static void +dump_classext_i(rb_classext_t *ext, bool is_prime, VALUE _ns, void *data) +{ + char buf[4096]; + struct rb_id_table *tbl; + VALUE ary, res = (VALUE)data; + + snprintf(buf, 4096, "Namespace %ld:%s classext %p\n", + RCLASSEXT_NS(ext)->ns_id, is_prime ? " prime" : "", (void *)ext); + rb_str_cat_cstr(res, buf); + + snprintf(buf, 2048, " Super: %s\n", classname(RCLASSEXT_SUPER(ext))); + rb_str_cat_cstr(res, buf); + + tbl = RCLASSEXT_M_TBL(ext); + if (tbl) { + ary = rb_ary_new_capa((long)rb_id_table_size(tbl)); + rb_id_table_foreach(RCLASSEXT_M_TBL(ext), dump_classext_methods_i, (void *)ary); + rb_ary_sort_bang(ary); + snprintf(buf, 4096, " Methods(%ld): ", RARRAY_LEN(ary)); + rb_str_cat_cstr(res, buf); + rb_str_concat(res, rb_ary_join(ary, rb_str_new_cstr(","))); + rb_str_cat_cstr(res, "\n"); + } + else { + rb_str_cat_cstr(res, " Methods(0): .\n"); + } + + tbl = RCLASSEXT_CONST_TBL(ext); + if (tbl) { + ary = rb_ary_new_capa((long)rb_id_table_size(tbl)); + rb_id_table_foreach(tbl, dump_classext_constants_i, (void *)ary); + rb_ary_sort_bang(ary); + snprintf(buf, 4096, " Constants(%ld): ", RARRAY_LEN(ary)); + rb_str_cat_cstr(res, buf); + rb_str_concat(res, rb_ary_join(ary, rb_str_new_cstr(","))); + rb_str_cat_cstr(res, "\n"); + } + else { + rb_str_cat_cstr(res, " Constants(0): .\n"); + } +} + +static VALUE +rb_f_dump_classext(VALUE recv, VALUE klass) +{ + /* + * The desired output String value is: + * Class: 0x88800932 (String) [singleton] + * Prime classext namespace(2,main), readable(t), writable(f) + * Non-prime classexts: 3 + * Namespace 2: prime classext 0x88800933 + * Super: Object + * Methods(43): aaaaa, bbbb, cccc, dddd, eeeee, ffff, gggg, hhhhh, ... + * Constants(12): FOO, Bar, ... + * Namespace 5: classext 0x88800934 + * Super: Object + * Methods(43): aaaaa, bbbb, cccc, dddd, eeeee, ffff, gggg, hhhhh, ... + * Constants(12): FOO, Bar, ... + */ + char buf[2048]; + VALUE res; + const rb_classext_t *ext; + const rb_namespace_t *ns; + st_table *classext_tbl; + + if (!(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE))) { + snprintf(buf, 2048, "Non-class/module value: %p (%s)\n", (void *)klass, rb_type_str(BUILTIN_TYPE(klass))); + return rb_str_new_cstr(buf); + } + + if (RB_TYPE_P(klass, T_CLASS)) { + snprintf(buf, 2048, "Class: %p (%s)%s\n", + (void *)klass, classname(klass), RCLASS_SINGLETON_P(klass) ? " [singleton]" : ""); + } + else { + snprintf(buf, 2048, "Module: %p (%s)\n", (void *)klass, classname(klass)); + } + res = rb_str_new_cstr(buf); + + ext = RCLASS_EXT_PRIME(klass); + ns = RCLASSEXT_NS(ext); + snprintf(buf, 2048, "Prime classext namespace(%ld,%s), readable(%s), writable(%s)\n", + ns->ns_id, + NAMESPACE_ROOT_P(ns) ? "root" : (NAMESPACE_MAIN_P(ns) ? "main" : "optional"), + RCLASS_PRIME_CLASSEXT_READABLE_P(klass) ? "t" : "f", + RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass) ? "t" : "f"); + rb_str_cat_cstr(res, buf); + + classext_tbl = RCLASS_CLASSEXT_TBL(klass); + if (!classext_tbl) { + rb_str_cat_cstr(res, "Non-prime classexts: 0\n"); + } + else { + snprintf(buf, 2048, "Non-prime classexts: %zu\n", st_table_size(classext_tbl)); + rb_str_cat_cstr(res, buf); + } + + rb_class_classext_foreach(klass, dump_classext_i, (void *)res); + + return res; +} + +#endif /* RUBY_DEBUG */ + /* * Document-class: Namespace * @@ -977,8 +1111,13 @@ Init_Namespace(void) namespace_define_loader_method("require"); namespace_define_loader_method("require_relative"); namespace_define_loader_method("load"); + if (rb_namespace_available()) { rb_include_module(rb_cObject, rb_mNamespaceLoader); + +#ifdef RUBY_DEBUG + rb_define_global_function("dump_classext", rb_f_dump_classext, 1); +#endif } rb_define_singleton_method(rb_cNamespace, "enabled?", rb_namespace_s_getenabled, 0); |
