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.
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…?
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.
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…?
“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.
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