From: Avi Bryant Date: 2001-03-06T17:15:43+09:00 Subject: [ruby-talk:12105] Re: RCR: replacing 'caller' Robert, Nice... this is, of course, exactly what we needed to be able to play with dispatchers in pure ruby. However, it needs some error checking: class Foo define_method(:x) {puts call_stack[0]} end Foo.new.x #=> SEGFAULT I can work around it for new by using call_stack(2)... On Tue, 6 Mar 2001, Robert Feldt wrote: > Hi, > > IMHO, 'caller' would be much more useful if you could know/access the > method and object that called you. Therefore I submit this RCR: > > Replace 'caller' with 'call_stack' returning an array of arrays each with > the format: > > [object_called, method_called_id, args, file_with_call, line_for_call] > > 'call_stack' takes a level parameter (almost) in the same way as 'caller'. > > Example: > def m(a,b) > puts call_stack.inspect > end > def m2(a,b) > m(a,b) > end > > m2(1,true) > > would print > [[main, :m, [1, true], "../call_stack/t2.rb", 5], [main, :m2, [1, true], > "../call_stack/t2.rb", 8]] > > It might also be useful to add any blocks associated with calls (I'm > skeptical if this adds enough value for the added complexity). > > Maybe there's a risk in including the args. I'm not sure... Probably > there's a risk in any of this since Matz hasn't previously included it? > > Below is the diff to eval.c in latest snapshot implementing > call_stack. > > Regards, > > Robert > > > > --- eval.c.orig Tue Mar 6 06:00:04 2001 > +++ eval.c Tue Mar 6 07:52:24 2001 > @@ -4687,6 +4687,54 @@ > } > > static VALUE > +call_stack(lev) > + int lev; > +{ > + struct FRAME *frame = ruby_frame; > + VALUE ary = rb_ary_new(); > + VALUE inner_ary; > + > + while (lev-- > 0) { > + frame = frame->prev; > + if (!frame) { > + ary = Qnil; > + break; > + } > + } > + while (frame && frame->file) { > + inner_ary = rb_ary_new(); > + rb_ary_push(inner_ary, frame->self); > + rb_ary_push(inner_ary, ID2SYM(frame->last_func)); > + rb_ary_push(inner_ary, rb_ary_new4(frame->argc, frame->argv)); > + rb_ary_push(inner_ary, rb_str_new2(frame->file)); > + rb_ary_push(inner_ary, INT2FIX(frame->line)); > + // Add block if block_given? ie. check iter stack and traverse > block > + // stack accordingly... > + rb_ary_push(ary, inner_ary); > + frame = frame->prev; > + } > + > + return ary; > +} > + > +static VALUE > +rb_f_call_stack(argc, argv) > + int argc; > + VALUE *argv; > +{ > + VALUE level; > + int lev; > + > + rb_scan_args(argc, argv, "01", &level); > + > + if (NIL_P(level)) lev = 1; > + else lev = NUM2INT(level); > + if (lev < 0) rb_raise(rb_eArgError, "negative level(%d)", lev); > + > + return call_stack(lev); > +} > + > +static VALUE > rb_f_caller(argc, argv) > int argc; > VALUE *argv; > @@ -5869,6 +5917,7 @@ > rb_define_global_function("fail", rb_f_raise, -1); > > rb_define_global_function("caller", rb_f_caller, -1); > + rb_define_global_function("call_stack", rb_f_call_stack, -1); > > rb_define_global_function("exit", rb_f_exit, -1); > rb_define_global_function("abort", rb_f_abort, 0); > >