根据堆栈跟踪的内容触发 Pry 绑定

Triggering Pry binding based on contents of stacktrace

我想在一个函数中启动一个 Pry 会话,但是由于我现在正在处理的项目中的一些元编程,Pry 在很多我不感兴趣的上下文中被触发。如何我可以根据程序当前执行的堆栈跟踪触发撬吗?

有点像,

binding.pry if stacktrace.include? "function_name"

尝试

binding.pry if caller.any?{|fn_name| fn_name.include?('function_name')}

参考:How to get a stack trace object in Ruby?

对于Ruby 2.0+,您可以使用Kernel#caller_locations获取程序的当前堆栈跟踪。

来自 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.

所以我们从文档中可以看出,这个方法returns一个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的数组,其中returns方法名在栈中的当前位置。您可以使用它来检查当前堆栈跟踪是否通过具有特定名称的方法运行。

用法示例:

def a
  caller_locations(0)
end
def b
  a
end
def c
  b
end

c.map(&:base_label)
#=> ["a", "b", "c", "<main>"]

所以在你的情况下,你会像这样使用它:

binding.pry if caller_locations.map(&:base_label).include? function_name

如果您使用的是旧版本的 Ruby (< 2.0),Kernel#caller_locations 不可用,您必须使用 Kernel#caller 改为:

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

你会注意到 Kernel#caller_locationsKernel#caller 之间的唯一区别是 Kernel#caller returns 是一个字符串数组,而不是 Thread::Backtrace::Location 对象。这意味着您必须使用正则表达式之类的东西来匹配方法名称,而不是像我们使用 Kernel#caller_locations 那样只使用 Array#include?。在你的情况下:

binding.pry if caller.any?{|stack_entry| stack_entry =~ /in `#{function_name}'$/}

有关在 Ruby 中获取堆栈跟踪的详细信息,请参阅 how to get a stack trace object in Ruby?