我可以在没有 &block 的情况下访问 ruby 块的源代码吗?
Can I access the source of a ruby block without &block?
我在 Ruby 2.5 下使用 Pry 调试基础 class (Net::HTTP
)
中的问题
我收到由 HTTP 404 响应引起的异常,我想检查发出的请求的正文。为此,我想检查传递给 start
的块,但是 start
方法没有参数,它是使用 yield
:
调用的
Frame type: method
From: /usr/share/ruby/net/http.rb @ line 910 Net::HTTP#start:
905: def start # :yield: http
906: raise IOError, 'HTTP session already opened' if @started
907: if block_given?
908: begin
909: do_start
=> 910: return yield(self)
使用 Pry 是否有任何方法可以查看块的来源,如果该块未在 &block
参数中传递?
看到 Printing the source code of a Ruby block 但它对我没有帮助,因为我没有方法参数可以在这里使用。
TL;DR 你可以尝试利用 Kernel#caller.
让我们考虑一个名为 foo.rb
:
的文件
(本例使用byebug
,但与binging.pry
的流程几乎相同)
1: require 'byebug'
2:
3: def bar
4: byebug
5:
6: yield
7: end
8:
9: bar { 'some string' }
当我们用ruby foo.rb
运行这个文件时,我们会在byebug
语句处停止。
[1, 9] in foo.rb
1: require 'byebug'
2:
3: def bar
4: byebug
5:
=> 6: yield
7: end
8:
9: bar { 'some string' }
然后我们可以执行caller
,然后会打印类似下面的内容:
(故意减少和格式化输出)
(byebug) caller
[
"~/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/byebug-11.0.1/lib/byebug/processors/command_processor.rb:97:in `process_commands'",
"~/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/byebug-11.0.1/lib/byebug/processors/command_processor.rb:55:in `at_line'",
"~/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/byebug-11.0.1/lib/byebug/context.rb:98:in `at_line'",
"foo.rb:6:in `bar'",
"foo.rb:9:in `<main>'"
]
如您所见,caller
returns 当前执行堆栈作为一个数组,包含 `method' 中 file:line
形式的字符串。
此数组中的最后一个字符串指定调用 bar
的位置。
了解此信息后,您可以使用该 bar
调用打开文件并跟踪哪个块被传递到其中。
(foo.rb:9
在这种特殊情况下)
希望对您有所帮助。
作为奖励,Tenderlove - I am a puts debugger 有一篇很棒的文章,您可以在其中找到每个 Ruby 调试问题的解决方案。
所以,这里真正的问题是我没有阅读所有 Pry 帮助(特别是 rescue-pry)并且不知道 up
命令...
Usage: up [OPTIONS]
Go up to the caller's context. Accepts optional numeric parameter for how many frames to move up.
Also accepts a string (regex) instead of numeric; for jumping to nearest parent method frame which matches the regex.
e.g: up #=> Move up 1 stack frame.
e.g: up 3 #=> Move up 2 stack frames.
e.g: up meth #=> Jump to nearest parent stack frame whose method matches /meth/ regex, i.e `my_method`.
-h, --help Show this message.
通过在引发异常的 pry
会话中执行 up
,我能够到达引发异常的块并检查我需要的局部变量。
Using Pry is there any way to view the source of a block, if that block is not passed in a &block parameter?
您的问题是双重的:您必须 1) 获取隐式块和 2) 打印其源代码。
对于 1),您只需在方法的上下文中调用 Proc.new
即可将其块参数作为 proc。
所以代替:
def foo(&block)
# ...
end
您还可以通过以下方式检索区块:
def foo
block = Proc.new
# ...
end
对于 2) 你可以使用 sourcify gem:
require 'sourcify'
prc = Proc.new { |i| i * 2 }
prc.to_source
#=> "proc { |i| (i * 2) }"
应用于您的问题:
# foo.rb
require 'pry'
require 'sourcify'
def foo
binding.pry
end
foo { |i| i * 2 }
$ ruby foo.rb
From: foo.rb @ line 6 Object#foo:
4: def foo
=> 5: binding.pry
6: end
[1] pry(main)> block = Proc.new
#=> #<Proc:0x00007f9373b1c368@foo.rb:9>
[2] pry(main)> block.call(123)
#=> 246
[3] pry(main)> block.to_source
#=> "proc { |i| (i * 2) }"
我在 Ruby 2.5 下使用 Pry 调试基础 class (Net::HTTP
)
我收到由 HTTP 404 响应引起的异常,我想检查发出的请求的正文。为此,我想检查传递给 start
的块,但是 start
方法没有参数,它是使用 yield
:
Frame type: method
From: /usr/share/ruby/net/http.rb @ line 910 Net::HTTP#start:
905: def start # :yield: http
906: raise IOError, 'HTTP session already opened' if @started
907: if block_given?
908: begin
909: do_start
=> 910: return yield(self)
使用 Pry 是否有任何方法可以查看块的来源,如果该块未在 &block
参数中传递?
看到 Printing the source code of a Ruby block 但它对我没有帮助,因为我没有方法参数可以在这里使用。
TL;DR 你可以尝试利用 Kernel#caller.
让我们考虑一个名为 foo.rb
:
(本例使用byebug
,但与binging.pry
的流程几乎相同)
1: require 'byebug'
2:
3: def bar
4: byebug
5:
6: yield
7: end
8:
9: bar { 'some string' }
当我们用ruby foo.rb
运行这个文件时,我们会在byebug
语句处停止。
[1, 9] in foo.rb
1: require 'byebug'
2:
3: def bar
4: byebug
5:
=> 6: yield
7: end
8:
9: bar { 'some string' }
然后我们可以执行caller
,然后会打印类似下面的内容:
(故意减少和格式化输出)
(byebug) caller
[
"~/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/byebug-11.0.1/lib/byebug/processors/command_processor.rb:97:in `process_commands'",
"~/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/byebug-11.0.1/lib/byebug/processors/command_processor.rb:55:in `at_line'",
"~/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/byebug-11.0.1/lib/byebug/context.rb:98:in `at_line'",
"foo.rb:6:in `bar'",
"foo.rb:9:in `<main>'"
]
如您所见,caller
returns 当前执行堆栈作为一个数组,包含 `method' 中 file:line
形式的字符串。
此数组中的最后一个字符串指定调用 bar
的位置。
了解此信息后,您可以使用该 bar
调用打开文件并跟踪哪个块被传递到其中。
(foo.rb:9
在这种特殊情况下)
希望对您有所帮助。
作为奖励,Tenderlove - I am a puts debugger 有一篇很棒的文章,您可以在其中找到每个 Ruby 调试问题的解决方案。
所以,这里真正的问题是我没有阅读所有 Pry 帮助(特别是 rescue-pry)并且不知道 up
命令...
Usage: up [OPTIONS]
Go up to the caller's context. Accepts optional numeric parameter for how many frames to move up.
Also accepts a string (regex) instead of numeric; for jumping to nearest parent method frame which matches the regex.
e.g: up #=> Move up 1 stack frame.
e.g: up 3 #=> Move up 2 stack frames.
e.g: up meth #=> Jump to nearest parent stack frame whose method matches /meth/ regex, i.e `my_method`.
-h, --help Show this message.
通过在引发异常的 pry
会话中执行 up
,我能够到达引发异常的块并检查我需要的局部变量。
Using Pry is there any way to view the source of a block, if that block is not passed in a &block parameter?
您的问题是双重的:您必须 1) 获取隐式块和 2) 打印其源代码。
对于 1),您只需在方法的上下文中调用 Proc.new
即可将其块参数作为 proc。
所以代替:
def foo(&block)
# ...
end
您还可以通过以下方式检索区块:
def foo
block = Proc.new
# ...
end
对于 2) 你可以使用 sourcify gem:
require 'sourcify'
prc = Proc.new { |i| i * 2 }
prc.to_source
#=> "proc { |i| (i * 2) }"
应用于您的问题:
# foo.rb
require 'pry'
require 'sourcify'
def foo
binding.pry
end
foo { |i| i * 2 }
$ ruby foo.rb
From: foo.rb @ line 6 Object#foo:
4: def foo
=> 5: binding.pry
6: end
[1] pry(main)> block = Proc.new
#=> #<Proc:0x00007f9373b1c368@foo.rb:9>
[2] pry(main)> block.call(123)
#=> 246
[3] pry(main)> block.to_source
#=> "proc { |i| (i * 2) }"