Project

General

Profile

Feature #15955 ยป umethod_apply.patch

mame (Yusuke Endoh), 08/23/2019 02:40 AM

View differences:

proc.c
2306 2306
 *
2307 2307
 */
2308 2308

  
2309
static void
2310
convert_umethod_to_method_components(VALUE method, VALUE recv, VALUE *methclass_out, VALUE *klass_out, const rb_method_entry_t **me_out)
2311
{
2312
    struct METHOD *data;
2313

  
2314
    TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
2315

  
2316
    VALUE methclass = data->me->owner;
2317
    VALUE klass = CLASS_OF(recv);
2318

  
2319
    if (!RB_TYPE_P(methclass, T_MODULE) &&
2320
	methclass != CLASS_OF(recv) && !rb_obj_is_kind_of(recv, methclass)) {
2321
	if (FL_TEST(methclass, FL_SINGLETON)) {
2322
	    rb_raise(rb_eTypeError,
2323
		     "singleton method called for a different object");
2324
	}
2325
	else {
2326
	    rb_raise(rb_eTypeError, "bind argument must be an instance of % "PRIsVALUE,
2327
		     methclass);
2328
	}
2329
    }
2330

  
2331
    const rb_method_entry_t *me = rb_method_entry_clone(data->me);
2332

  
2333
    if (RB_TYPE_P(me->owner, T_MODULE)) {
2334
	VALUE ic = rb_class_search_ancestor(klass, me->owner);
2335
	if (ic) {
2336
	    klass = ic;
2337
	}
2338
	else {
2339
	    klass = rb_include_class_new(methclass, klass);
2340
	}
2341
        me = (const rb_method_entry_t *) rb_method_entry_complement_defined_class(me, me->called_id, klass);
2342
    }
2343

  
2344
    *methclass_out = methclass;
2345
    *klass_out = klass;
2346
    *me_out = me;
2347
}
2348

  
2309 2349
/*
2310 2350
 *  call-seq:
2311 2351
 *     umeth.bind(obj) -> method
......
2344 2384
static VALUE
2345 2385
umethod_bind(VALUE method, VALUE recv)
2346 2386
{
2347
    struct METHOD *data, *bound;
2348 2387
    VALUE methclass, klass;
2388
    const rb_method_entry_t *me;
2389
    convert_umethod_to_method_components(method, recv, &methclass, &klass, &me);
2349 2390

  
2350
    TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
2351

  
2352
    methclass = data->me->owner;
2391
    struct METHOD *bound;
2392
    method = TypedData_Make_Struct(rb_cMethod, struct METHOD, &method_data_type, bound);
2393
    RB_OBJ_WRITE(method, &bound->recv, recv);
2394
    RB_OBJ_WRITE(method, &bound->klass, klass);
2395
    RB_OBJ_WRITE(method, &bound->me, me);
2353 2396

  
2354
    if (!RB_TYPE_P(methclass, T_MODULE) &&
2355
	methclass != CLASS_OF(recv) && !rb_obj_is_kind_of(recv, methclass)) {
2356
	if (FL_TEST(methclass, FL_SINGLETON)) {
2357
	    rb_raise(rb_eTypeError,
2358
		     "singleton method called for a different object");
2359
	}
2360
	else {
2361
	    rb_raise(rb_eTypeError, "bind argument must be an instance of % "PRIsVALUE,
2362
		     methclass);
2363
	}
2364
    }
2397
    return method;
2398
}
2365 2399

  
2366
    klass  = CLASS_OF(recv);
2400
/*
2401
 *  call-seq:
2402
 *     umeth.apply(obj, args, ...) -> obj
2403
 *
2404
 *  Bind <i>umeth</i> to <i>obj</i> and then invokes the method with the
2405
 *  specified arguments.
2406
 *  This is equivalent to <code>umeth.bind(obj).call(args, ...)</code>.
2407
 */
2408
static VALUE
2409
umethod_apply(int argc, VALUE *argv, VALUE method)
2410
{
2411
    rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
2412
    VALUE recv = argv[0];
2413
    argc--;
2414
    argv++;
2367 2415

  
2368
    method = TypedData_Make_Struct(rb_cMethod, struct METHOD, &method_data_type, bound);
2369
    RB_OBJ_WRITE(method, &bound->recv, recv);
2370
    RB_OBJ_WRITE(method, &bound->klass, data->klass);
2371
    RB_OBJ_WRITE(method, &bound->me, rb_method_entry_clone(data->me));
2416
    VALUE methclass, klass;
2417
    const rb_method_entry_t *me;
2418
    convert_umethod_to_method_components(method, recv, &methclass, &klass, &me);
2419
    struct METHOD bound = { recv, klass, 0, me };
2372 2420

  
2373
    if (RB_TYPE_P(bound->me->owner, T_MODULE)) {
2374
	VALUE ic = rb_class_search_ancestor(klass, bound->me->owner);
2375
	if (ic) {
2376
	    klass = ic;
2377
	}
2378
	else {
2379
	    klass = rb_include_class_new(methclass, klass);
2380
	}
2381
	RB_OBJ_WRITE(method, &bound->me, rb_method_entry_complement_defined_class(bound->me, bound->me->called_id, klass));
2382
    }
2421
    VALUE passed_procval = rb_block_given_p() ? rb_block_proc() : Qnil;
2383 2422

  
2384
    return method;
2423
    rb_execution_context_t *ec = GET_EC();
2424
    return call_method_data(ec, &bound, argc, argv, passed_procval);
2385 2425
}
2386 2426

  
2387 2427
/*
......
3671 3711
    rb_define_method(rb_cUnboundMethod, "original_name", method_original_name, 0);
3672 3712
    rb_define_method(rb_cUnboundMethod, "owner", method_owner, 0);
3673 3713
    rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1);
3714
    rb_define_method(rb_cUnboundMethod, "apply", umethod_apply, -1);
3674 3715
    rb_define_method(rb_cUnboundMethod, "source_location", rb_method_location, 0);
3675 3716
    rb_define_method(rb_cUnboundMethod, "parameters", rb_method_parameters, 0);
3676 3717
    rb_define_method(rb_cUnboundMethod, "super_method", method_super_method, 0);
test/ruby/test_method.rb
1136 1136
    assert_equal(m, o.:foo)
1137 1137
    assert_nil(o.method(:foo))
1138 1138
  end
1139

  
1140
  def test_umethod_apply
1141
    foo = Base.instance_method(:foo)
1142
    assert_equal(:base, foo.apply(Base.new))
1143
    assert_equal(:base, foo.apply(Derived.new))
1144

  
1145
    plus = Integer.instance_method(:+)
1146
    assert_equal(3, plus.apply(1, 2))
1147
  end
1139 1148
end