From: "ko1 (Koichi Sasada)" Date: 2012-10-27T04:52:30+09:00 Subject: [ruby-core:48326] [ruby-trunk - Feature #1906][Closed] Kernel#backtrace: Objectifying Kernel#caller Issue #1906 has been updated by ko1 (Koichi Sasada). Status changed from Assigned to Closed I close this issue because #3917 was accepted. Please re-open I'm misunderstanding. ---------------------------------------- Feature #1906: Kernel#backtrace: Objectifying Kernel#caller https://bugs.ruby-lang.org/issues/1906#change-31630 Author: runpaint (Run Paint Run Run) Status: Closed Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: 2.0.0 =begin Inspired by nobu's recent refactoring of Kernel#rand`, several conversations with Ruby implementors about Kernel#caller, and Rubinius' Backtrace class, I've put together a _rough_ demo of how we could "objectify" Kernel#caller. It's at http://tinyurl.com/m9fdrn [github.com], along with some initial specs. Rationale ========= `caller` has two principle uses: * Allowing users to display the backtrace at a given point, e.g. `puts caller`. * Introspection to determine the callpath that lead the current method. The first use is reasonably achievable with `caller`, as long as you don't want to do any formatting of the output. The second is hard because it requires parsing lines of the `caller` Array with regular expressions, and knowing what the various permutations of output imply. It would be easier if we could inspect the call stack with a Ruby-ish API. Further, this would allow alternative implementations to provide this functionality without having to reverse-engineer the output of `caller`. As a result, backtraces would become more useful and code using them more portable. Name ==== The advantage of calling this feature #backtrace is that it's consistent with the usage of the term by Thread and Exception. This, however, could also be construed as a disadvantage because although identically named the output would be materially different. I'm not sure of the best approach in this regard. API === A Kernel method named, for sake of argument, 'backtrace' which returns a Backtrace object. It can be treated like an Array, in the same way `caller` is, because it's an Enumerable. It also has shortcuts for accessing the most recent entry on the stack. Each line in the backtrace is represented by a Backtrace::Line object which has #file, #line, and #name accessors which correspond to the filename, the line number, and the method name, respectively. For example: backtrace.name # The name of the method which invoked the current one as a Symbol backtrace.file(2) # The absolute filename of the 3rd entry in the backtrace backtrace.each do |line| # Yields Line objects puts line.method end backtrace.lines.select {|l| l.method == :foo} # #lines returns an Array of Line objects Simple stuff. Weaknesses ========== Ideally, #name (not called #method because of the clash with Object#method) would return a Method object. One of the many advantages of this would be that we could combine backtraces with Method#parameters to display the signatures of each method. Unfortunately, I can't see a non-hackish way to create Method objects from the output of `caller`, because I don't know which object the method is bound to. but if this were possible it would be useful. I'm currently throwing away some of the output of `caller` because I don't completely understand it. We'll need to decide whether this would be useful to expose via the API, and if so how. I'd prefer to return a File object for #file, but the majority of Ruby APIs return pathnames instead, so I've went with convention. So is there any interest in this type of thing? Is it worth exploring further? =end -- http://bugs.ruby-lang.org/