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; }