static VALUE find_class_path(VALUE klass) { struct fc_result arg; arg.name = 0; arg.path = 0; arg.klass = klass; arg.track = rb_cObject; arg.prev = 0; CFMutableDictionaryRef iv_dict = rb_class_ivar_dict(rb_cObject); if (iv_dict != NULL) { ivar_dict_foreach(iv_dict, fc_i, (VALUE)&arg); } if (arg.path == 0) { st_foreach_safe(rb_class_tbl, fc_i, (st_data_t)&arg); } if (arg.path) { iv_dict = rb_class_ivar_dict_or_create(klass); CFDictionarySetValue(iv_dict, (const void *)id_classpath, (const void *)arg.path); CFDictionaryRemoveValue(iv_dict, (const void *)id_tmp_classpath); return arg.path; } if (!RCLASS_RUBY(klass)) { VALUE name = rb_str_new2(class_getName((Class)klass)); iv_dict = rb_class_ivar_dict_or_create(klass); CFDictionarySetValue(iv_dict, (const void *)id_classpath, (const void *)name); CFDictionaryRemoveValue(iv_dict, (const void *)id_tmp_classpath); return name; } return Qnil; }
static VALUE classname(VALUE klass) { VALUE path = Qnil; if (klass == 0) { klass = rb_cObject; } CFMutableDictionaryRef iv_dict = rb_class_ivar_dict(klass); if (iv_dict != NULL) { if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)iv_dict, (const void *)id_classpath, (const void **)&path)) { if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)iv_dict, (const void *)id_classid, (const void **)&path)) { return find_class_path(klass); } path = rb_str_dup(path); OBJ_FREEZE(path); CFDictionarySetValue(iv_dict, (const void *)id_classpath, (const void *)path); CFDictionaryRemoveValue(iv_dict, (const void *)id_classid); } if (TYPE(path) != T_STRING) { rb_bug("class path is not set properly"); } return path; } return find_class_path(klass); }
VALUE rb_singleton_class_clone(VALUE obj) { VALUE klass = RBASIC(obj)->klass; if (!RCLASS_SINGLETON(klass)) { return klass; } // Create new singleton class. VALUE clone = rb_objc_create_class(NULL, RCLASS_SUPER(klass)); // Copy ivars. CFMutableDictionaryRef ivar_dict = rb_class_ivar_dict(klass); if (ivar_dict != NULL) { CFMutableDictionaryRef cloned_ivar_dict = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)ivar_dict); rb_class_ivar_set_dict(clone, cloned_ivar_dict); CFMakeCollectable(cloned_ivar_dict); } // Copy methods. rb_vm_copy_methods((Class)klass, (Class)clone); rb_singleton_class_attached(clone, obj); if (RCLASS_SUPER(clone) == rb_cRubyObject) { long v = RCLASS_VERSION(clone) ^ RCLASS_IS_OBJECT_SUBCLASS; RCLASS_SET_VERSION(clone, v); } RCLASS_SET_VERSION_FLAG(clone, RCLASS_IS_SINGLETON); return clone; }
VALUE rb_mod_init_copy(VALUE clone, SEL sel, VALUE orig) { rb_obj_init_copy(clone, 0, orig); VALUE super; if (!RCLASS_RUBY(orig)) { super = orig; rb_warn("cloning class `%s' is not supported, creating a " \ "subclass instead", rb_class2name(orig)); } else { super = RCLASS_SUPER(orig); } RCLASS_SET_SUPER(clone, super); // Copy flags. unsigned long version_flag = RCLASS_IS_RUBY_CLASS; if ((RCLASS_VERSION(super) & RCLASS_IS_OBJECT_SUBCLASS) == RCLASS_IS_OBJECT_SUBCLASS) { version_flag |= RCLASS_IS_OBJECT_SUBCLASS; } if (RCLASS_MODULE(orig)) { version_flag |= RCLASS_IS_MODULE; } RCLASS_SET_VERSION(clone, version_flag); if (!class_isMetaClass((Class)clone)) { // Clear type info. RCLASS_SET_VERSION(*(Class *)clone, RCLASS_VERSION(*(Class *)clone)); } // Copy methods. rb_vm_copy_methods((Class)orig, (Class)clone); if (!class_isMetaClass((Class)orig)) { rb_vm_copy_methods(*(Class *)orig, *(Class *)clone); } // Copy ivars. CFMutableDictionaryRef orig_dict = rb_class_ivar_dict(orig); CFMutableDictionaryRef clone_dict; if (orig_dict != NULL) { clone_dict = CFDictionaryCreateMutableCopy(NULL, 0, orig_dict); rb_class_ivar_set_dict(clone, clone_dict); CFMakeCollectable(clone_dict); } else { clone_dict = rb_class_ivar_dict_or_create(clone); } // Remove the classpath & classid (name) so that they are not // copied over the new module / class. CFDictionaryRemoveValue(clone_dict, (const void *)id_classpath); CFDictionaryRemoveValue(clone_dict, (const void *)id_classid); return clone; }
/* :nodoc: */ VALUE rb_mod_init_copy(VALUE clone, SEL sel, VALUE orig) { static ID classpath = 0; static ID classid = 0; rb_obj_init_copy(clone, 0, orig); { VALUE super; unsigned long version_flag; if (!RCLASS_RUBY(orig)) { super = orig; rb_warn("cloning class `%s' is not supported, creating a " \ "subclass instead", rb_class2name(orig)); } else { super = RCLASS_SUPER(orig); } RCLASS_SET_SUPER(clone, super); version_flag = RCLASS_IS_RUBY_CLASS; if ((RCLASS_VERSION(super) & RCLASS_IS_OBJECT_SUBCLASS) == RCLASS_IS_OBJECT_SUBCLASS) { version_flag |= RCLASS_IS_OBJECT_SUBCLASS; } RCLASS_SET_VERSION(clone, version_flag); rb_vm_copy_methods((Class)orig, (Class)clone); CFMutableDictionaryRef ivar_dict = rb_class_ivar_dict(orig); if (ivar_dict != NULL) { CFMutableDictionaryRef cloned_ivar_dict; if (classpath == 0) { classpath = rb_intern("__classpath__"); } if (classid == 0) { classid = rb_intern("__classid__"); } cloned_ivar_dict = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)ivar_dict); // Remove the classpath & classid (name) so that they are not // copied over the new module / class CFDictionaryRemoveValue(cloned_ivar_dict, (const void *)classpath); CFDictionaryRemoveValue(cloned_ivar_dict, (const void *)classid); CFMakeCollectable(cloned_ivar_dict); rb_class_ivar_set_dict(clone, cloned_ivar_dict); } } return clone; }
static int fc_i(ID key, VALUE value, struct fc_result *res) { if (!rb_is_const_id(key)) return ST_CONTINUE; if (value == res->klass) { res->path = fc_path(res, key); return ST_STOP; } switch (TYPE(value)) { case T_MODULE: case T_CLASS: { CFDictionaryRef iv_dict = rb_class_ivar_dict(value); if (iv_dict == NULL) return ST_CONTINUE; else { struct fc_result arg; struct fc_result *list; list = res; while (list) { if (list->track == value) return ST_CONTINUE; list = list->prev; } arg.name = key; arg.path = 0; arg.klass = res->klass; arg.track = value; arg.prev = res; ivar_dict_foreach(iv_dict, fc_i, (VALUE)&arg); if (arg.path) { res->path = arg.path; return ST_STOP; } } break; } default: break; } return ST_CONTINUE; }
void rb_include_module2(VALUE klass, VALUE orig_klass, VALUE module, bool check, bool add_methods) { if (check) { rb_frozen_class_p(klass); if (!OBJ_TAINTED(klass)) { rb_secure(4); } Check_Type(module, T_MODULE); } // Register the module as included in the class. VALUE ary = rb_attr_get(klass, idIncludedModules); if (ary == Qnil) { ary = rb_ary_new(); rb_ivar_set(klass, idIncludedModules, ary); } else { if (rb_ary_includes(ary, module)) { return; } } rb_ary_insert(ary, 0, module); // Mark the module as included somewhere. const long v = RCLASS_VERSION(module) | RCLASS_IS_INCLUDED; RCLASS_SET_VERSION(module, v); // Register the class as included in the module. ary = rb_attr_get(module, idIncludedInClasses); if (ary == Qnil) { ary = rb_ary_new(); rb_ivar_set(module, idIncludedInClasses, ary); } rb_ary_push(ary, klass); // Delete the ancestors array if it exists, since we just changed it. CFMutableDictionaryRef iv_dict = rb_class_ivar_dict(klass); if (iv_dict != NULL) { CFDictionaryRemoveValue(iv_dict, (const void *)idAncestors); } if (add_methods) { // Copy methods. If original class has the basic -initialize and if the // module has a customized -initialize, we must copy the customized // version to the original class too. rb_vm_copy_methods((Class)module, (Class)klass); // When including into the class Class, also copy the methods to the // singleton class of NSObject. if (klass == rb_cClass || klass == rb_cModule) { rb_vm_copy_methods((Class)module, *(Class *)rb_cNSObject); } if (orig_klass != 0 && orig_klass != klass) { Method m = class_getInstanceMethod((Class)orig_klass, selInitialize); Method m2 = class_getInstanceMethod((Class)klass, selInitialize); if (m != NULL && m2 != NULL && method_getImplementation(m) == (IMP)rb_objc_init && method_getImplementation(m2) != (IMP)rb_objc_init) { rb_vm_copy_method((Class)orig_klass, m2); } } } }