Beispiel #1
0
void
rb_undef(VALUE klass, ID id)
{
    // TODO
#if 0
    VALUE origin;
    NODE *body;

#if 0 // TODO
    if (rb_vm_cbase() == rb_cObject && klass == rb_cObject) {
	rb_secure(4);
    }
#endif
    if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
	rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'",
		 rb_id2name(id));
    }
    rb_frozen_class_p(klass);
    if (id == object_id || id == __send__ || id == idInitialize) {
	rb_warn("undefining `%s' may cause serious problem", rb_id2name(id));
    }
    /* TODO: warn if a very important method of NSObject is undefined 
     * by default, pure objc methods are not exposed by introspections API 
     */
    body = search_method(klass, id, &origin);
    if (!body || !body->nd_body) {
	const char *s0 = " class";
	VALUE c = klass;

	if (RCLASS_SINGLETON(c)) {
	    VALUE obj = rb_iv_get(klass, "__attached__");

	    switch (TYPE(obj)) {
	      case T_MODULE:
	      case T_CLASS:
		c = obj;
		s0 = "";
	    }
	}
	else if (TYPE(c) == T_MODULE) {
	    s0 = " module";
	}
	rb_name_error(id, "undefined method `%s' for%s `%s'",
		      rb_id2name(id), s0, rb_class2name(c));
    }

    rb_add_method(klass, id, 0, NOEX_PUBLIC);

    if (RCLASS_SINGLETON(klass)) {
	rb_funcall(rb_iv_get(klass, "__attached__"),
		   singleton_undefined, 1, ID2SYM(id));
    }
    else {
	rb_funcall(klass, undefined, 1, ID2SYM(id));
    }
#endif
}
Beispiel #2
0
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;
}
Beispiel #3
0
VALUE 
rb_obj_singleton_methods(VALUE obj, SEL sel, int argc, VALUE *argv)
{
    VALUE recur, objc_methods, klass, ary;

    if (argc == 0) {
	recur = Qtrue;
	objc_methods = Qfalse;
    }
    else {
	rb_scan_args(argc, argv, "02", &recur, &objc_methods);
    }

    klass = CLASS_OF(obj);
    ary = rb_ary_new();

    do {
	if (RCLASS_SINGLETON(klass)) {
	    rb_vm_push_methods(ary, klass, RTEST(objc_methods), ins_methods_i);
	}
	klass = RCLASS_SUPER(klass);
    }
    while (recur == Qtrue && klass != 0);

    return ary;
}
Beispiel #4
0
static VALUE
rb_mod_append_features(VALUE module, SEL sel, VALUE include)
{
    VALUE orig = include;
    switch (TYPE(include)) {
	case T_CLASS:
	case T_MODULE:
	    break;
	default:
	    Check_Type(include, T_CLASS);
	    break;
    }
    if (RCLASS_RUBY(include)) {
	VALUE sinclude = rb_make_singleton_class(RCLASS_SUPER(include));
	RCLASS_SET_SUPER(include, sinclude);
	include = sinclude;
    }	
    rb_include_module2(include, orig, module, true, true);

    VALUE m = module;
    do {
	VALUE ary = rb_attr_get(m, idIncludedModules);
	if (ary != Qnil) {
	    for (int i = 0, count = RARRAY_LEN(ary); i < count; i++) {
		VALUE mod = RARRAY_AT(ary, i);
		rb_mod_append_features(mod, sel, include);
	    }
	}
	m = RCLASS_SUPER(m);
    }
    while (m == 0 || RCLASS_SINGLETON(m));

    return module;
}
Beispiel #5
0
void
rb_extend_object(VALUE obj, VALUE module)
{
    VALUE klass;
    if (TYPE(obj) == T_CLASS && RCLASS_RUBY(obj)) {
	VALUE sklass = rb_make_singleton_class(RCLASS_SUPER(obj));
	RCLASS_SET_SUPER(obj, sklass);
	klass = *(VALUE *)sklass;
    }
    else {
	klass = rb_singleton_class(obj);
    }

    rb_include_module(klass, module);

    VALUE m = module;
    do {
	VALUE ary = rb_attr_get(m, idIncludedModules);
	if (ary != Qnil) {
	    for (int i = 0, count = RARRAY_LEN(ary); i < count; i++) {
		VALUE mod = RARRAY_AT(ary, i);
		rb_extend_object(obj, mod);
	    }
	}
	m = RCLASS_SUPER(m);
    }
    while (m == 0 || RCLASS_SINGLETON(m));
}
Beispiel #6
0
static void
robj_sclass_finalize_imp(void *rcv, SEL sel)
{
    bool changed = false;
    while (true) {
	VALUE k = *(VALUE *)rcv;
	if (!RCLASS_SINGLETON(k)
		|| !rb_singleton_class_attached_object(k) == (VALUE)rcv) {
	    break;
	}
	VALUE sk = RCLASS_SUPER(k);
	if (sk == 0) {
	    // This can't happen, but we are never sure...
	    break;
	}
	*(VALUE *)rcv = sk;

	rb_vm_dispose_class((Class)k);

	changed = true;
    }

#if 0
    if (changed) {
	objc_msgSend(rcv, selFinalize);
    }
#endif
}
Beispiel #7
0
void
rb_singleton_class_attached(VALUE klass, VALUE obj)
{
    if (RCLASS_SINGLETON(klass)) {
	// Weak ref.
	VALUE wobj = LONG2NUM((long)obj);
	rb_ivar_set(klass, idAttached, wobj);
	// FIXME commented for now as it breaks some RubySpecs.
	//rb_singleton_class_promote_for_gc(klass);
    }
}
Beispiel #8
0
void
rb_check_inheritable(VALUE super)
{
    if (TYPE(super) != T_CLASS) {
	rb_raise(rb_eTypeError, "superclass must be a Class (%s given)",
		 rb_obj_classname(super));
    }
    if (RCLASS_SINGLETON(super)) {
	rb_raise(rb_eTypeError, "can't make subclass of singleton class");
    }
}
Beispiel #9
0
VALUE
rb_singleton_class_attached_object(VALUE klass)
{
    if (RCLASS_SINGLETON(klass)) {
	// Weak ref.
	VALUE obj = rb_ivar_get(klass, idAttached);
	if (FIXNUM_P(obj)) {
	    return (VALUE)NUM2LONG(obj);
	}
    }
    return Qnil;
}
Beispiel #10
0
VALUE
rb_make_metaclass(VALUE obj, VALUE super)
{
    VALUE klass;
    if (TYPE(obj) == T_CLASS && RCLASS_SINGLETON(obj)) {
	RBASIC(obj)->klass = rb_cClass;
	klass = rb_cClass;
    }
    else {
	VALUE objk = RBASIC(obj)->klass;
	if (RCLASS_SINGLETON(objk)
		&& rb_singleton_class_attached_object(objk) == obj) {
	    klass = objk;
	}
	else {
	    klass = rb_make_singleton_class(super);
	    RBASIC(obj)->klass = klass;
	    rb_singleton_class_attached(klass, obj);
	}
    }
    return klass;
}
Beispiel #11
0
VALUE
rhash_dup(VALUE rcv, SEL sel)
{
    VALUE klass = CLASS_OF(rcv);
    while (RCLASS_SINGLETON(klass)) {
	klass = RCLASS_SUPER(klass);
    }
    assert(rb_klass_is_rhash(klass));

    VALUE dup = rhash_alloc(klass, 0);
    rb_obj_invoke_initialize_copy(dup, rcv);

    OBJ_INFECT(dup, rcv);
    return dup;
}
Beispiel #12
0
/* :nodoc: */
VALUE
rb_class_init_copy(VALUE clone, SEL sel, VALUE orig)
{
    if (orig == rb_cBasicObject || orig == rb_cObject) {
	rb_raise(rb_eTypeError, "can't copy the root class");
    }
    if (/* RCLASS_SUPER(clone) ||  FIXME: comment out because Singleton.clone raises a rb_eTypeError */
	(clone == rb_cBasicObject || clone == rb_cObject)) {
	rb_raise(rb_eTypeError, "already initialized class");
    }
    if (RCLASS_SINGLETON(orig)) {
	rb_raise(rb_eTypeError, "can't copy singleton class");
    }
    clone =  rb_mod_init_copy(clone, 0, orig);
    rb_objc_class_sync_version((Class)clone, (Class)orig);
    return clone;
}
Beispiel #13
0
static VALUE
method_inspect(VALUE method)
{
    struct METHOD *data;
    VALUE str;
    const char *s;
    const char *sharp = "#";

    Data_Get_Struct(method, struct METHOD, data);
    str = rb_str_buf_new2("#<");
    s = rb_obj_classname(method);
    rb_str_buf_cat2(str, s);
    rb_str_buf_cat2(str, ": ");

    if (RCLASS_SINGLETON(data->oclass)) {
	VALUE v = rb_iv_get(data->oclass, "__attached__");

	if (data->recv == Qundef) {
	    rb_str_buf_append(str, rb_inspect(data->oclass));
	}
	else if (data->recv == v) {
	    rb_str_buf_append(str, rb_inspect(v));
	    sharp = ".";
	}
	else {
	    rb_str_buf_append(str, rb_inspect(data->recv));
	    rb_str_buf_cat2(str, "(");
	    rb_str_buf_append(str, rb_inspect(v));
	    rb_str_buf_cat2(str, ")");
	    sharp = ".";
	}
    }
    else {
	rb_str_buf_cat2(str, rb_class2name(data->rclass));
	if (data->rclass != data->oclass) {
	    rb_str_buf_cat2(str, "(");
	    rb_str_buf_cat2(str, rb_class2name(data->oclass));
	    rb_str_buf_cat2(str, ")");
	}
    }
    rb_str_buf_cat2(str, sharp);
    rb_str_append(str, rb_id2str(data->oid));
    rb_str_buf_cat2(str, ">");

    return str;
}
Beispiel #14
0
static void
remove_method(VALUE klass, ID mid)
{
    if (klass == rb_cObject) {
	rb_secure(4);
    }
    if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
	rb_raise(rb_eSecurityError, "Insecure: can't remove method");
    }
    if (OBJ_FROZEN(klass))
	rb_error_frozen("class/module");
    if (mid == object_id || mid == __send__ || mid == idInitialize) {
	rb_warn("removing `%s' may cause serious problem", rb_id2name(mid));
    }
    SEL sel;
    Method m;

    sel = sel_registerName(rb_id2name(mid));
    m = class_getInstanceMethod((Class)klass, sel);
    if (m == NULL) {
	char buf[100];
	size_t len = strlen((char *)sel);
	if (((char *)sel)[len - 1] != ':') {
	    snprintf(buf, sizeof buf, "%s:", (char *)sel);
	    sel = sel_registerName(buf);
	    m = class_getInstanceMethod((Class)klass, sel);
	}
    }
    if (m == NULL) {
	rb_name_error(mid, "method `%s' not defined in %s",
		      rb_id2name(mid), rb_class2name(klass));
    }
    if (rb_vm_get_method_node(method_getImplementation(m)) == NULL) {
	rb_warn("removing pure Objective-C method `%s' may cause serious " \
		"problem", rb_id2name(mid));
    }
    method_setImplementation(m, NULL);

    if (RCLASS_SINGLETON(klass)) {
	rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1,
		   ID2SYM(mid));
    }
    else {
	rb_funcall(klass, removed, 1, ID2SYM(mid));
    }
}
Beispiel #15
0
static VALUE
mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
{
    VALUE method;
    NODE *body;
    struct METHOD *data;
    VALUE rclass = klass;
    ID oid = id;

  again:
    if ((body = rb_get_method_body(klass, id, 0)) == 0) {
	rb_print_undef(rclass, oid, 0);
    }
    if (scope && (body->nd_noex & NOEX_MASK) != NOEX_PUBLIC) {
	rb_print_undef(rclass, oid, (body->nd_noex & NOEX_MASK));
    }

    klass = body->nd_clss;
    body = body->nd_body;

    if (nd_type(body) == NODE_ZSUPER) {
	klass = RCLASS_SUPER(klass);
	goto again;
    }

    while (rclass != klass &&
	   (RCLASS_SINGLETON(rclass) || TYPE(rclass) == T_ICLASS)) {
	rclass = RCLASS_SUPER(rclass);
    }
    if (TYPE(klass) == T_ICLASS)
	klass = RBASIC(klass)->klass;
    method = Data_Make_Struct(mclass, struct METHOD, bm_mark, -1, data);
    data->oclass = klass;
    GC_WB(&data->recv, obj);

    data->id = id;
    data->body = body;
    data->rclass = rclass;
    data->oid = oid;
#if !WITH_OBJC
    OBJ_INFECT(method, klass);
#endif

    return method;
}
Beispiel #16
0
bool
rb_objc_hash_is_pure(VALUE hash)
{
    VALUE k = *(VALUE *)hash;
    while (RCLASS_SINGLETON(k)) {
        k = RCLASS_SUPER(k);
    }
    if (k == rb_cRubyHash) {
	return true;
    }
    while (k != 0) {
	if (k == rb_cRubyHash) {
	    return false;
	}
	k = RCLASS_SUPER(k);
    }
    return true;
}
Beispiel #17
0
VALUE
rb_mod_included_modules(VALUE mod)
{
    VALUE ary = rb_ary_new();
    bool mod_detected = false;

    for (VALUE p = mod; p != 0; p = RCLASS_SUPER(p)) {
	if (!mod_detected) {
	    if (RCLASS_MODULE(p)) {
		mod_detected = true;
	    }
	}
	else {
	    if (!RCLASS_SINGLETON(p)) {
		break;
	    }
	}
	rb_mod_included_modules_nosuper(p, ary);
    }
    return ary;
}
Beispiel #18
0
void
rb_frozen_class_p(VALUE klass)
{
    const char *desc = "something(?!)";

    if (OBJ_FROZEN(klass)) {
	if (RCLASS_SINGLETON(klass))
	    desc = "object";
	else {
	    switch (TYPE(klass)) {
	      case T_MODULE:
	      case T_ICLASS:
		desc = "module";
		break;
	      case T_CLASS:
		desc = "class";
		break;
	    }
	}
	rb_error_frozen(desc);
    }
}
Beispiel #19
0
static VALUE
umethod_bind(VALUE method, VALUE recv)
{
    struct METHOD *data, *bound;

    Data_Get_Struct(method, struct METHOD, data);
    if (data->rclass != CLASS_OF(recv)) {
	if (RCLASS_SINGLETON(data->rclass)) {
	    rb_raise(rb_eTypeError,
		     "singleton method called for a different object");
	}
	if (!rb_obj_is_kind_of(recv, data->rclass)) {
	    rb_raise(rb_eTypeError, "bind argument must be an instance of %s",
		     rb_class2name(data->rclass));
	}
    }

    method = Data_Make_Struct(rb_cMethod, struct METHOD, bm_mark, xfree, bound);
    *bound = *data;
    GC_WB(&bound->recv, recv);
    bound->rclass = CLASS_OF(recv);

    return method;
}
Beispiel #20
0
static VALUE
rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
{
    ID id;
    VALUE body;
    NODE *node;
    int noex = NOEX_PUBLIC;

    if (argc == 1) {
	id = rb_to_id(argv[0]);
	body = rb_block_lambda();
    }
    else if (argc == 2) {
	id = rb_to_id(argv[0]);
	body = argv[1];
	if (!rb_obj_is_method(body) && !rb_obj_is_proc(body)) {
	    rb_raise(rb_eTypeError,
		     "wrong argument type %s (expected Proc/Method)",
		     rb_obj_classname(body));
	}
    }
    else {
	rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
    }

    if (RDATA(body)->dmark == (RUBY_DATA_FUNC) bm_mark) {
	struct METHOD *method = (struct METHOD *)DATA_PTR(body);
	VALUE rclass = method->rclass;
	if (rclass != mod) {
	    if (RCLASS_SINGLETON(rclass)) {
		rb_raise(rb_eTypeError,
			 "can't bind singleton method to a different class");
	    }
	    if (!RTEST(rb_class_inherited_p(mod, rclass))) {
		rb_raise(rb_eTypeError,
			 "bind argument must be a subclass of %s",
			 rb_class2name(rclass));
	    }
	}
	node = method->body;
    }
    else if (rb_obj_is_proc(body)) {
	rb_proc_t *proc;
	body = proc_dup(body);
	GetProcPtr(body, proc);
	if (BUILTIN_TYPE(proc->block.iseq) != T_NODE) {
	    proc->block.iseq->defined_method_id = id;
	    proc->block.iseq->klass = mod;
	    proc->is_lambda = Qtrue;
	    proc->is_from_method = Qtrue;
	}
	node = NEW_BMETHOD(body);
    }
    else {
	/* type error */
	rb_raise(rb_eTypeError, "wrong argument type (expected Proc/Method)");
    }

    /* TODO: visibility */

    rb_add_method(mod, id, node, noex);
    return body;
}
Beispiel #21
0
static bool
rb_class_hidden(VALUE klass)
{
    return klass == rb_cModuleObject || klass == rb_cRubyObject || RCLASS_SINGLETON(klass);
}