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