const char* mrb_class_name(mrb_state *mrb, struct RClass* c) { mrb_value path = mrb_class_path(mrb, c); if (mrb_nil_p(path)) return 0; return mrb_str_ptr(path)->ptr; }
mrb_value mrb_class_path(mrb_state *mrb, struct RClass *c) { mrb_value path; const char *name; int len; path = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern(mrb, "__classpath__")); if (mrb_nil_p(path)) { struct RClass *outer = mrb_class_outer_module(mrb, c); mrb_sym sym = mrb_class_sym(mrb, c, outer); if (sym == 0) { return mrb_nil_value(); } else if (outer && outer != mrb->object_class) { mrb_value base = mrb_class_path(mrb, outer); path = mrb_str_plus(mrb, base, mrb_str_new(mrb, "::", 2)); name = mrb_sym2name_len(mrb, sym, &len); mrb_str_concat(mrb, path, mrb_str_new(mrb, name, len)); } else { name = mrb_sym2name_len(mrb, sym, &len); path = mrb_str_new(mrb, name, len); } mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern(mrb, "__classpath__"), path); } return path; }
static mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass) { mrb_value str; if (mrb_type(klass) == MRB_TT_SCLASS) { mrb_value v = mrb_iv_get(mrb, klass, mrb_intern2(mrb, "__attached__", 12)); str = mrb_str_new(mrb, "#<Class:", 8); switch (mrb_type(v)) { case MRB_TT_CLASS: case MRB_TT_MODULE: case MRB_TT_SCLASS: mrb_str_append(mrb, str, mrb_inspect(mrb, v)); break; default: mrb_str_append(mrb, str, mrb_any_to_s(mrb, v)); break; } mrb_str_cat(mrb, str, ">", 1); } else { struct RClass *c; mrb_value path; str = mrb_str_buf_new(mrb, 32); c = mrb_class_ptr(klass); path = mrb_class_path(mrb, c); if (mrb_nil_p(path)) { switch (mrb_type(klass)) { case MRB_TT_CLASS: mrb_str_cat(mrb, str, "#<Class:", 8); break; case MRB_TT_MODULE: mrb_str_cat(mrb, str, "#<Module:", 9); break; default: /* Shouldn't be happened? */ mrb_str_cat(mrb, str, "#<??????:", 9); break; } mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, c)); mrb_str_cat(mrb, str, ">", 1); } else { str = path; } } return str; }
const char* mrb_class_name(mrb_state *mrb, struct RClass* c) { mrb_value path = mrb_class_path(mrb, c); if (mrb_nil_p(path)) { path = mrb_str_new(mrb, "#<Class:", 8); mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c)); mrb_str_cat(mrb, path, ">", 1); } return mrb_str_ptr(path)->ptr; }
mrb_value mrb_class_path(mrb_state *mrb, struct RClass *c) { mrb_value path; path = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern(mrb, "__classpath__")); if (mrb_nil_p(path)) { struct RClass *outer = mrb_class_outer_module(mrb, c); mrb_sym sym = class_sym(mrb, c, outer); if (outer && outer != mrb->object_class) { mrb_value base = mrb_class_path(mrb, outer); path = mrb_str_plus(mrb, base, mrb_str_new_cstr(mrb, "::")); mrb_str_concat(mrb, path, mrb_str_new_cstr(mrb, mrb_sym2name(mrb, sym))); } else if (sym == 0) { return mrb_nil_value(); } else { path = mrb_str_new_cstr(mrb, mrb_sym2name(mrb, sym)); } mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern(mrb, "__classpath__"), path); } return path; }
static mrb_value mrb_mod_name(mrb_state *mrb, mrb_value self) { mrb_value name = mrb_class_path(mrb, mrb_class_ptr(self)); return mrb_nil_p(name)? name : mrb_str_dup(mrb, name); }
// based on https://gist.github.com/3066997 static mrb_value migrate_simple_value(mrb_state *mrb, mrb_value v, mrb_state *mrb2) { mrb_value nv; switch (mrb_type(v)) { case MRB_TT_OBJECT: case MRB_TT_EXCEPTION: { struct RObject *o = mrb_obj_ptr(v); mrb_value path = mrb_class_path(mrb, o->c); struct RClass *c; if (mrb_nil_p(path)) { mrb_raise(mrb, E_TYPE_ERROR, "cannot migrate class"); } c = mrb_class_get(mrb2, RSTRING_PTR(path)); nv = mrb_obj_value(mrb_obj_alloc(mrb2, mrb_type(v), c)); } migrate_simple_iv(mrb, v, mrb2, nv); break; case MRB_TT_FALSE: case MRB_TT_TRUE: case MRB_TT_FIXNUM: nv = v; break; case MRB_TT_SYMBOL: nv = mrb_symbol_value(migrate_sym(mrb, mrb_symbol(v), mrb2)); break; case MRB_TT_FLOAT: nv = mrb_float_value(mrb2, mrb_float(v)); break; case MRB_TT_STRING: nv = mrb_str_new(mrb2, RSTRING_PTR(v), RSTRING_LEN(v)); break; case MRB_TT_RANGE: { struct RRange *r = mrb_range_ptr(v); nv = mrb_range_new(mrb2, migrate_simple_value(mrb, r->edges->beg, mrb2), migrate_simple_value(mrb, r->edges->end, mrb2), r->excl); } break; case MRB_TT_ARRAY: { struct RArray *a0, *a1; int i; a0 = mrb_ary_ptr(v); nv = mrb_ary_new_capa(mrb2, a0->len); a1 = mrb_ary_ptr(nv); for (i=0; i<a0->len; i++) { int ai = mrb_gc_arena_save(mrb2); a1->ptr[i] = migrate_simple_value(mrb, a0->ptr[i], mrb2); a1->len++; mrb_gc_arena_restore(mrb2, ai); } } break; case MRB_TT_HASH: { mrb_value ka; int i, l; nv = mrb_hash_new(mrb2); ka = mrb_hash_keys(mrb, v); l = RARRAY_LEN(ka); for (i = 0; i < l; i++) { int ai = mrb_gc_arena_save(mrb2); mrb_value k = migrate_simple_value(mrb, mrb_ary_entry(ka, i), mrb2); mrb_value o = migrate_simple_value(mrb, mrb_hash_get(mrb, v, k), mrb2); mrb_hash_set(mrb2, nv, k, o); mrb_gc_arena_restore(mrb2, ai); } } migrate_simple_iv(mrb, v, mrb2, nv); break; case MRB_TT_DATA: if (!is_safe_migratable_datatype(DATA_TYPE(v))) mrb_raise(mrb, E_TYPE_ERROR, "cannot migrate object"); nv = v; DATA_PTR(nv) = DATA_PTR(v); DATA_TYPE(nv) = DATA_TYPE(v); migrate_simple_iv(mrb, v, mrb2, nv); break; default: mrb_raise(mrb, E_TYPE_ERROR, "cannot migrate object"); break; } return nv; }
static mrb_bool is_safe_migratable_simple_value(mrb_state *mrb, mrb_value v, mrb_state *mrb2) { switch (mrb_type(v)) { case MRB_TT_OBJECT: case MRB_TT_EXCEPTION: { struct RObject *o = mrb_obj_ptr(v); mrb_value path = mrb_class_path(mrb, o->c); if (mrb_nil_p(path) || !mrb_class_defined(mrb2, RSTRING_PTR(path))) { return FALSE; } } break; case MRB_TT_FALSE: case MRB_TT_TRUE: case MRB_TT_FIXNUM: case MRB_TT_SYMBOL: case MRB_TT_FLOAT: case MRB_TT_STRING: break; case MRB_TT_RANGE: { struct RRange *r = mrb_range_ptr(v); if (!is_safe_migratable_simple_value(mrb, r->edges->beg, mrb2) || !is_safe_migratable_simple_value(mrb, r->edges->end, mrb2)) { return FALSE; } } break; case MRB_TT_ARRAY: { struct RArray *a0; int i; a0 = mrb_ary_ptr(v); for (i=0; i<a0->len; i++) { if (!is_safe_migratable_simple_value(mrb, a0->ptr[i], mrb2)) { return FALSE; } } } break; case MRB_TT_HASH: { mrb_value ka; int i, l; ka = mrb_hash_keys(mrb, v); l = RARRAY_LEN(ka); for (i = 0; i < l; i++) { mrb_value k = mrb_ary_entry(ka, i); if (!is_safe_migratable_simple_value(mrb, k, mrb2) || !is_safe_migratable_simple_value(mrb, mrb_hash_get(mrb, v, k), mrb2)) { return FALSE; } } } break; case MRB_TT_DATA: if (!is_safe_migratable_datatype(DATA_TYPE(v))) return FALSE; break; default: return FALSE; break; } return TRUE; }