Accessing the call stack

I’ve been wishing there were an easy to way to access Ruby’s call
stack. I mean, you can use “caller”, but that just gives you an array
of strings. Sometimes it would be nice to know the file, line, method
and object that invoked a particular method, without having to parse the
caller strings. The object and/or class cannot even be obtained that
way.

Is there an easy way? I wound up adding a trace function that
"listened" for call and return events, and then added them to a custom
stack. This worked very well, but is not very robust since if anyone
sets a new trace function, the “call stack” is no longer accurate.

Here’s my solution:

···

#-------------------------------------------------
def invoker
Thread.current[:callstack] ||= []
( Thread.current[:callstack][-3] || Object )
end

set_trace_func proc { |event,file,line,obj,bind,klass|
if event == "call"
Thread.current[:callstack] ||= []
Thread.current[:callstack].push klass
elsif event == "return"
Thread.current[:callstack].pop
end
}
#-------------------------------------------------

All it tells you is the class of object that invoked the method, but it
could easily be extended. What I really want to know is: have I
reinvented the wheel? If not, perhaps something like this would be a
candidate for Rite…?

  • Jamis

This reminds me of something I heard proposed for Java 1.5, I think.
I’ve found myself wishing I could not only access stack information in an
OO way, but that I could access stack information of any Thread, rather
than just myself. It would be nice to be able to print stack-dumps of a
multithreaded application.

···

On Sat, 6 Dec 2003, Jamis Buck wrote:

I’ve been wishing there were an easy to way to access Ruby’s call
stack. I mean, you can use “caller”, but that just gives you an array
of strings. Sometimes it would be nice to know the file, line, method
and object that invoked a particular method, without having to parse the
caller strings. The object and/or class cannot even be obtained that
way.

Is there an easy way? I wound up adding a trace function that
“listened” for call and return events, and then added them to a custom
stack. This worked very well, but is not very robust since if anyone
sets a new trace function, the “call stack” is no longer accurate.

Here’s my solution:

#-------------------------------------------------
def invoker
Thread.current[:callstack] ||=
( Thread.current[:callstack][-3] || Object )
end

set_trace_func proc { |event,file,line,obj,bind,klass|
if event == “call”
Thread.current[:callstack] ||=
Thread.current[:callstack].push klass
elsif event == “return”
Thread.current[:callstack].pop
end
}
#-------------------------------------------------

All it tells you is the class of object that invoked the method, but it
could easily be extended. What I really want to know is: have I
reinvented the wheel? If not, perhaps something like this would be a
candidate for Rite…?

  • Jamis

Derek Lewis

===================================================================
Java Web-Application Developer

  Email    : email@lewisd.com
  Cellular : 604.312.2846
  Website  : http://www.lewisd.com

“If you’ve got a 5000-line JSP page that has “all in one” support
for three input forms and four follow-up screens, all controlled
by “if” statements in scriptlets, well … please don’t show it
to me :-). Its almost dinner time, and I don’t want to lose my
appetite :-).”
- Craig R. McClanahan

“Jamis Buck” jgb3@email.byu.edu schrieb im Newsbeitrag
news:1070640684.3565.10.camel@localhost…

I’ve been wishing there were an easy to way to access Ruby’s call
stack. I mean, you can use “caller”, but that just gives you an array
of strings. Sometimes it would be nice to know the file, line, method
and object that invoked a particular method, without having to parse the
caller strings. The object and/or class cannot even be obtained that
way.

Is there an easy way? I wound up adding a trace function that
“listened” for call and return events, and then added them to a custom
stack. This worked very well, but is not very robust since if anyone
sets a new trace function, the “call stack” is no longer accurate.

Here’s my solution:

#-------------------------------------------------
def invoker
Thread.current[:callstack] ||=
( Thread.current[:callstack][-3] || Object )
end

set_trace_func proc { |event,file,line,obj,bind,klass|
if event == “call”
Thread.current[:callstack] ||=
Thread.current[:callstack].push klass
elsif event == “return”
Thread.current[:callstack].pop
end
}
#-------------------------------------------------

All it tells you is the class of object that invoked the method, but it
could easily be extended. What I really want to know is: have I
reinvented the wheel? If not, perhaps something like this would be a
candidate for Rite…?

I don’t think you have reinvented the wheel. I’d do just some little
changes:

module Kernel
def invoker(levels = -1)
st = Thread.current[:callstack]
st && st[levels - 2]
end
end

set_trace_func proc {|*args|
case args[0]
when /call$/
( Thread.current[:callstack] ||= ).push args
when /return$/
Thread.current[:callstack].pop
end
}

def rec(count)
p invoker
puts count
rec count - 1 if count > 0
end

rec 10

Regards

robert