For Ruby 2.0+, you can use Kernel#caller_locations
to get the current stack trace of the program.
From the docs for Kernel#caller_locations
:
caller_locations(start=1, length=nil) → array or nil
source caller_locations(range) → array or nil
Returns the current execution stack—an array containing backtrace
location objects.
See Thread::Backtrace::Location
for more information.
So as we can see from the documentation, this method returns an array of Thread::Backtrace::Location
objects, which you can use to determine whether or not to call binding.pry
. Thread::Backtrace::Location
provides a method called base_label
, which returns the name of the method in the current position in the stack. You can use this to check whether the current stack trace runs through a method with a specific name.
Usage example:
def a
caller_locations(0)
end
def b
a
end
def c
b
end
c.map(&:base_label)
#=> ["a", "b", "c", "<main>"]
So in your case, you'd use it like this:
binding.pry if caller_locations.map(&:base_label).include? function_name
If you're using an older version of Ruby (< 2.0), Kernel#caller_locations
isn't available, and you'll have to use Kernel#caller
instead:
caller(start=1, length=nil) → array or nil
caller(range) → array or nil
Returns the current execution stack—an array containing strings in the
form file:line or file:line: in `method'.
The optional start parameter determines the number of initial stack
entries to omit from the top of the stack.
A second optional length parameter can be used to limit how many
entries are returned from the stack.
Returns nil if start is greater than the size of current execution
stack.
Optionally you can pass a range, which will return an array containing
the entries within the specified range.
def a(skip)
caller(skip)
end
def b(skip)
a(skip)
end
def c(skip)
b(skip)
end
c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
c(3) #=> ["prog:13:in `<main>'"]
c(4) #=> []
c(5) #=> nil
You'll notice that the only difference between Kernel#caller_locations
and Kernel#caller
is that Kernel#caller
returns an array of strings, not an array of Thread::Backtrace::Location
objects. This means that you'll have to use something like regular expressions to match the method name, instead of just using Array#include?
as we did with Kernel#caller_locations
. In your case:
binding.pry if caller.any?{|stack_entry| stack_entry =~ /in `#{function_name}'$/}
For more information on getting stack traces in Ruby, see how to get a stack trace object in Ruby?