binding.pry 和 Pry.start 有什么区别?
What's the difference between binding.pry and Pry.start?
require 'pry'
var = "variable"
class Gnar
def self.gar
@var = "lar!"
# binding.pry
# Pry.start(binding)
# Pry.start
end
end
Gnar.gar
当我取消注释 binding.pry
时,我发现自己处于 self == Gnar
的 Pry REPL 中。当我取消注释 Pry.start(binding)
时,Pry REPL 永远不会启动。当我取消注释 Pry.start
时,我发现自己处于 self == main
.
的 Pry REPL 中
我不明白这种行为,我想真正掌握这个必不可少的 Ruby 调试工具的本质。我想关注 binding.pry
和 Pry.start(binding)
.
的行为
在一种情况下,我们在 binding
对象上调用 #pry
方法,在另一种情况下,我们在 Pry
class 以 binding
作为参数。
让我们从binding.pry
开始。根据the docs,#pry
定义如下:
def pry(object=nil, hash={})
if object.nil? || Hash === object
Pry.start(self, object || {})
else
Pry.start(object, hash)
end
end
根据该方法定义,当我们在不带参数的对象上调用 #pry
时,我们调用 Pry.start(self, {})
,其中 self
是 self
在 binding
上下文。
那么 Pry.start
发生了什么? The definition in the docs 很长,但我注意到 self
作为 Pry.start
的 target
传入,然后在这一行中使用:
options[:target] = Pry.binding_for(target || toplevel_binding) #line 152
之前
# Enter the matrix
driver.start(options) #line 169
考虑到所有这些,我的理解是 binding.pry
导致通过 driver.start(options)
和 options[:target] = Pry.binding_for(binding)
开始的 REPL。 如果 target == binding
在这两种情况下,为什么 Pry.start(binding)
没有表现出相同的行为(即不启动 REPL)?我做了什么不正确的假设? 我有点理解 Pry.start
启动一个 REPL,默认 self == main
target == toplevel_binding
。
从控制台中调用 Pry.start(binding)
应该与调用 binding.pry
:
具有相似的效果
rails c
Loading development environment (Rails 5.1.6.2)
[1] pry(main)> class Gnar
[1] pry(main)* def self.gar
[1] pry(main)* @var = "lar!"
[1] pry(main)* Pry.start(binding)
[1] pry(main)* end
[1] pry(main)* end
=> :gar
[2] pry(main)> Gnar.gar
From: /Users/redacted/.gem/gems/pry-0.12.2/lib/pry/pry_instance.rb @ line 388 Pry#evaluate_ruby:
383: def evaluate_ruby(code)
384: inject_sticky_locals!
385: exec_hook :before_eval, code, self
386:
387: result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
=> 388: set_last_result(result, code)
389: ensure
390: update_input_history(code)
391: exec_hook :after_eval, result, self
392: end
[1] pry(#<Pry>)>
Binding 对象将代码的执行上下文封装在特定位置。 Binding#pry
在绑定对象上启动 Pry REPL。
Pry.start
刚刚启动一个 Pry REPL。如果你不给它传递一个绑定,那么它只是一个没有任何执行上下文的 Pry REPL;如果传递给它的绑定的执行上下文是 Pry 实例,控制台会通过从 pry(main)
(无上下文)更改为 pry(#<Pry>)>
来告诉您它是否具有上下文:
$ rails c
Loading development environment (Rails 5.1.6.2)
[1] pry(main)> Pry.start(binding)
From: /Users/redacted/.gem/gems/pry-0.12.2/lib/pry/pry_instance.rb @ line 388 Pry#evaluate_ruby:
383: def evaluate_ruby(code)
384: inject_sticky_locals!
385: exec_hook :before_eval, code, self
386:
387: result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
=> 388: set_last_result(result, code)
389: ensure
390: update_input_history(code)
391: exec_hook :after_eval, result, self
392: end
[1] pry(#<Pry>)> exit
=> nil
[2] pry(main)> binding.pry
From: /Users/redacted/.gem/gems/pry-0.12.2/lib/pry/pry_instance.rb @ line 388 Pry#evaluate_ruby:
383: def evaluate_ruby(code)
384: inject_sticky_locals!
385: exec_hook :before_eval, code, self
386:
387: result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
=> 388: set_last_result(result, code)
389: ensure
390: update_input_history(code)
391: exec_hook :after_eval, result, self
392: end
[1] pry(#<Pry>)> exit
=> nil
[3] pry(main)> exit
类似地,从 class 方法中调用 binding.pry 会在 class (pry(ClassName)
) 的执行上下文中打开一个 Pry REPL。从 实例方法 中调用 binding.pry 会在该 实例 (pry(#<ClassName>
) 的执行上下文中打开一个 Pry REPL .
rails c
Loading development environment (Rails 5.1.6.2)
[1] pry(main)> class A
[1] pry(main)* def self.b
[1] pry(main)* binding.pry
[1] pry(main)* end
[1] pry(main)*
[1] pry(main)* def c
[1] pry(main)* binding.pry
[1] pry(main)* end
[1] pry(main)* end
=> :c
[2] pry(main)> A.b
From: (pry) @ line 4 A.b:
2: def self.b
3: binding.pry
=> 4: end
[1] pry(A)> exit
=> nil
[3] pry(main)> A.new.c
From: (pry) @ line 8 A#c:
6: def c
7: binding.pry
=> 8: end
[1] pry(#<A>)> exit
=> nil
希望对您有所帮助。
require 'pry'
var = "variable"
class Gnar
def self.gar
@var = "lar!"
# binding.pry
# Pry.start(binding)
# Pry.start
end
end
Gnar.gar
当我取消注释 binding.pry
时,我发现自己处于 self == Gnar
的 Pry REPL 中。当我取消注释 Pry.start(binding)
时,Pry REPL 永远不会启动。当我取消注释 Pry.start
时,我发现自己处于 self == main
.
我不明白这种行为,我想真正掌握这个必不可少的 Ruby 调试工具的本质。我想关注 binding.pry
和 Pry.start(binding)
.
在一种情况下,我们在 binding
对象上调用 #pry
方法,在另一种情况下,我们在 Pry
class 以 binding
作为参数。
让我们从binding.pry
开始。根据the docs,#pry
定义如下:
def pry(object=nil, hash={})
if object.nil? || Hash === object
Pry.start(self, object || {})
else
Pry.start(object, hash)
end
end
根据该方法定义,当我们在不带参数的对象上调用 #pry
时,我们调用 Pry.start(self, {})
,其中 self
是 self
在 binding
上下文。
那么 Pry.start
发生了什么? The definition in the docs 很长,但我注意到 self
作为 Pry.start
的 target
传入,然后在这一行中使用:
options[:target] = Pry.binding_for(target || toplevel_binding) #line 152
之前
# Enter the matrix
driver.start(options) #line 169
考虑到所有这些,我的理解是 binding.pry
导致通过 driver.start(options)
和 options[:target] = Pry.binding_for(binding)
开始的 REPL。 如果 target == binding
在这两种情况下,为什么 Pry.start(binding)
没有表现出相同的行为(即不启动 REPL)?我做了什么不正确的假设? 我有点理解 Pry.start
启动一个 REPL,默认 self == main
target == toplevel_binding
。
从控制台中调用 Pry.start(binding)
应该与调用 binding.pry
:
rails c
Loading development environment (Rails 5.1.6.2)
[1] pry(main)> class Gnar
[1] pry(main)* def self.gar
[1] pry(main)* @var = "lar!"
[1] pry(main)* Pry.start(binding)
[1] pry(main)* end
[1] pry(main)* end
=> :gar
[2] pry(main)> Gnar.gar
From: /Users/redacted/.gem/gems/pry-0.12.2/lib/pry/pry_instance.rb @ line 388 Pry#evaluate_ruby:
383: def evaluate_ruby(code)
384: inject_sticky_locals!
385: exec_hook :before_eval, code, self
386:
387: result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
=> 388: set_last_result(result, code)
389: ensure
390: update_input_history(code)
391: exec_hook :after_eval, result, self
392: end
[1] pry(#<Pry>)>
Binding 对象将代码的执行上下文封装在特定位置。 Binding#pry
在绑定对象上启动 Pry REPL。
Pry.start
刚刚启动一个 Pry REPL。如果你不给它传递一个绑定,那么它只是一个没有任何执行上下文的 Pry REPL;如果传递给它的绑定的执行上下文是 Pry 实例,控制台会通过从 pry(main)
(无上下文)更改为 pry(#<Pry>)>
来告诉您它是否具有上下文:
$ rails c
Loading development environment (Rails 5.1.6.2)
[1] pry(main)> Pry.start(binding)
From: /Users/redacted/.gem/gems/pry-0.12.2/lib/pry/pry_instance.rb @ line 388 Pry#evaluate_ruby:
383: def evaluate_ruby(code)
384: inject_sticky_locals!
385: exec_hook :before_eval, code, self
386:
387: result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
=> 388: set_last_result(result, code)
389: ensure
390: update_input_history(code)
391: exec_hook :after_eval, result, self
392: end
[1] pry(#<Pry>)> exit
=> nil
[2] pry(main)> binding.pry
From: /Users/redacted/.gem/gems/pry-0.12.2/lib/pry/pry_instance.rb @ line 388 Pry#evaluate_ruby:
383: def evaluate_ruby(code)
384: inject_sticky_locals!
385: exec_hook :before_eval, code, self
386:
387: result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
=> 388: set_last_result(result, code)
389: ensure
390: update_input_history(code)
391: exec_hook :after_eval, result, self
392: end
[1] pry(#<Pry>)> exit
=> nil
[3] pry(main)> exit
类似地,从 class 方法中调用 binding.pry 会在 class (pry(ClassName)
) 的执行上下文中打开一个 Pry REPL。从 实例方法 中调用 binding.pry 会在该 实例 (pry(#<ClassName>
) 的执行上下文中打开一个 Pry REPL .
rails c
Loading development environment (Rails 5.1.6.2)
[1] pry(main)> class A
[1] pry(main)* def self.b
[1] pry(main)* binding.pry
[1] pry(main)* end
[1] pry(main)*
[1] pry(main)* def c
[1] pry(main)* binding.pry
[1] pry(main)* end
[1] pry(main)* end
=> :c
[2] pry(main)> A.b
From: (pry) @ line 4 A.b:
2: def self.b
3: binding.pry
=> 4: end
[1] pry(A)> exit
=> nil
[3] pry(main)> A.new.c
From: (pry) @ line 8 A#c:
6: def c
7: binding.pry
=> 8: end
[1] pry(#<A>)> exit
=> nil
希望对您有所帮助。