@@ -950,6 +950,140 @@ Init_enable_namespace(void)
950950 }
951951}
952952
953+ #ifdef RUBY_DEBUG
954+
955+ static const char *
956+ classname (VALUE klass )
957+ {
958+ VALUE p = RCLASS_CLASSPATH (klass );
959+ if (RTEST (p ))
960+ return RSTRING_PTR (p );
961+ if (RB_TYPE_P (klass , T_CLASS ) || RB_TYPE_P (klass , T_MODULE ) || RB_TYPE_P (klass , T_ICLASS ))
962+ return RSTRING_PTR (rb_inspect (klass ));
963+ return "NonClassValue" ;
964+ }
965+
966+ static enum rb_id_table_iterator_result
967+ dump_classext_methods_i (ID mid , VALUE _val , void * data )
968+ {
969+ VALUE ary = (VALUE )data ;
970+ rb_ary_push (ary , rb_id2str (mid ));
971+ return ID_TABLE_CONTINUE ;
972+ }
973+
974+ static enum rb_id_table_iterator_result
975+ dump_classext_constants_i (ID mid , VALUE _val , void * data )
976+ {
977+ VALUE ary = (VALUE )data ;
978+ rb_ary_push (ary , rb_id2str (mid ));
979+ return ID_TABLE_CONTINUE ;
980+ }
981+
982+ static void
983+ dump_classext_i (rb_classext_t * ext , bool is_prime , VALUE _ns , void * data )
984+ {
985+ char buf [4096 ];
986+ struct rb_id_table * tbl ;
987+ VALUE ary , res = (VALUE )data ;
988+
989+ snprintf (buf , 4096 , "Namespace %ld:%s classext %p\n" ,
990+ RCLASSEXT_NS (ext )-> ns_id , is_prime ? " prime" : "" , (void * )ext );
991+ rb_str_cat_cstr (res , buf );
992+
993+ snprintf (buf , 2048 , " Super: %s\n" , classname (RCLASSEXT_SUPER (ext )));
994+ rb_str_cat_cstr (res , buf );
995+
996+ tbl = RCLASSEXT_M_TBL (ext );
997+ if (tbl ) {
998+ ary = rb_ary_new_capa ((long )rb_id_table_size (tbl ));
999+ rb_id_table_foreach (RCLASSEXT_M_TBL (ext ), dump_classext_methods_i , (void * )ary );
1000+ rb_ary_sort_bang (ary );
1001+ snprintf (buf , 4096 , " Methods(%ld): " , RARRAY_LEN (ary ));
1002+ rb_str_cat_cstr (res , buf );
1003+ rb_str_concat (res , rb_ary_join (ary , rb_str_new_cstr ("," )));
1004+ rb_str_cat_cstr (res , "\n" );
1005+ }
1006+ else {
1007+ rb_str_cat_cstr (res , " Methods(0): .\n" );
1008+ }
1009+
1010+ tbl = RCLASSEXT_CONST_TBL (ext );
1011+ if (tbl ) {
1012+ ary = rb_ary_new_capa ((long )rb_id_table_size (tbl ));
1013+ rb_id_table_foreach (tbl , dump_classext_constants_i , (void * )ary );
1014+ rb_ary_sort_bang (ary );
1015+ snprintf (buf , 4096 , " Constants(%ld): " , RARRAY_LEN (ary ));
1016+ rb_str_cat_cstr (res , buf );
1017+ rb_str_concat (res , rb_ary_join (ary , rb_str_new_cstr ("," )));
1018+ rb_str_cat_cstr (res , "\n" );
1019+ }
1020+ else {
1021+ rb_str_cat_cstr (res , " Constants(0): .\n" );
1022+ }
1023+ }
1024+
1025+ static VALUE
1026+ rb_f_dump_classext (VALUE recv , VALUE klass )
1027+ {
1028+ /*
1029+ * The desired output String value is:
1030+ * Class: 0x88800932 (String) [singleton]
1031+ * Prime classext namespace(2,main), readable(t), writable(f)
1032+ * Non-prime classexts: 3
1033+ * Namespace 2: prime classext 0x88800933
1034+ * Super: Object
1035+ * Methods(43): aaaaa, bbbb, cccc, dddd, eeeee, ffff, gggg, hhhhh, ...
1036+ * Constants(12): FOO, Bar, ...
1037+ * Namespace 5: classext 0x88800934
1038+ * Super: Object
1039+ * Methods(43): aaaaa, bbbb, cccc, dddd, eeeee, ffff, gggg, hhhhh, ...
1040+ * Constants(12): FOO, Bar, ...
1041+ */
1042+ char buf [2048 ];
1043+ VALUE res ;
1044+ const rb_classext_t * ext ;
1045+ const rb_namespace_t * ns ;
1046+ st_table * classext_tbl ;
1047+
1048+ if (!(RB_TYPE_P (klass , T_CLASS ) || RB_TYPE_P (klass , T_MODULE ))) {
1049+ snprintf (buf , 2048 , "Non-class/module value: %p (%s)\n" , (void * )klass , rb_type_str (BUILTIN_TYPE (klass )));
1050+ return rb_str_new_cstr (buf );
1051+ }
1052+
1053+ if (RB_TYPE_P (klass , T_CLASS )) {
1054+ snprintf (buf , 2048 , "Class: %p (%s)%s\n" ,
1055+ (void * )klass , classname (klass ), RCLASS_SINGLETON_P (klass ) ? " [singleton]" : "" );
1056+ }
1057+ else {
1058+ snprintf (buf , 2048 , "Module: %p (%s)\n" , (void * )klass , classname (klass ));
1059+ }
1060+ res = rb_str_new_cstr (buf );
1061+
1062+ ext = RCLASS_EXT_PRIME (klass );
1063+ ns = RCLASSEXT_NS (ext );
1064+ snprintf (buf , 2048 , "Prime classext namespace(%ld,%s), readable(%s), writable(%s)\n" ,
1065+ ns -> ns_id ,
1066+ NAMESPACE_ROOT_P (ns ) ? "root" : (NAMESPACE_MAIN_P (ns ) ? "main" : "optional" ),
1067+ RCLASS_PRIME_CLASSEXT_READABLE_P (klass ) ? "t" : "f" ,
1068+ RCLASS_PRIME_CLASSEXT_WRITABLE_P (klass ) ? "t" : "f" );
1069+ rb_str_cat_cstr (res , buf );
1070+
1071+ classext_tbl = RCLASS_CLASSEXT_TBL (klass );
1072+ if (!classext_tbl ) {
1073+ rb_str_cat_cstr (res , "Non-prime classexts: 0\n" );
1074+ }
1075+ else {
1076+ snprintf (buf , 2048 , "Non-prime classexts: %zu\n" , st_table_size (classext_tbl ));
1077+ rb_str_cat_cstr (res , buf );
1078+ }
1079+
1080+ rb_class_classext_foreach (klass , dump_classext_i , (void * )res );
1081+
1082+ return res ;
1083+ }
1084+
1085+ #endif /* RUBY_DEBUG */
1086+
9531087/*
9541088 * Document-class: Namespace
9551089 *
@@ -977,8 +1111,13 @@ Init_Namespace(void)
9771111 namespace_define_loader_method ("require" );
9781112 namespace_define_loader_method ("require_relative" );
9791113 namespace_define_loader_method ("load" );
1114+
9801115 if (rb_namespace_available ()) {
9811116 rb_include_module (rb_cObject , rb_mNamespaceLoader );
1117+
1118+ #ifdef RUBY_DEBUG
1119+ rb_define_global_function ("dump_classext" , rb_f_dump_classext , 1 );
1120+ #endif
9821121 }
9831122
9841123 rb_define_singleton_method (rb_cNamespace , "enabled?" , rb_namespace_s_getenabled , 0 );
0 commit comments