ext/sender/rb_Global.c in sender-1.4.2 vs ext/sender/rb_Global.c in sender-1.4.3

- old
+ new

@@ -41,20 +41,42 @@ // 2: the frame we want, unless it is :new (call to context: __sender__) // 3: the frame we want in the case #2 is :new VALUE rb_backtrace_limit = INT2FIX( 3 ); VALUE rb_backtrace_array = rb_RPRuby_Sender_Kernel_backtrace( 1, - & rb_backtrace_limit, - rb_mKernel ); - - VALUE rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, 1 ); + & rb_backtrace_limit, + rb_mKernel ); + + int c_backtrace_index = 1; + + VALUE rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, c_backtrace_index ); VALUE rb_caller = rb_hash_aref( rb_backtrace_frame_hash, ID2SYM( rb_intern( "method" ) ) ); + // if we get :initialize as our caller and our __method__ is :initialize, we need to go up the chain + // until our caller is no longer :initialize or :new + while ( rb_caller == ID2SYM( rb_intern( "initialize" ) ) ) { + c_backtrace_index++; + rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, c_backtrace_index ); + rb_caller = rb_hash_aref( rb_backtrace_frame_hash, + ID2SYM( rb_intern( "method" ) ) ); + + // we have one parent past our current method; if that is also :initialize, get the whole backtrace + if ( c_backtrace_index == 2 ) { + rb_backtrace_array = rb_RPRuby_Sender_Kernel_backtrace( 0, NULL, rb_mKernel ); + } + } + + // if we get "new" as our caller we need to get the next level, as we are in :initialize + // and want to know what called :new + // + // since we might have had to go up the chain from :initialize through parents before getting here we + // want to use a separate if statement if ( rb_caller == ID2SYM( rb_intern( "new" ) ) ) { - rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, 2 ); + c_backtrace_index++; + rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, c_backtrace_index ); } VALUE rb_sender = rb_hash_aref( rb_backtrace_frame_hash, ID2SYM( rb_intern( "object" ) ) ); @@ -80,20 +102,46 @@ // 2: the frame we want, unless it is :new (call to context: __sender__) // 3: the frame we want in the case #2 is :new VALUE rb_backtrace_limit = INT2FIX( 3 ); VALUE rb_backtrace_array = rb_RPRuby_Sender_Kernel_backtrace( 1, - & rb_backtrace_limit, - rb_mKernel ); + & rb_backtrace_limit, + rb_mKernel ); - VALUE rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, 1 ); + int c_backtrace_index = 1; + VALUE rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, c_backtrace_index ); + VALUE rb_caller = rb_hash_aref( rb_backtrace_frame_hash, - ID2SYM( rb_intern( "method" ) ) ); + ID2SYM( rb_intern( "method" ) ) ); - if ( rb_caller == ID2SYM( rb_intern( "new" ) ) ) { - rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, 2 ); + // we want to compare our caller as we go up the chain to our first caller to deal with super methods + // we have a symbol so no cloning is necessary (or appropriate) + VALUE rb_first_caller = rb_hash_aref( rb_ary_entry( rb_backtrace_array, 0 ), + ID2SYM( rb_intern( "method" ) ) ); + + // if we get :initialize as our caller and our __method__ is :initialize, we need to go up the chain + // until our caller is no longer :initialize or :new + while ( rb_caller == rb_first_caller ) { + c_backtrace_index++; + rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, c_backtrace_index ); + rb_caller = rb_hash_aref( rb_backtrace_frame_hash, + ID2SYM( rb_intern( "method" ) ) ); + // we have one parent past our current method; if that is also :initialize, get the whole backtrace + if ( c_backtrace_index == 2 ) { + rb_backtrace_array = rb_RPRuby_Sender_Kernel_backtrace( 0, NULL, rb_mKernel ); + } + } + + // if we get "new" as our caller we need to get the next level, as we are in :initialize + // and want to know what called :new + // + // since we might have had to go up the chain from :initialize through parents before getting here we + // want to use a separate if statement + if ( rb_caller == ID2SYM( rb_intern( "new" ) ) ) { + c_backtrace_index++; + rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, c_backtrace_index ); rb_caller = rb_hash_aref( rb_backtrace_frame_hash, ID2SYM( rb_intern( "method" ) ) ); } // assuming we have a previous frame, return its rb_self (our current receiver's sender)